xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Pointer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1a7dea167SDimitry Andric //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric 
9a7dea167SDimitry Andric #include "Pointer.h"
105f757f3fSDimitry Andric #include "Boolean.h"
115f757f3fSDimitry Andric #include "Context.h"
125f757f3fSDimitry Andric #include "Floating.h"
13a7dea167SDimitry Andric #include "Function.h"
145f757f3fSDimitry Andric #include "Integral.h"
155ffd83dbSDimitry Andric #include "InterpBlock.h"
16*0fca6ea1SDimitry Andric #include "MemberPointer.h"
17a7dea167SDimitry Andric #include "PrimType.h"
185f757f3fSDimitry Andric #include "Record.h"
19*0fca6ea1SDimitry Andric #include "clang/AST/RecordLayout.h"
20a7dea167SDimitry Andric 
21a7dea167SDimitry Andric using namespace clang;
22a7dea167SDimitry Andric using namespace clang::interp;
23a7dea167SDimitry Andric 
24*0fca6ea1SDimitry Andric Pointer::Pointer(Block *Pointee)
25*0fca6ea1SDimitry Andric     : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
26*0fca6ea1SDimitry Andric               Pointee->getDescriptor()->getMetadataSize()) {}
27a7dea167SDimitry Andric 
28*0fca6ea1SDimitry Andric Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
29bdd1243dSDimitry Andric     : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
30bdd1243dSDimitry Andric 
31*0fca6ea1SDimitry Andric Pointer::Pointer(const Pointer &P)
32*0fca6ea1SDimitry Andric     : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
33*0fca6ea1SDimitry Andric       StorageKind(P.StorageKind) {
34a7dea167SDimitry Andric 
35*0fca6ea1SDimitry Andric   if (isBlockPointer() && PointeeStorage.BS.Pointee)
36*0fca6ea1SDimitry Andric     PointeeStorage.BS.Pointee->addPointer(this);
37a7dea167SDimitry Andric }
38a7dea167SDimitry Andric 
39*0fca6ea1SDimitry Andric Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
40*0fca6ea1SDimitry Andric     : Offset(Offset), StorageKind(Storage::Block) {
41a7dea167SDimitry Andric   assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
42*0fca6ea1SDimitry Andric 
43*0fca6ea1SDimitry Andric   PointeeStorage.BS = {Pointee, Base};
44*0fca6ea1SDimitry Andric 
45a7dea167SDimitry Andric   if (Pointee)
46a7dea167SDimitry Andric     Pointee->addPointer(this);
47a7dea167SDimitry Andric }
48a7dea167SDimitry Andric 
49*0fca6ea1SDimitry Andric Pointer::Pointer(Pointer &&P)
50*0fca6ea1SDimitry Andric     : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
51*0fca6ea1SDimitry Andric       StorageKind(P.StorageKind) {
52*0fca6ea1SDimitry Andric 
53*0fca6ea1SDimitry Andric   if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
54*0fca6ea1SDimitry Andric     PointeeStorage.BS.Pointee->replacePointer(&P, this);
55*0fca6ea1SDimitry Andric }
56*0fca6ea1SDimitry Andric 
57a7dea167SDimitry Andric Pointer::~Pointer() {
58*0fca6ea1SDimitry Andric   if (isIntegralPointer())
59*0fca6ea1SDimitry Andric     return;
60*0fca6ea1SDimitry Andric 
61*0fca6ea1SDimitry Andric   if (Block *Pointee = PointeeStorage.BS.Pointee) {
62a7dea167SDimitry Andric     Pointee->removePointer(this);
63a7dea167SDimitry Andric     Pointee->cleanup();
64a7dea167SDimitry Andric   }
65a7dea167SDimitry Andric }
66a7dea167SDimitry Andric 
67a7dea167SDimitry Andric void Pointer::operator=(const Pointer &P) {
68*0fca6ea1SDimitry Andric   // If the current storage type is Block, we need to remove
69*0fca6ea1SDimitry Andric   // this pointer from the block.
70*0fca6ea1SDimitry Andric   bool WasBlockPointer = isBlockPointer();
71*0fca6ea1SDimitry Andric   if (StorageKind == Storage::Block) {
72*0fca6ea1SDimitry Andric     Block *Old = PointeeStorage.BS.Pointee;
73*0fca6ea1SDimitry Andric     if (WasBlockPointer && Old) {
74*0fca6ea1SDimitry Andric       PointeeStorage.BS.Pointee->removePointer(this);
75a7dea167SDimitry Andric       Old->cleanup();
76a7dea167SDimitry Andric     }
77*0fca6ea1SDimitry Andric   }
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric   StorageKind = P.StorageKind;
80*0fca6ea1SDimitry Andric   Offset = P.Offset;
81*0fca6ea1SDimitry Andric 
82*0fca6ea1SDimitry Andric   if (P.isBlockPointer()) {
83*0fca6ea1SDimitry Andric     PointeeStorage.BS = P.PointeeStorage.BS;
84*0fca6ea1SDimitry Andric     PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
85*0fca6ea1SDimitry Andric 
86*0fca6ea1SDimitry Andric     if (PointeeStorage.BS.Pointee)
87*0fca6ea1SDimitry Andric       PointeeStorage.BS.Pointee->addPointer(this);
88*0fca6ea1SDimitry Andric   } else if (P.isIntegralPointer()) {
89*0fca6ea1SDimitry Andric     PointeeStorage.Int = P.PointeeStorage.Int;
90*0fca6ea1SDimitry Andric   } else {
91*0fca6ea1SDimitry Andric     assert(false && "Unhandled storage kind");
92*0fca6ea1SDimitry Andric   }
93*0fca6ea1SDimitry Andric }
94a7dea167SDimitry Andric 
95a7dea167SDimitry Andric void Pointer::operator=(Pointer &&P) {
96*0fca6ea1SDimitry Andric   // If the current storage type is Block, we need to remove
97*0fca6ea1SDimitry Andric   // this pointer from the block.
98*0fca6ea1SDimitry Andric   bool WasBlockPointer = isBlockPointer();
99*0fca6ea1SDimitry Andric   if (StorageKind == Storage::Block) {
100*0fca6ea1SDimitry Andric     Block *Old = PointeeStorage.BS.Pointee;
101*0fca6ea1SDimitry Andric     if (WasBlockPointer && Old) {
102*0fca6ea1SDimitry Andric       PointeeStorage.BS.Pointee->removePointer(this);
103a7dea167SDimitry Andric       Old->cleanup();
104a7dea167SDimitry Andric     }
105*0fca6ea1SDimitry Andric   }
106a7dea167SDimitry Andric 
107*0fca6ea1SDimitry Andric   StorageKind = P.StorageKind;
108*0fca6ea1SDimitry Andric   Offset = P.Offset;
109a7dea167SDimitry Andric 
110*0fca6ea1SDimitry Andric   if (P.isBlockPointer()) {
111*0fca6ea1SDimitry Andric     PointeeStorage.BS = P.PointeeStorage.BS;
112*0fca6ea1SDimitry Andric     PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
113*0fca6ea1SDimitry Andric 
114*0fca6ea1SDimitry Andric     if (PointeeStorage.BS.Pointee)
115*0fca6ea1SDimitry Andric       PointeeStorage.BS.Pointee->addPointer(this);
116*0fca6ea1SDimitry Andric   } else if (P.isIntegralPointer()) {
117*0fca6ea1SDimitry Andric     PointeeStorage.Int = P.PointeeStorage.Int;
118a7dea167SDimitry Andric   } else {
119*0fca6ea1SDimitry Andric     assert(false && "Unhandled storage kind");
120*0fca6ea1SDimitry Andric   }
121*0fca6ea1SDimitry Andric }
122*0fca6ea1SDimitry Andric 
123*0fca6ea1SDimitry Andric APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
124*0fca6ea1SDimitry Andric   llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
125*0fca6ea1SDimitry Andric 
126*0fca6ea1SDimitry Andric   if (isZero())
127*0fca6ea1SDimitry Andric     return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
128*0fca6ea1SDimitry Andric                    /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
129*0fca6ea1SDimitry Andric   if (isIntegralPointer())
130*0fca6ea1SDimitry Andric     return APValue(static_cast<const Expr *>(nullptr),
131*0fca6ea1SDimitry Andric                    CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
132*0fca6ea1SDimitry Andric                    Path,
133*0fca6ea1SDimitry Andric                    /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
134*0fca6ea1SDimitry Andric 
135a7dea167SDimitry Andric   // Build the lvalue base from the block.
1365f757f3fSDimitry Andric   const Descriptor *Desc = getDeclDesc();
137*0fca6ea1SDimitry Andric   APValue::LValueBase Base;
138*0fca6ea1SDimitry Andric   if (const auto *VD = Desc->asValueDecl())
139a7dea167SDimitry Andric     Base = VD;
140*0fca6ea1SDimitry Andric   else if (const auto *E = Desc->asExpr())
141a7dea167SDimitry Andric     Base = E;
142a7dea167SDimitry Andric   else
143a7dea167SDimitry Andric     llvm_unreachable("Invalid allocation type");
144a7dea167SDimitry Andric 
145*0fca6ea1SDimitry Andric   if (isUnknownSizeArray() || Desc->asExpr())
146*0fca6ea1SDimitry Andric     return APValue(Base, CharUnits::Zero(), Path,
147*0fca6ea1SDimitry Andric                    /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
148a7dea167SDimitry Andric 
149*0fca6ea1SDimitry Andric   CharUnits Offset = CharUnits::Zero();
150*0fca6ea1SDimitry Andric 
151*0fca6ea1SDimitry Andric   auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
152*0fca6ea1SDimitry Andric     // This shouldn't happen, but if it does, don't crash inside
153*0fca6ea1SDimitry Andric     // getASTRecordLayout.
154*0fca6ea1SDimitry Andric     if (FD->getParent()->isInvalidDecl())
155*0fca6ea1SDimitry Andric       return CharUnits::Zero();
156*0fca6ea1SDimitry Andric     const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
157*0fca6ea1SDimitry Andric     unsigned FieldIndex = FD->getFieldIndex();
158*0fca6ea1SDimitry Andric     return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
159*0fca6ea1SDimitry Andric   };
160a7dea167SDimitry Andric 
161a7dea167SDimitry Andric   // Build the path into the object.
162a7dea167SDimitry Andric   Pointer Ptr = *this;
163bdd1243dSDimitry Andric   while (Ptr.isField() || Ptr.isArrayElement()) {
164*0fca6ea1SDimitry Andric     if (Ptr.isArrayRoot()) {
165*0fca6ea1SDimitry Andric       Path.push_back(APValue::LValuePathEntry(
166*0fca6ea1SDimitry Andric           {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric       if (const auto *FD = dyn_cast<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
169*0fca6ea1SDimitry Andric         Offset += getFieldOffset(FD);
170*0fca6ea1SDimitry Andric 
171*0fca6ea1SDimitry Andric       Ptr = Ptr.getBase();
172*0fca6ea1SDimitry Andric     } else if (Ptr.isArrayElement()) {
173*0fca6ea1SDimitry Andric       unsigned Index;
174*0fca6ea1SDimitry Andric       if (Ptr.isOnePastEnd())
175*0fca6ea1SDimitry Andric         Index = Ptr.getArray().getNumElems();
176*0fca6ea1SDimitry Andric       else
177*0fca6ea1SDimitry Andric         Index = Ptr.getIndex();
178*0fca6ea1SDimitry Andric 
179*0fca6ea1SDimitry Andric       Offset += (Index * ASTCtx.getTypeSizeInChars(Ptr.getType()));
180*0fca6ea1SDimitry Andric       Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
181a7dea167SDimitry Andric       Ptr = Ptr.getArray();
182a7dea167SDimitry Andric     } else {
183a7dea167SDimitry Andric       bool IsVirtual = false;
184a7dea167SDimitry Andric 
185a7dea167SDimitry Andric       // Create a path entry for the field.
1865f757f3fSDimitry Andric       const Descriptor *Desc = Ptr.getFieldDesc();
1875f757f3fSDimitry Andric       if (const auto *BaseOrMember = Desc->asDecl()) {
188*0fca6ea1SDimitry Andric         if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
189a7dea167SDimitry Andric           Ptr = Ptr.getBase();
190*0fca6ea1SDimitry Andric           Offset += getFieldOffset(FD);
191*0fca6ea1SDimitry Andric         } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
192*0fca6ea1SDimitry Andric           IsVirtual = Ptr.isVirtualBaseClass();
193*0fca6ea1SDimitry Andric           Ptr = Ptr.getBase();
194*0fca6ea1SDimitry Andric           const Record *BaseRecord = Ptr.getRecord();
195*0fca6ea1SDimitry Andric 
196*0fca6ea1SDimitry Andric           const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
197*0fca6ea1SDimitry Andric               cast<CXXRecordDecl>(BaseRecord->getDecl()));
198*0fca6ea1SDimitry Andric           if (IsVirtual)
199*0fca6ea1SDimitry Andric             Offset += Layout.getVBaseClassOffset(RD);
200*0fca6ea1SDimitry Andric           else
201*0fca6ea1SDimitry Andric             Offset += Layout.getBaseClassOffset(RD);
202*0fca6ea1SDimitry Andric 
203*0fca6ea1SDimitry Andric         } else {
204*0fca6ea1SDimitry Andric           Ptr = Ptr.getBase();
205*0fca6ea1SDimitry Andric         }
206*0fca6ea1SDimitry Andric         Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
207a7dea167SDimitry Andric         continue;
208a7dea167SDimitry Andric       }
209a7dea167SDimitry Andric       llvm_unreachable("Invalid field type");
210a7dea167SDimitry Andric     }
211a7dea167SDimitry Andric   }
212a7dea167SDimitry Andric 
213*0fca6ea1SDimitry Andric   // FIXME(perf): We compute the lvalue path above, but we can't supply it
214*0fca6ea1SDimitry Andric   // for dummy pointers (that causes crashes later in CheckConstantExpression).
215*0fca6ea1SDimitry Andric   if (isDummy())
216*0fca6ea1SDimitry Andric     Path.clear();
217a7dea167SDimitry Andric 
218bdd1243dSDimitry Andric   // We assemble the LValuePath starting from the innermost pointer to the
219bdd1243dSDimitry Andric   // outermost one. SO in a.b.c, the first element in Path will refer to
220bdd1243dSDimitry Andric   // the field 'c', while later code expects it to refer to 'a'.
221bdd1243dSDimitry Andric   // Just invert the order of the elements.
222bdd1243dSDimitry Andric   std::reverse(Path.begin(), Path.end());
223bdd1243dSDimitry Andric 
224*0fca6ea1SDimitry Andric   return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
225*0fca6ea1SDimitry Andric                  /*IsNullPtr=*/false);
226*0fca6ea1SDimitry Andric }
227*0fca6ea1SDimitry Andric 
228*0fca6ea1SDimitry Andric void Pointer::print(llvm::raw_ostream &OS) const {
229*0fca6ea1SDimitry Andric   OS << PointeeStorage.BS.Pointee << " (";
230*0fca6ea1SDimitry Andric   if (isBlockPointer()) {
231*0fca6ea1SDimitry Andric     const Block *B = PointeeStorage.BS.Pointee;
232*0fca6ea1SDimitry Andric     OS << "Block) {";
233*0fca6ea1SDimitry Andric 
234*0fca6ea1SDimitry Andric     if (isRoot())
235*0fca6ea1SDimitry Andric       OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
236*0fca6ea1SDimitry Andric     else
237*0fca6ea1SDimitry Andric       OS << PointeeStorage.BS.Base << ", ";
238*0fca6ea1SDimitry Andric 
239*0fca6ea1SDimitry Andric     if (isElementPastEnd())
240*0fca6ea1SDimitry Andric       OS << "pastend, ";
241*0fca6ea1SDimitry Andric     else
242*0fca6ea1SDimitry Andric       OS << Offset << ", ";
243*0fca6ea1SDimitry Andric 
244*0fca6ea1SDimitry Andric     if (B)
245*0fca6ea1SDimitry Andric       OS << B->getSize();
246*0fca6ea1SDimitry Andric     else
247*0fca6ea1SDimitry Andric       OS << "nullptr";
248*0fca6ea1SDimitry Andric   } else {
249*0fca6ea1SDimitry Andric     OS << "Int) {";
250*0fca6ea1SDimitry Andric     OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc;
251*0fca6ea1SDimitry Andric   }
252*0fca6ea1SDimitry Andric   OS << "}";
253a7dea167SDimitry Andric }
254a7dea167SDimitry Andric 
2555f757f3fSDimitry Andric std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
256*0fca6ea1SDimitry Andric   if (isZero())
2575f757f3fSDimitry Andric     return "nullptr";
2585f757f3fSDimitry Andric 
259*0fca6ea1SDimitry Andric   if (isIntegralPointer())
260*0fca6ea1SDimitry Andric     return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
261*0fca6ea1SDimitry Andric 
262*0fca6ea1SDimitry Andric   return toAPValue(Ctx).getAsString(Ctx, getType());
2635f757f3fSDimitry Andric }
2645f757f3fSDimitry Andric 
265a7dea167SDimitry Andric bool Pointer::isInitialized() const {
266*0fca6ea1SDimitry Andric   if (isIntegralPointer())
267*0fca6ea1SDimitry Andric     return true;
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
270*0fca6ea1SDimitry Andric     const GlobalInlineDescriptor &GD =
271*0fca6ea1SDimitry Andric         *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
272*0fca6ea1SDimitry Andric     return GD.InitState == GlobalInitState::Initialized;
273*0fca6ea1SDimitry Andric   }
274*0fca6ea1SDimitry Andric 
275*0fca6ea1SDimitry Andric   assert(PointeeStorage.BS.Pointee &&
276*0fca6ea1SDimitry Andric          "Cannot check if null pointer was initialized");
27706c3fb27SDimitry Andric   const Descriptor *Desc = getFieldDesc();
278bdd1243dSDimitry Andric   assert(Desc);
279a7dea167SDimitry Andric   if (Desc->isPrimitiveArray()) {
280*0fca6ea1SDimitry Andric     if (isStatic() && PointeeStorage.BS.Base == 0)
281a7dea167SDimitry Andric       return true;
2825f757f3fSDimitry Andric 
2835f757f3fSDimitry Andric     InitMapPtr &IM = getInitMap();
2845f757f3fSDimitry Andric 
2855f757f3fSDimitry Andric     if (!IM)
286a7dea167SDimitry Andric       return false;
2875f757f3fSDimitry Andric 
2885f757f3fSDimitry Andric     if (IM->first)
289a7dea167SDimitry Andric       return true;
2905f757f3fSDimitry Andric 
2915f757f3fSDimitry Andric     return IM->second->isElementInitialized(getIndex());
29206c3fb27SDimitry Andric   }
29306c3fb27SDimitry Andric 
294*0fca6ea1SDimitry Andric   if (asBlockPointer().Base == 0)
295*0fca6ea1SDimitry Andric     return true;
296*0fca6ea1SDimitry Andric 
297a7dea167SDimitry Andric   // Field has its bit in an inline descriptor.
298*0fca6ea1SDimitry Andric   return getInlineDesc()->IsInitialized;
299a7dea167SDimitry Andric }
300a7dea167SDimitry Andric 
301a7dea167SDimitry Andric void Pointer::initialize() const {
302*0fca6ea1SDimitry Andric   if (isIntegralPointer())
303*0fca6ea1SDimitry Andric     return;
304*0fca6ea1SDimitry Andric 
305*0fca6ea1SDimitry Andric   assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
30606c3fb27SDimitry Andric   const Descriptor *Desc = getFieldDesc();
307bdd1243dSDimitry Andric 
308*0fca6ea1SDimitry Andric   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
309*0fca6ea1SDimitry Andric     GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
310*0fca6ea1SDimitry Andric         asBlockPointer().Pointee->rawData());
311*0fca6ea1SDimitry Andric     GD.InitState = GlobalInitState::Initialized;
312*0fca6ea1SDimitry Andric     return;
313*0fca6ea1SDimitry Andric   }
314*0fca6ea1SDimitry Andric 
315bdd1243dSDimitry Andric   assert(Desc);
316a7dea167SDimitry Andric   if (Desc->isPrimitiveArray()) {
317bdd1243dSDimitry Andric     // Primitive global arrays don't have an initmap.
318*0fca6ea1SDimitry Andric     if (isStatic() && PointeeStorage.BS.Base == 0)
319*0fca6ea1SDimitry Andric       return;
320*0fca6ea1SDimitry Andric 
321*0fca6ea1SDimitry Andric     // Nothing to do for these.
322*0fca6ea1SDimitry Andric     if (Desc->getNumElems() == 0)
323bdd1243dSDimitry Andric       return;
324bdd1243dSDimitry Andric 
3255f757f3fSDimitry Andric     InitMapPtr &IM = getInitMap();
3265f757f3fSDimitry Andric     if (!IM)
3275f757f3fSDimitry Andric       IM =
3285f757f3fSDimitry Andric           std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
3295f757f3fSDimitry Andric 
3305f757f3fSDimitry Andric     assert(IM);
3315f757f3fSDimitry Andric 
3325f757f3fSDimitry Andric     // All initialized.
3335f757f3fSDimitry Andric     if (IM->first)
334a7dea167SDimitry Andric       return;
3355f757f3fSDimitry Andric 
3365f757f3fSDimitry Andric     if (IM->second->initializeElement(getIndex())) {
3375f757f3fSDimitry Andric       IM->first = true;
3385f757f3fSDimitry Andric       IM->second.reset();
339a7dea167SDimitry Andric     }
34006c3fb27SDimitry Andric     return;
341a7dea167SDimitry Andric   }
34206c3fb27SDimitry Andric 
343a7dea167SDimitry Andric   // Field has its bit in an inline descriptor.
344*0fca6ea1SDimitry Andric   assert(PointeeStorage.BS.Base != 0 &&
345*0fca6ea1SDimitry Andric          "Only composite fields can be initialised");
346a7dea167SDimitry Andric   getInlineDesc()->IsInitialized = true;
347a7dea167SDimitry Andric }
348a7dea167SDimitry Andric 
349a7dea167SDimitry Andric void Pointer::activate() const {
350a7dea167SDimitry Andric   // Field has its bit in an inline descriptor.
351*0fca6ea1SDimitry Andric   assert(PointeeStorage.BS.Base != 0 &&
352*0fca6ea1SDimitry Andric          "Only composite fields can be initialised");
353*0fca6ea1SDimitry Andric 
354*0fca6ea1SDimitry Andric   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
355*0fca6ea1SDimitry Andric     return;
356*0fca6ea1SDimitry Andric 
357a7dea167SDimitry Andric   getInlineDesc()->IsActive = true;
358a7dea167SDimitry Andric }
359a7dea167SDimitry Andric 
360a7dea167SDimitry Andric void Pointer::deactivate() const {
361a7dea167SDimitry Andric   // TODO: this only appears in constructors, so nothing to deactivate.
362a7dea167SDimitry Andric }
363a7dea167SDimitry Andric 
364a7dea167SDimitry Andric bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
365*0fca6ea1SDimitry Andric   // Two null pointers always have the same base.
366*0fca6ea1SDimitry Andric   if (A.isZero() && B.isZero())
367*0fca6ea1SDimitry Andric     return true;
368*0fca6ea1SDimitry Andric 
369*0fca6ea1SDimitry Andric   if (A.isIntegralPointer() && B.isIntegralPointer())
370*0fca6ea1SDimitry Andric     return true;
371*0fca6ea1SDimitry Andric 
372*0fca6ea1SDimitry Andric   if (A.isIntegralPointer() || B.isIntegralPointer())
373*0fca6ea1SDimitry Andric     return A.getSource() == B.getSource();
374*0fca6ea1SDimitry Andric 
375*0fca6ea1SDimitry Andric   return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
376a7dea167SDimitry Andric }
377a7dea167SDimitry Andric 
378a7dea167SDimitry Andric bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
379*0fca6ea1SDimitry Andric   return hasSameBase(A, B) &&
380*0fca6ea1SDimitry Andric          A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
381*0fca6ea1SDimitry Andric          A.getFieldDesc()->IsArray;
382a7dea167SDimitry Andric }
3835f757f3fSDimitry Andric 
384*0fca6ea1SDimitry Andric std::optional<APValue> Pointer::toRValue(const Context &Ctx,
385*0fca6ea1SDimitry Andric                                          QualType ResultType) const {
386*0fca6ea1SDimitry Andric   const ASTContext &ASTCtx = Ctx.getASTContext();
387*0fca6ea1SDimitry Andric   assert(!ResultType.isNull());
3887a6dacacSDimitry Andric   // Method to recursively traverse composites.
3897a6dacacSDimitry Andric   std::function<bool(QualType, const Pointer &, APValue &)> Composite;
390*0fca6ea1SDimitry Andric   Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
391*0fca6ea1SDimitry Andric                                           APValue &R) {
3927a6dacacSDimitry Andric     if (const auto *AT = Ty->getAs<AtomicType>())
3937a6dacacSDimitry Andric       Ty = AT->getValueType();
3947a6dacacSDimitry Andric 
3957a6dacacSDimitry Andric     // Invalid pointers.
396*0fca6ea1SDimitry Andric     if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
397*0fca6ea1SDimitry Andric         Ptr.isPastEnd())
3987a6dacacSDimitry Andric       return false;
3997a6dacacSDimitry Andric 
4007a6dacacSDimitry Andric     // Primitive values.
4017a6dacacSDimitry Andric     if (std::optional<PrimType> T = Ctx.classify(Ty)) {
402*0fca6ea1SDimitry Andric       TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
4037a6dacacSDimitry Andric       return true;
4045f757f3fSDimitry Andric     }
4055f757f3fSDimitry Andric 
4067a6dacacSDimitry Andric     if (const auto *RT = Ty->getAs<RecordType>()) {
4077a6dacacSDimitry Andric       const auto *Record = Ptr.getRecord();
4087a6dacacSDimitry Andric       assert(Record && "Missing record descriptor");
4097a6dacacSDimitry Andric 
4107a6dacacSDimitry Andric       bool Ok = true;
4117a6dacacSDimitry Andric       if (RT->getDecl()->isUnion()) {
4127a6dacacSDimitry Andric         const FieldDecl *ActiveField = nullptr;
4137a6dacacSDimitry Andric         APValue Value;
4147a6dacacSDimitry Andric         for (const auto &F : Record->fields()) {
4157a6dacacSDimitry Andric           const Pointer &FP = Ptr.atField(F.Offset);
4167a6dacacSDimitry Andric           QualType FieldTy = F.Decl->getType();
4177a6dacacSDimitry Andric           if (FP.isActive()) {
4187a6dacacSDimitry Andric             if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
419*0fca6ea1SDimitry Andric               TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
4207a6dacacSDimitry Andric             } else {
4217a6dacacSDimitry Andric               Ok &= Composite(FieldTy, FP, Value);
4227a6dacacSDimitry Andric             }
423*0fca6ea1SDimitry Andric             ActiveField = FP.getFieldDesc()->asFieldDecl();
4247a6dacacSDimitry Andric             break;
4257a6dacacSDimitry Andric           }
4267a6dacacSDimitry Andric         }
4277a6dacacSDimitry Andric         R = APValue(ActiveField, Value);
4287a6dacacSDimitry Andric       } else {
4297a6dacacSDimitry Andric         unsigned NF = Record->getNumFields();
4307a6dacacSDimitry Andric         unsigned NB = Record->getNumBases();
4317a6dacacSDimitry Andric         unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
4327a6dacacSDimitry Andric 
4337a6dacacSDimitry Andric         R = APValue(APValue::UninitStruct(), NB, NF);
4347a6dacacSDimitry Andric 
4357a6dacacSDimitry Andric         for (unsigned I = 0; I < NF; ++I) {
4367a6dacacSDimitry Andric           const Record::Field *FD = Record->getField(I);
4377a6dacacSDimitry Andric           QualType FieldTy = FD->Decl->getType();
4387a6dacacSDimitry Andric           const Pointer &FP = Ptr.atField(FD->Offset);
4397a6dacacSDimitry Andric           APValue &Value = R.getStructField(I);
4407a6dacacSDimitry Andric 
4417a6dacacSDimitry Andric           if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
442*0fca6ea1SDimitry Andric             TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
4437a6dacacSDimitry Andric           } else {
4447a6dacacSDimitry Andric             Ok &= Composite(FieldTy, FP, Value);
4457a6dacacSDimitry Andric           }
4467a6dacacSDimitry Andric         }
4477a6dacacSDimitry Andric 
4487a6dacacSDimitry Andric         for (unsigned I = 0; I < NB; ++I) {
4497a6dacacSDimitry Andric           const Record::Base *BD = Record->getBase(I);
4507a6dacacSDimitry Andric           QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
4517a6dacacSDimitry Andric           const Pointer &BP = Ptr.atField(BD->Offset);
4527a6dacacSDimitry Andric           Ok &= Composite(BaseTy, BP, R.getStructBase(I));
4537a6dacacSDimitry Andric         }
4547a6dacacSDimitry Andric 
4557a6dacacSDimitry Andric         for (unsigned I = 0; I < NV; ++I) {
4567a6dacacSDimitry Andric           const Record::Base *VD = Record->getVirtualBase(I);
4577a6dacacSDimitry Andric           QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
4587a6dacacSDimitry Andric           const Pointer &VP = Ptr.atField(VD->Offset);
4597a6dacacSDimitry Andric           Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
4607a6dacacSDimitry Andric         }
4617a6dacacSDimitry Andric       }
4627a6dacacSDimitry Andric       return Ok;
4637a6dacacSDimitry Andric     }
4647a6dacacSDimitry Andric 
4657a6dacacSDimitry Andric     if (Ty->isIncompleteArrayType()) {
4667a6dacacSDimitry Andric       R = APValue(APValue::UninitArray(), 0, 0);
4677a6dacacSDimitry Andric       return true;
4687a6dacacSDimitry Andric     }
4697a6dacacSDimitry Andric 
4707a6dacacSDimitry Andric     if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
4717a6dacacSDimitry Andric       const size_t NumElems = Ptr.getNumElems();
4727a6dacacSDimitry Andric       QualType ElemTy = AT->getElementType();
4737a6dacacSDimitry Andric       R = APValue(APValue::UninitArray{}, NumElems, NumElems);
4747a6dacacSDimitry Andric 
4757a6dacacSDimitry Andric       bool Ok = true;
4767a6dacacSDimitry Andric       for (unsigned I = 0; I < NumElems; ++I) {
4777a6dacacSDimitry Andric         APValue &Slot = R.getArrayInitializedElt(I);
4787a6dacacSDimitry Andric         const Pointer &EP = Ptr.atIndex(I);
4797a6dacacSDimitry Andric         if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
480*0fca6ea1SDimitry Andric           TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
4817a6dacacSDimitry Andric         } else {
4827a6dacacSDimitry Andric           Ok &= Composite(ElemTy, EP.narrow(), Slot);
4837a6dacacSDimitry Andric         }
4847a6dacacSDimitry Andric       }
4857a6dacacSDimitry Andric       return Ok;
4867a6dacacSDimitry Andric     }
4877a6dacacSDimitry Andric 
4887a6dacacSDimitry Andric     // Complex types.
4897a6dacacSDimitry Andric     if (const auto *CT = Ty->getAs<ComplexType>()) {
4907a6dacacSDimitry Andric       QualType ElemTy = CT->getElementType();
4917a6dacacSDimitry Andric 
4927a6dacacSDimitry Andric       if (ElemTy->isIntegerType()) {
493*0fca6ea1SDimitry Andric         std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
494*0fca6ea1SDimitry Andric         assert(ElemT);
4957a6dacacSDimitry Andric         INT_TYPE_SWITCH(*ElemT, {
4967a6dacacSDimitry Andric           auto V1 = Ptr.atIndex(0).deref<T>();
4977a6dacacSDimitry Andric           auto V2 = Ptr.atIndex(1).deref<T>();
4987a6dacacSDimitry Andric           R = APValue(V1.toAPSInt(), V2.toAPSInt());
4997a6dacacSDimitry Andric           return true;
5007a6dacacSDimitry Andric         });
5017a6dacacSDimitry Andric       } else if (ElemTy->isFloatingType()) {
5027a6dacacSDimitry Andric         R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
5037a6dacacSDimitry Andric                     Ptr.atIndex(1).deref<Floating>().getAPFloat());
5047a6dacacSDimitry Andric         return true;
5057a6dacacSDimitry Andric       }
5067a6dacacSDimitry Andric       return false;
5077a6dacacSDimitry Andric     }
5087a6dacacSDimitry Andric 
509*0fca6ea1SDimitry Andric     // Vector types.
510*0fca6ea1SDimitry Andric     if (const auto *VT = Ty->getAs<VectorType>()) {
511*0fca6ea1SDimitry Andric       assert(Ptr.getFieldDesc()->isPrimitiveArray());
512*0fca6ea1SDimitry Andric       QualType ElemTy = VT->getElementType();
513*0fca6ea1SDimitry Andric       PrimType ElemT = *Ctx.classify(ElemTy);
514*0fca6ea1SDimitry Andric 
515*0fca6ea1SDimitry Andric       SmallVector<APValue> Values;
516*0fca6ea1SDimitry Andric       Values.reserve(VT->getNumElements());
517*0fca6ea1SDimitry Andric       for (unsigned I = 0; I != VT->getNumElements(); ++I) {
518*0fca6ea1SDimitry Andric         TYPE_SWITCH(ElemT, {
519*0fca6ea1SDimitry Andric           Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
520*0fca6ea1SDimitry Andric         });
521*0fca6ea1SDimitry Andric       }
522*0fca6ea1SDimitry Andric 
523*0fca6ea1SDimitry Andric       assert(Values.size() == VT->getNumElements());
524*0fca6ea1SDimitry Andric       R = APValue(Values.data(), Values.size());
525*0fca6ea1SDimitry Andric       return true;
526*0fca6ea1SDimitry Andric     }
527*0fca6ea1SDimitry Andric 
5287a6dacacSDimitry Andric     llvm_unreachable("invalid value to return");
5297a6dacacSDimitry Andric   };
5307a6dacacSDimitry Andric 
531*0fca6ea1SDimitry Andric   // Invalid to read from.
532*0fca6ea1SDimitry Andric   if (isDummy() || !isLive() || isPastEnd())
5337a6dacacSDimitry Andric     return std::nullopt;
5347a6dacacSDimitry Andric 
535*0fca6ea1SDimitry Andric   // We can return these as rvalues, but we can't deref() them.
536*0fca6ea1SDimitry Andric   if (isZero() || isIntegralPointer())
537*0fca6ea1SDimitry Andric     return toAPValue(ASTCtx);
538*0fca6ea1SDimitry Andric 
539*0fca6ea1SDimitry Andric   // Just load primitive types.
540*0fca6ea1SDimitry Andric   if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
541*0fca6ea1SDimitry Andric     TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
542*0fca6ea1SDimitry Andric   }
543*0fca6ea1SDimitry Andric 
5447a6dacacSDimitry Andric   // Return the composite type.
5455f757f3fSDimitry Andric   APValue Result;
5467a6dacacSDimitry Andric   if (!Composite(getType(), *this, Result))
5477a6dacacSDimitry Andric     return std::nullopt;
5485f757f3fSDimitry Andric   return Result;
5495f757f3fSDimitry Andric }
550