1 //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
15 #include "InterpBlock.h"
19 using namespace clang
;
20 using namespace clang::interp
;
22 Pointer::Pointer(Block
*Pointee
) : Pointer(Pointee
, 0, 0) {}
24 Pointer::Pointer(Block
*Pointee
, unsigned BaseAndOffset
)
25 : Pointer(Pointee
, BaseAndOffset
, BaseAndOffset
) {}
27 Pointer::Pointer(const Pointer
&P
) : Pointer(P
.Pointee
, P
.Base
, P
.Offset
) {}
29 Pointer::Pointer(Pointer
&&P
)
30 : Pointee(P
.Pointee
), Base(P
.Base
), Offset(P
.Offset
) {
32 Pointee
->replacePointer(&P
, this);
35 Pointer::Pointer(Block
*Pointee
, unsigned Base
, unsigned Offset
)
36 : Pointee(Pointee
), Base(Base
), Offset(Offset
) {
37 assert((Base
== RootPtrMark
|| Base
% alignof(void *) == 0) && "wrong base");
39 Pointee
->addPointer(this);
44 Pointee
->removePointer(this);
49 void Pointer::operator=(const Pointer
&P
) {
53 Pointee
->removePointer(this);
60 Pointee
->addPointer(this);
66 void Pointer::operator=(Pointer
&&P
) {
70 Pointee
->removePointer(this);
77 Pointee
->replacePointer(&P
, this);
83 APValue
Pointer::toAPValue() const {
84 APValue::LValueBase Base
;
85 llvm::SmallVector
<APValue::LValuePathEntry
, 5> Path
;
91 Base
= static_cast<const Expr
*>(nullptr);
94 Offset
= CharUnits::Zero();
96 // Build the lvalue base from the block.
97 const Descriptor
*Desc
= getDeclDesc();
98 if (auto *VD
= Desc
->asValueDecl())
100 else if (auto *E
= Desc
->asExpr())
103 llvm_unreachable("Invalid allocation type");
105 // Not a null pointer.
108 if (isUnknownSizeArray()) {
109 IsOnePastEnd
= false;
110 Offset
= CharUnits::Zero();
111 } else if (Desc
->asExpr()) {
112 // Pointer pointing to a an expression.
113 IsOnePastEnd
= false;
114 Offset
= CharUnits::Zero();
116 // TODO: compute the offset into the object.
117 Offset
= CharUnits::Zero();
119 // Build the path into the object.
121 while (Ptr
.isField() || Ptr
.isArrayElement()) {
122 if (Ptr
.isArrayElement()) {
123 Path
.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr
.getIndex()));
124 Ptr
= Ptr
.getArray();
126 // TODO: figure out if base is virtual
127 bool IsVirtual
= false;
129 // Create a path entry for the field.
130 const Descriptor
*Desc
= Ptr
.getFieldDesc();
131 if (const auto *BaseOrMember
= Desc
->asDecl()) {
132 Path
.push_back(APValue::LValuePathEntry({BaseOrMember
, IsVirtual
}));
136 llvm_unreachable("Invalid field type");
140 IsOnePastEnd
= isOnePastEnd();
144 // We assemble the LValuePath starting from the innermost pointer to the
145 // outermost one. SO in a.b.c, the first element in Path will refer to
146 // the field 'c', while later code expects it to refer to 'a'.
147 // Just invert the order of the elements.
148 std::reverse(Path
.begin(), Path
.end());
150 return APValue(Base
, Offset
, Path
, IsOnePastEnd
, IsNullPtr
);
153 std::string
Pointer::toDiagnosticString(const ASTContext
&Ctx
) const {
157 return toAPValue().getAsString(Ctx
, getType());
160 bool Pointer::isInitialized() const {
161 assert(Pointee
&& "Cannot check if null pointer was initialized");
162 const Descriptor
*Desc
= getFieldDesc();
164 if (Desc
->isPrimitiveArray()) {
165 if (isStatic() && Base
== 0)
168 InitMapPtr
&IM
= getInitMap();
176 return IM
->second
->isElementInitialized(getIndex());
179 // Field has its bit in an inline descriptor.
180 return Base
== 0 || getInlineDesc()->IsInitialized
;
183 void Pointer::initialize() const {
184 assert(Pointee
&& "Cannot initialize null pointer");
185 const Descriptor
*Desc
= getFieldDesc();
188 if (Desc
->isPrimitiveArray()) {
189 // Primitive global arrays don't have an initmap.
190 if (isStatic() && Base
== 0)
193 InitMapPtr
&IM
= getInitMap();
196 std::make_pair(false, std::make_shared
<InitMap
>(Desc
->getNumElems()));
204 if (IM
->second
->initializeElement(getIndex())) {
211 // Field has its bit in an inline descriptor.
212 assert(Base
!= 0 && "Only composite fields can be initialised");
213 getInlineDesc()->IsInitialized
= true;
216 void Pointer::activate() const {
217 // Field has its bit in an inline descriptor.
218 assert(Base
!= 0 && "Only composite fields can be initialised");
219 getInlineDesc()->IsActive
= true;
222 void Pointer::deactivate() const {
223 // TODO: this only appears in constructors, so nothing to deactivate.
226 bool Pointer::hasSameBase(const Pointer
&A
, const Pointer
&B
) {
227 return A
.Pointee
== B
.Pointee
;
230 bool Pointer::hasSameArray(const Pointer
&A
, const Pointer
&B
) {
231 return hasSameBase(A
, B
) && A
.Base
== B
.Base
&& A
.getFieldDesc()->IsArray
;
234 APValue
Pointer::toRValue(const Context
&Ctx
) const {
236 if (getFieldDesc()->isPrimitive()) {
237 PrimType PT
= *Ctx
.classify(getType());
238 TYPE_SWITCH(PT
, return deref
<T
>().toAPValue());
239 llvm_unreachable("Unhandled PrimType?");
244 if (getFieldDesc()->isRecord()) {
245 const Record
*R
= getRecord();
247 APValue(APValue::UninitStruct(), R
->getNumBases(), R
->getNumFields());
249 for (unsigned I
= 0; I
!= R
->getNumFields(); ++I
) {
250 const Pointer
&FieldPtr
= this->atField(R
->getField(I
)->Offset
);
251 Result
.getStructField(I
) = FieldPtr
.toRValue(Ctx
);
254 for (unsigned I
= 0; I
!= R
->getNumBases(); ++I
) {
255 const Pointer
&BasePtr
= this->atField(R
->getBase(I
)->Offset
);
256 Result
.getStructBase(I
) = BasePtr
.toRValue(Ctx
);