xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Pointer.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric 
9*700637cbSDimitry Andric #include "Pointer.h"
10*700637cbSDimitry Andric #include "Boolean.h"
11*700637cbSDimitry Andric #include "Context.h"
12*700637cbSDimitry Andric #include "Floating.h"
13*700637cbSDimitry Andric #include "Function.h"
14*700637cbSDimitry Andric #include "Integral.h"
15*700637cbSDimitry Andric #include "InterpBlock.h"
16*700637cbSDimitry Andric #include "MemberPointer.h"
17*700637cbSDimitry Andric #include "PrimType.h"
18*700637cbSDimitry Andric #include "Record.h"
19*700637cbSDimitry Andric #include "clang/AST/ExprCXX.h"
20*700637cbSDimitry Andric #include "clang/AST/RecordLayout.h"
21*700637cbSDimitry Andric 
22*700637cbSDimitry Andric using namespace clang;
23*700637cbSDimitry Andric using namespace clang::interp;
24*700637cbSDimitry Andric 
Pointer(Block * Pointee)25*700637cbSDimitry Andric Pointer::Pointer(Block *Pointee)
26*700637cbSDimitry Andric     : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
27*700637cbSDimitry Andric               Pointee->getDescriptor()->getMetadataSize()) {}
28*700637cbSDimitry Andric 
Pointer(Block * Pointee,uint64_t BaseAndOffset)29*700637cbSDimitry Andric Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
30*700637cbSDimitry Andric     : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
31*700637cbSDimitry Andric 
Pointer(const Pointer & P)32*700637cbSDimitry Andric Pointer::Pointer(const Pointer &P)
33*700637cbSDimitry Andric     : Offset(P.Offset), StorageKind(P.StorageKind),
34*700637cbSDimitry Andric       PointeeStorage(P.PointeeStorage) {
35*700637cbSDimitry Andric 
36*700637cbSDimitry Andric   if (isBlockPointer() && PointeeStorage.BS.Pointee)
37*700637cbSDimitry Andric     PointeeStorage.BS.Pointee->addPointer(this);
38*700637cbSDimitry Andric }
39*700637cbSDimitry Andric 
Pointer(Block * Pointee,unsigned Base,uint64_t Offset)40*700637cbSDimitry Andric Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
41*700637cbSDimitry Andric     : Offset(Offset), StorageKind(Storage::Block) {
42*700637cbSDimitry Andric   assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
43*700637cbSDimitry Andric 
44*700637cbSDimitry Andric   PointeeStorage.BS = {Pointee, Base};
45*700637cbSDimitry Andric 
46*700637cbSDimitry Andric   if (Pointee)
47*700637cbSDimitry Andric     Pointee->addPointer(this);
48*700637cbSDimitry Andric }
49*700637cbSDimitry Andric 
Pointer(Pointer && P)50*700637cbSDimitry Andric Pointer::Pointer(Pointer &&P)
51*700637cbSDimitry Andric     : Offset(P.Offset), StorageKind(P.StorageKind),
52*700637cbSDimitry Andric       PointeeStorage(P.PointeeStorage) {
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric   if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
55*700637cbSDimitry Andric     PointeeStorage.BS.Pointee->replacePointer(&P, this);
56*700637cbSDimitry Andric }
57*700637cbSDimitry Andric 
~Pointer()58*700637cbSDimitry Andric Pointer::~Pointer() {
59*700637cbSDimitry Andric   if (!isBlockPointer())
60*700637cbSDimitry Andric     return;
61*700637cbSDimitry Andric 
62*700637cbSDimitry Andric   if (Block *Pointee = PointeeStorage.BS.Pointee) {
63*700637cbSDimitry Andric     Pointee->removePointer(this);
64*700637cbSDimitry Andric     PointeeStorage.BS.Pointee = nullptr;
65*700637cbSDimitry Andric     Pointee->cleanup();
66*700637cbSDimitry Andric   }
67*700637cbSDimitry Andric }
68*700637cbSDimitry Andric 
operator =(const Pointer & P)69*700637cbSDimitry Andric void Pointer::operator=(const Pointer &P) {
70*700637cbSDimitry Andric   // If the current storage type is Block, we need to remove
71*700637cbSDimitry Andric   // this pointer from the block.
72*700637cbSDimitry Andric   if (isBlockPointer()) {
73*700637cbSDimitry Andric     if (P.isBlockPointer() && this->block() == P.block()) {
74*700637cbSDimitry Andric       Offset = P.Offset;
75*700637cbSDimitry Andric       PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
76*700637cbSDimitry Andric       return;
77*700637cbSDimitry Andric     }
78*700637cbSDimitry Andric 
79*700637cbSDimitry Andric     if (Block *Pointee = PointeeStorage.BS.Pointee) {
80*700637cbSDimitry Andric       Pointee->removePointer(this);
81*700637cbSDimitry Andric       PointeeStorage.BS.Pointee = nullptr;
82*700637cbSDimitry Andric       Pointee->cleanup();
83*700637cbSDimitry Andric     }
84*700637cbSDimitry Andric   }
85*700637cbSDimitry Andric 
86*700637cbSDimitry Andric   StorageKind = P.StorageKind;
87*700637cbSDimitry Andric   Offset = P.Offset;
88*700637cbSDimitry Andric 
89*700637cbSDimitry Andric   if (P.isBlockPointer()) {
90*700637cbSDimitry Andric     PointeeStorage.BS = P.PointeeStorage.BS;
91*700637cbSDimitry Andric     PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
92*700637cbSDimitry Andric 
93*700637cbSDimitry Andric     if (PointeeStorage.BS.Pointee)
94*700637cbSDimitry Andric       PointeeStorage.BS.Pointee->addPointer(this);
95*700637cbSDimitry Andric   } else if (P.isIntegralPointer()) {
96*700637cbSDimitry Andric     PointeeStorage.Int = P.PointeeStorage.Int;
97*700637cbSDimitry Andric   } else if (P.isFunctionPointer()) {
98*700637cbSDimitry Andric     PointeeStorage.Fn = P.PointeeStorage.Fn;
99*700637cbSDimitry Andric   } else if (P.isTypeidPointer()) {
100*700637cbSDimitry Andric     PointeeStorage.Typeid = P.PointeeStorage.Typeid;
101*700637cbSDimitry Andric   } else {
102*700637cbSDimitry Andric     assert(false && "Unhandled storage kind");
103*700637cbSDimitry Andric   }
104*700637cbSDimitry Andric }
105*700637cbSDimitry Andric 
operator =(Pointer && P)106*700637cbSDimitry Andric void Pointer::operator=(Pointer &&P) {
107*700637cbSDimitry Andric   // If the current storage type is Block, we need to remove
108*700637cbSDimitry Andric   // this pointer from the block.
109*700637cbSDimitry Andric   if (isBlockPointer()) {
110*700637cbSDimitry Andric     if (P.isBlockPointer() && this->block() == P.block()) {
111*700637cbSDimitry Andric       Offset = P.Offset;
112*700637cbSDimitry Andric       PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
113*700637cbSDimitry Andric       return;
114*700637cbSDimitry Andric     }
115*700637cbSDimitry Andric 
116*700637cbSDimitry Andric     if (Block *Pointee = PointeeStorage.BS.Pointee) {
117*700637cbSDimitry Andric       Pointee->removePointer(this);
118*700637cbSDimitry Andric       PointeeStorage.BS.Pointee = nullptr;
119*700637cbSDimitry Andric       Pointee->cleanup();
120*700637cbSDimitry Andric     }
121*700637cbSDimitry Andric   }
122*700637cbSDimitry Andric 
123*700637cbSDimitry Andric   StorageKind = P.StorageKind;
124*700637cbSDimitry Andric   Offset = P.Offset;
125*700637cbSDimitry Andric 
126*700637cbSDimitry Andric   if (P.isBlockPointer()) {
127*700637cbSDimitry Andric     PointeeStorage.BS = P.PointeeStorage.BS;
128*700637cbSDimitry Andric     PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
129*700637cbSDimitry Andric 
130*700637cbSDimitry Andric     if (PointeeStorage.BS.Pointee)
131*700637cbSDimitry Andric       PointeeStorage.BS.Pointee->addPointer(this);
132*700637cbSDimitry Andric   } else if (P.isIntegralPointer()) {
133*700637cbSDimitry Andric     PointeeStorage.Int = P.PointeeStorage.Int;
134*700637cbSDimitry Andric   } else if (P.isFunctionPointer()) {
135*700637cbSDimitry Andric     PointeeStorage.Fn = P.PointeeStorage.Fn;
136*700637cbSDimitry Andric   } else if (P.isTypeidPointer()) {
137*700637cbSDimitry Andric     PointeeStorage.Typeid = P.PointeeStorage.Typeid;
138*700637cbSDimitry Andric   } else {
139*700637cbSDimitry Andric     assert(false && "Unhandled storage kind");
140*700637cbSDimitry Andric   }
141*700637cbSDimitry Andric }
142*700637cbSDimitry Andric 
toAPValue(const ASTContext & ASTCtx) const143*700637cbSDimitry Andric APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
144*700637cbSDimitry Andric   llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
145*700637cbSDimitry Andric 
146*700637cbSDimitry Andric   if (isZero())
147*700637cbSDimitry Andric     return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
148*700637cbSDimitry Andric                    /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
149*700637cbSDimitry Andric   if (isIntegralPointer())
150*700637cbSDimitry Andric     return APValue(static_cast<const Expr *>(nullptr),
151*700637cbSDimitry Andric                    CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
152*700637cbSDimitry Andric                    Path,
153*700637cbSDimitry Andric                    /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
154*700637cbSDimitry Andric   if (isFunctionPointer()) {
155*700637cbSDimitry Andric     const FunctionPointer &FP = asFunctionPointer();
156*700637cbSDimitry Andric     if (const FunctionDecl *FD = FP.getFunction()->getDecl())
157*700637cbSDimitry Andric       return APValue(FD, CharUnits::fromQuantity(Offset), {},
158*700637cbSDimitry Andric                      /*OnePastTheEnd=*/false, /*IsNull=*/false);
159*700637cbSDimitry Andric     return APValue(FP.getFunction()->getExpr(), CharUnits::fromQuantity(Offset),
160*700637cbSDimitry Andric                    {},
161*700637cbSDimitry Andric                    /*OnePastTheEnd=*/false, /*IsNull=*/false);
162*700637cbSDimitry Andric   }
163*700637cbSDimitry Andric 
164*700637cbSDimitry Andric   if (isTypeidPointer()) {
165*700637cbSDimitry Andric     TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr);
166*700637cbSDimitry Andric     return APValue(
167*700637cbSDimitry Andric         APValue::LValueBase::getTypeInfo(
168*700637cbSDimitry Andric             TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)),
169*700637cbSDimitry Andric         CharUnits::Zero(), {},
170*700637cbSDimitry Andric         /*OnePastTheEnd=*/false, /*IsNull=*/false);
171*700637cbSDimitry Andric   }
172*700637cbSDimitry Andric 
173*700637cbSDimitry Andric   // Build the lvalue base from the block.
174*700637cbSDimitry Andric   const Descriptor *Desc = getDeclDesc();
175*700637cbSDimitry Andric   APValue::LValueBase Base;
176*700637cbSDimitry Andric   if (const auto *VD = Desc->asValueDecl())
177*700637cbSDimitry Andric     Base = VD;
178*700637cbSDimitry Andric   else if (const auto *E = Desc->asExpr()) {
179*700637cbSDimitry Andric     if (block()->isDynamic()) {
180*700637cbSDimitry Andric       QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
181*700637cbSDimitry Andric       // FIXME: Suboptimal counting of dynamic allocations. Move this to Context
182*700637cbSDimitry Andric       // or InterpState?
183*700637cbSDimitry Andric       static int ReportedDynamicAllocs = 0;
184*700637cbSDimitry Andric       DynamicAllocLValue DA(ReportedDynamicAllocs++);
185*700637cbSDimitry Andric       Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
186*700637cbSDimitry Andric     } else {
187*700637cbSDimitry Andric       Base = E;
188*700637cbSDimitry Andric     }
189*700637cbSDimitry Andric   } else
190*700637cbSDimitry Andric     llvm_unreachable("Invalid allocation type");
191*700637cbSDimitry Andric 
192*700637cbSDimitry Andric   if (isUnknownSizeArray())
193*700637cbSDimitry Andric     return APValue(Base, CharUnits::Zero(), Path,
194*700637cbSDimitry Andric                    /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
195*700637cbSDimitry Andric 
196*700637cbSDimitry Andric   CharUnits Offset = CharUnits::Zero();
197*700637cbSDimitry Andric 
198*700637cbSDimitry Andric   auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
199*700637cbSDimitry Andric     // This shouldn't happen, but if it does, don't crash inside
200*700637cbSDimitry Andric     // getASTRecordLayout.
201*700637cbSDimitry Andric     if (FD->getParent()->isInvalidDecl())
202*700637cbSDimitry Andric       return CharUnits::Zero();
203*700637cbSDimitry Andric     const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
204*700637cbSDimitry Andric     unsigned FieldIndex = FD->getFieldIndex();
205*700637cbSDimitry Andric     return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
206*700637cbSDimitry Andric   };
207*700637cbSDimitry Andric 
208*700637cbSDimitry Andric   bool UsePath = true;
209*700637cbSDimitry Andric   if (const ValueDecl *VD = getDeclDesc()->asValueDecl();
210*700637cbSDimitry Andric       VD && VD->getType()->isReferenceType())
211*700637cbSDimitry Andric     UsePath = false;
212*700637cbSDimitry Andric 
213*700637cbSDimitry Andric   // Build the path into the object.
214*700637cbSDimitry Andric   bool OnePastEnd = isOnePastEnd();
215*700637cbSDimitry Andric   Pointer Ptr = *this;
216*700637cbSDimitry Andric   while (Ptr.isField() || Ptr.isArrayElement()) {
217*700637cbSDimitry Andric 
218*700637cbSDimitry Andric     if (Ptr.isArrayRoot()) {
219*700637cbSDimitry Andric       // An array root may still be an array element itself.
220*700637cbSDimitry Andric       if (Ptr.isArrayElement()) {
221*700637cbSDimitry Andric         Ptr = Ptr.expand();
222*700637cbSDimitry Andric         const Descriptor *Desc = Ptr.getFieldDesc();
223*700637cbSDimitry Andric         unsigned Index = Ptr.getIndex();
224*700637cbSDimitry Andric         QualType ElemType = Desc->getElemQualType();
225*700637cbSDimitry Andric         Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
226*700637cbSDimitry Andric         if (Ptr.getArray().getType()->isArrayType())
227*700637cbSDimitry Andric           Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
228*700637cbSDimitry Andric         Ptr = Ptr.getArray();
229*700637cbSDimitry Andric       } else {
230*700637cbSDimitry Andric         const Descriptor *Desc = Ptr.getFieldDesc();
231*700637cbSDimitry Andric         const auto *Dcl = Desc->asDecl();
232*700637cbSDimitry Andric         Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
233*700637cbSDimitry Andric 
234*700637cbSDimitry Andric         if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl))
235*700637cbSDimitry Andric           Offset += getFieldOffset(FD);
236*700637cbSDimitry Andric 
237*700637cbSDimitry Andric         Ptr = Ptr.getBase();
238*700637cbSDimitry Andric       }
239*700637cbSDimitry Andric     } else if (Ptr.isArrayElement()) {
240*700637cbSDimitry Andric       Ptr = Ptr.expand();
241*700637cbSDimitry Andric       const Descriptor *Desc = Ptr.getFieldDesc();
242*700637cbSDimitry Andric       unsigned Index;
243*700637cbSDimitry Andric       if (Ptr.isOnePastEnd()) {
244*700637cbSDimitry Andric         Index = Ptr.getArray().getNumElems();
245*700637cbSDimitry Andric         OnePastEnd = false;
246*700637cbSDimitry Andric       } else
247*700637cbSDimitry Andric         Index = Ptr.getIndex();
248*700637cbSDimitry Andric 
249*700637cbSDimitry Andric       QualType ElemType = Desc->getElemQualType();
250*700637cbSDimitry Andric       if (const auto *RD = ElemType->getAsRecordDecl();
251*700637cbSDimitry Andric           RD && !RD->getDefinition()) {
252*700637cbSDimitry Andric         // Ignore this for the offset.
253*700637cbSDimitry Andric       } else {
254*700637cbSDimitry Andric         Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
255*700637cbSDimitry Andric       }
256*700637cbSDimitry Andric       if (Ptr.getArray().getType()->isArrayType())
257*700637cbSDimitry Andric         Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
258*700637cbSDimitry Andric       Ptr = Ptr.getArray();
259*700637cbSDimitry Andric     } else {
260*700637cbSDimitry Andric       const Descriptor *Desc = Ptr.getFieldDesc();
261*700637cbSDimitry Andric       bool IsVirtual = false;
262*700637cbSDimitry Andric 
263*700637cbSDimitry Andric       // Create a path entry for the field.
264*700637cbSDimitry Andric       if (const auto *BaseOrMember = Desc->asDecl()) {
265*700637cbSDimitry Andric         if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
266*700637cbSDimitry Andric           Ptr = Ptr.getBase();
267*700637cbSDimitry Andric           Offset += getFieldOffset(FD);
268*700637cbSDimitry Andric         } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
269*700637cbSDimitry Andric           IsVirtual = Ptr.isVirtualBaseClass();
270*700637cbSDimitry Andric           Ptr = Ptr.getBase();
271*700637cbSDimitry Andric           const Record *BaseRecord = Ptr.getRecord();
272*700637cbSDimitry Andric 
273*700637cbSDimitry Andric           const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
274*700637cbSDimitry Andric               cast<CXXRecordDecl>(BaseRecord->getDecl()));
275*700637cbSDimitry Andric           if (IsVirtual)
276*700637cbSDimitry Andric             Offset += Layout.getVBaseClassOffset(RD);
277*700637cbSDimitry Andric           else
278*700637cbSDimitry Andric             Offset += Layout.getBaseClassOffset(RD);
279*700637cbSDimitry Andric 
280*700637cbSDimitry Andric         } else {
281*700637cbSDimitry Andric           Ptr = Ptr.getBase();
282*700637cbSDimitry Andric         }
283*700637cbSDimitry Andric         Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
284*700637cbSDimitry Andric         continue;
285*700637cbSDimitry Andric       }
286*700637cbSDimitry Andric       llvm_unreachable("Invalid field type");
287*700637cbSDimitry Andric     }
288*700637cbSDimitry Andric   }
289*700637cbSDimitry Andric 
290*700637cbSDimitry Andric   // We assemble the LValuePath starting from the innermost pointer to the
291*700637cbSDimitry Andric   // outermost one. SO in a.b.c, the first element in Path will refer to
292*700637cbSDimitry Andric   // the field 'c', while later code expects it to refer to 'a'.
293*700637cbSDimitry Andric   // Just invert the order of the elements.
294*700637cbSDimitry Andric   std::reverse(Path.begin(), Path.end());
295*700637cbSDimitry Andric 
296*700637cbSDimitry Andric   if (UsePath)
297*700637cbSDimitry Andric     return APValue(Base, Offset, Path, OnePastEnd);
298*700637cbSDimitry Andric 
299*700637cbSDimitry Andric   return APValue(Base, Offset, APValue::NoLValuePath());
300*700637cbSDimitry Andric }
301*700637cbSDimitry Andric 
print(llvm::raw_ostream & OS) const302*700637cbSDimitry Andric void Pointer::print(llvm::raw_ostream &OS) const {
303*700637cbSDimitry Andric   switch (StorageKind) {
304*700637cbSDimitry Andric   case Storage::Block: {
305*700637cbSDimitry Andric     const Block *B = PointeeStorage.BS.Pointee;
306*700637cbSDimitry Andric     OS << "(Block) " << B << " {";
307*700637cbSDimitry Andric 
308*700637cbSDimitry Andric     if (isRoot())
309*700637cbSDimitry Andric       OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
310*700637cbSDimitry Andric     else
311*700637cbSDimitry Andric       OS << PointeeStorage.BS.Base << ", ";
312*700637cbSDimitry Andric 
313*700637cbSDimitry Andric     if (isElementPastEnd())
314*700637cbSDimitry Andric       OS << "pastend, ";
315*700637cbSDimitry Andric     else
316*700637cbSDimitry Andric       OS << Offset << ", ";
317*700637cbSDimitry Andric 
318*700637cbSDimitry Andric     if (B)
319*700637cbSDimitry Andric       OS << B->getSize();
320*700637cbSDimitry Andric     else
321*700637cbSDimitry Andric       OS << "nullptr";
322*700637cbSDimitry Andric     OS << "}";
323*700637cbSDimitry Andric   } break;
324*700637cbSDimitry Andric   case Storage::Int:
325*700637cbSDimitry Andric     OS << "(Int) {";
326*700637cbSDimitry Andric     OS << PointeeStorage.Int.Value << " + " << Offset << ", "
327*700637cbSDimitry Andric        << PointeeStorage.Int.Desc;
328*700637cbSDimitry Andric     OS << "}";
329*700637cbSDimitry Andric     break;
330*700637cbSDimitry Andric   case Storage::Fn:
331*700637cbSDimitry Andric     OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
332*700637cbSDimitry Andric        << " }";
333*700637cbSDimitry Andric     break;
334*700637cbSDimitry Andric   case Storage::Typeid:
335*700637cbSDimitry Andric     OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
336*700637cbSDimitry Andric        << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
337*700637cbSDimitry Andric        << "}";
338*700637cbSDimitry Andric   }
339*700637cbSDimitry Andric }
340*700637cbSDimitry Andric 
computeOffsetForComparison() const341*700637cbSDimitry Andric size_t Pointer::computeOffsetForComparison() const {
342*700637cbSDimitry Andric   if (isIntegralPointer())
343*700637cbSDimitry Andric     return asIntPointer().Value + Offset;
344*700637cbSDimitry Andric   if (isTypeidPointer())
345*700637cbSDimitry Andric     return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
346*700637cbSDimitry Andric 
347*700637cbSDimitry Andric   if (!isBlockPointer())
348*700637cbSDimitry Andric     return Offset;
349*700637cbSDimitry Andric 
350*700637cbSDimitry Andric   size_t Result = 0;
351*700637cbSDimitry Andric   Pointer P = *this;
352*700637cbSDimitry Andric   while (true) {
353*700637cbSDimitry Andric 
354*700637cbSDimitry Andric     if (P.isVirtualBaseClass()) {
355*700637cbSDimitry Andric       Result += getInlineDesc()->Offset;
356*700637cbSDimitry Andric       P = P.getBase();
357*700637cbSDimitry Andric       continue;
358*700637cbSDimitry Andric     }
359*700637cbSDimitry Andric 
360*700637cbSDimitry Andric     if (P.isBaseClass()) {
361*700637cbSDimitry Andric       if (P.getRecord()->getNumVirtualBases() > 0)
362*700637cbSDimitry Andric         Result += P.getInlineDesc()->Offset;
363*700637cbSDimitry Andric       P = P.getBase();
364*700637cbSDimitry Andric       continue;
365*700637cbSDimitry Andric     }
366*700637cbSDimitry Andric     if (P.isArrayElement()) {
367*700637cbSDimitry Andric       P = P.expand();
368*700637cbSDimitry Andric       Result += (P.getIndex() * P.elemSize());
369*700637cbSDimitry Andric       P = P.getArray();
370*700637cbSDimitry Andric       continue;
371*700637cbSDimitry Andric     }
372*700637cbSDimitry Andric 
373*700637cbSDimitry Andric     if (P.isRoot()) {
374*700637cbSDimitry Andric       if (P.isOnePastEnd())
375*700637cbSDimitry Andric         ++Result;
376*700637cbSDimitry Andric       break;
377*700637cbSDimitry Andric     }
378*700637cbSDimitry Andric 
379*700637cbSDimitry Andric     if (const Record *R = P.getBase().getRecord(); R && R->isUnion()) {
380*700637cbSDimitry Andric       // Direct child of a union - all have offset 0.
381*700637cbSDimitry Andric       P = P.getBase();
382*700637cbSDimitry Andric       continue;
383*700637cbSDimitry Andric     }
384*700637cbSDimitry Andric 
385*700637cbSDimitry Andric     // Fields, etc.
386*700637cbSDimitry Andric     Result += P.getInlineDesc()->Offset;
387*700637cbSDimitry Andric     if (P.isOnePastEnd())
388*700637cbSDimitry Andric       ++Result;
389*700637cbSDimitry Andric 
390*700637cbSDimitry Andric     P = P.getBase();
391*700637cbSDimitry Andric     if (P.isRoot())
392*700637cbSDimitry Andric       break;
393*700637cbSDimitry Andric   }
394*700637cbSDimitry Andric 
395*700637cbSDimitry Andric   return Result;
396*700637cbSDimitry Andric }
397*700637cbSDimitry Andric 
toDiagnosticString(const ASTContext & Ctx) const398*700637cbSDimitry Andric std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
399*700637cbSDimitry Andric   if (isZero())
400*700637cbSDimitry Andric     return "nullptr";
401*700637cbSDimitry Andric 
402*700637cbSDimitry Andric   if (isIntegralPointer())
403*700637cbSDimitry Andric     return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
404*700637cbSDimitry Andric 
405*700637cbSDimitry Andric   if (isFunctionPointer())
406*700637cbSDimitry Andric     return asFunctionPointer().toDiagnosticString(Ctx);
407*700637cbSDimitry Andric 
408*700637cbSDimitry Andric   return toAPValue(Ctx).getAsString(Ctx, getType());
409*700637cbSDimitry Andric }
410*700637cbSDimitry Andric 
isInitialized() const411*700637cbSDimitry Andric bool Pointer::isInitialized() const {
412*700637cbSDimitry Andric   if (!isBlockPointer())
413*700637cbSDimitry Andric     return true;
414*700637cbSDimitry Andric 
415*700637cbSDimitry Andric   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
416*700637cbSDimitry Andric     const GlobalInlineDescriptor &GD =
417*700637cbSDimitry Andric         *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
418*700637cbSDimitry Andric     return GD.InitState == GlobalInitState::Initialized;
419*700637cbSDimitry Andric   }
420*700637cbSDimitry Andric 
421*700637cbSDimitry Andric   assert(PointeeStorage.BS.Pointee &&
422*700637cbSDimitry Andric          "Cannot check if null pointer was initialized");
423*700637cbSDimitry Andric   const Descriptor *Desc = getFieldDesc();
424*700637cbSDimitry Andric   assert(Desc);
425*700637cbSDimitry Andric   if (Desc->isPrimitiveArray()) {
426*700637cbSDimitry Andric     if (isStatic() && PointeeStorage.BS.Base == 0)
427*700637cbSDimitry Andric       return true;
428*700637cbSDimitry Andric 
429*700637cbSDimitry Andric     InitMapPtr &IM = getInitMap();
430*700637cbSDimitry Andric 
431*700637cbSDimitry Andric     if (!IM)
432*700637cbSDimitry Andric       return false;
433*700637cbSDimitry Andric 
434*700637cbSDimitry Andric     if (IM->first)
435*700637cbSDimitry Andric       return true;
436*700637cbSDimitry Andric 
437*700637cbSDimitry Andric     return IM->second->isElementInitialized(getIndex());
438*700637cbSDimitry Andric   }
439*700637cbSDimitry Andric 
440*700637cbSDimitry Andric   if (asBlockPointer().Base == 0)
441*700637cbSDimitry Andric     return true;
442*700637cbSDimitry Andric 
443*700637cbSDimitry Andric   // Field has its bit in an inline descriptor.
444*700637cbSDimitry Andric   return getInlineDesc()->IsInitialized;
445*700637cbSDimitry Andric }
446*700637cbSDimitry Andric 
initialize() const447*700637cbSDimitry Andric void Pointer::initialize() const {
448*700637cbSDimitry Andric   if (!isBlockPointer())
449*700637cbSDimitry Andric     return;
450*700637cbSDimitry Andric 
451*700637cbSDimitry Andric   assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
452*700637cbSDimitry Andric 
453*700637cbSDimitry Andric   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
454*700637cbSDimitry Andric     GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
455*700637cbSDimitry Andric         asBlockPointer().Pointee->rawData());
456*700637cbSDimitry Andric     GD.InitState = GlobalInitState::Initialized;
457*700637cbSDimitry Andric     return;
458*700637cbSDimitry Andric   }
459*700637cbSDimitry Andric 
460*700637cbSDimitry Andric   const Descriptor *Desc = getFieldDesc();
461*700637cbSDimitry Andric   assert(Desc);
462*700637cbSDimitry Andric   if (Desc->isPrimitiveArray()) {
463*700637cbSDimitry Andric     // Primitive global arrays don't have an initmap.
464*700637cbSDimitry Andric     if (isStatic() && PointeeStorage.BS.Base == 0)
465*700637cbSDimitry Andric       return;
466*700637cbSDimitry Andric 
467*700637cbSDimitry Andric     // Nothing to do for these.
468*700637cbSDimitry Andric     if (Desc->getNumElems() == 0)
469*700637cbSDimitry Andric       return;
470*700637cbSDimitry Andric 
471*700637cbSDimitry Andric     InitMapPtr &IM = getInitMap();
472*700637cbSDimitry Andric     if (!IM)
473*700637cbSDimitry Andric       IM =
474*700637cbSDimitry Andric           std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
475*700637cbSDimitry Andric 
476*700637cbSDimitry Andric     assert(IM);
477*700637cbSDimitry Andric 
478*700637cbSDimitry Andric     // All initialized.
479*700637cbSDimitry Andric     if (IM->first)
480*700637cbSDimitry Andric       return;
481*700637cbSDimitry Andric 
482*700637cbSDimitry Andric     if (IM->second->initializeElement(getIndex())) {
483*700637cbSDimitry Andric       IM->first = true;
484*700637cbSDimitry Andric       IM->second.reset();
485*700637cbSDimitry Andric     }
486*700637cbSDimitry Andric     return;
487*700637cbSDimitry Andric   }
488*700637cbSDimitry Andric 
489*700637cbSDimitry Andric   // Field has its bit in an inline descriptor.
490*700637cbSDimitry Andric   assert(PointeeStorage.BS.Base != 0 &&
491*700637cbSDimitry Andric          "Only composite fields can be initialised");
492*700637cbSDimitry Andric   getInlineDesc()->IsInitialized = true;
493*700637cbSDimitry Andric }
494*700637cbSDimitry Andric 
activate() const495*700637cbSDimitry Andric void Pointer::activate() const {
496*700637cbSDimitry Andric   // Field has its bit in an inline descriptor.
497*700637cbSDimitry Andric   assert(PointeeStorage.BS.Base != 0 &&
498*700637cbSDimitry Andric          "Only composite fields can be activated");
499*700637cbSDimitry Andric 
500*700637cbSDimitry Andric   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
501*700637cbSDimitry Andric     return;
502*700637cbSDimitry Andric   if (!getInlineDesc()->InUnion)
503*700637cbSDimitry Andric     return;
504*700637cbSDimitry Andric 
505*700637cbSDimitry Andric   auto activate = [](Pointer &P) -> void {
506*700637cbSDimitry Andric     P.getInlineDesc()->IsActive = true;
507*700637cbSDimitry Andric   };
508*700637cbSDimitry Andric 
509*700637cbSDimitry Andric   std::function<void(Pointer &)> deactivate;
510*700637cbSDimitry Andric   deactivate = [&deactivate](Pointer &P) -> void {
511*700637cbSDimitry Andric     P.getInlineDesc()->IsActive = false;
512*700637cbSDimitry Andric 
513*700637cbSDimitry Andric     if (const Record *R = P.getRecord()) {
514*700637cbSDimitry Andric       for (const Record::Field &F : R->fields()) {
515*700637cbSDimitry Andric         Pointer FieldPtr = P.atField(F.Offset);
516*700637cbSDimitry Andric         if (FieldPtr.getInlineDesc()->IsActive)
517*700637cbSDimitry Andric           deactivate(FieldPtr);
518*700637cbSDimitry Andric       }
519*700637cbSDimitry Andric       // FIXME: Bases?
520*700637cbSDimitry Andric     }
521*700637cbSDimitry Andric   };
522*700637cbSDimitry Andric 
523*700637cbSDimitry Andric   Pointer B = *this;
524*700637cbSDimitry Andric   while (!B.isRoot() && B.inUnion()) {
525*700637cbSDimitry Andric     activate(B);
526*700637cbSDimitry Andric 
527*700637cbSDimitry Andric     // When walking up the pointer chain, deactivate
528*700637cbSDimitry Andric     // all union child pointers that aren't on our path.
529*700637cbSDimitry Andric     Pointer Cur = B;
530*700637cbSDimitry Andric     B = B.getBase();
531*700637cbSDimitry Andric     if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
532*700637cbSDimitry Andric       for (const Record::Field &F : BR->fields()) {
533*700637cbSDimitry Andric         Pointer FieldPtr = B.atField(F.Offset);
534*700637cbSDimitry Andric         if (FieldPtr != Cur)
535*700637cbSDimitry Andric           deactivate(FieldPtr);
536*700637cbSDimitry Andric       }
537*700637cbSDimitry Andric     }
538*700637cbSDimitry Andric   }
539*700637cbSDimitry Andric }
540*700637cbSDimitry Andric 
deactivate() const541*700637cbSDimitry Andric void Pointer::deactivate() const {
542*700637cbSDimitry Andric   // TODO: this only appears in constructors, so nothing to deactivate.
543*700637cbSDimitry Andric }
544*700637cbSDimitry Andric 
hasSameBase(const Pointer & A,const Pointer & B)545*700637cbSDimitry Andric bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
546*700637cbSDimitry Andric   // Two null pointers always have the same base.
547*700637cbSDimitry Andric   if (A.isZero() && B.isZero())
548*700637cbSDimitry Andric     return true;
549*700637cbSDimitry Andric 
550*700637cbSDimitry Andric   if (A.isIntegralPointer() && B.isIntegralPointer())
551*700637cbSDimitry Andric     return true;
552*700637cbSDimitry Andric   if (A.isFunctionPointer() && B.isFunctionPointer())
553*700637cbSDimitry Andric     return true;
554*700637cbSDimitry Andric   if (A.isTypeidPointer() && B.isTypeidPointer())
555*700637cbSDimitry Andric     return true;
556*700637cbSDimitry Andric 
557*700637cbSDimitry Andric   if (A.isIntegralPointer() || B.isIntegralPointer())
558*700637cbSDimitry Andric     return A.getSource() == B.getSource();
559*700637cbSDimitry Andric 
560*700637cbSDimitry Andric   if (A.StorageKind != B.StorageKind)
561*700637cbSDimitry Andric     return false;
562*700637cbSDimitry Andric 
563*700637cbSDimitry Andric   return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
564*700637cbSDimitry Andric }
565*700637cbSDimitry Andric 
pointToSameBlock(const Pointer & A,const Pointer & B)566*700637cbSDimitry Andric bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
567*700637cbSDimitry Andric   if (!A.isBlockPointer() || !B.isBlockPointer())
568*700637cbSDimitry Andric     return false;
569*700637cbSDimitry Andric   return A.block() == B.block();
570*700637cbSDimitry Andric }
571*700637cbSDimitry Andric 
hasSameArray(const Pointer & A,const Pointer & B)572*700637cbSDimitry Andric bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
573*700637cbSDimitry Andric   return hasSameBase(A, B) &&
574*700637cbSDimitry Andric          A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
575*700637cbSDimitry Andric          A.getFieldDesc()->IsArray;
576*700637cbSDimitry Andric }
577*700637cbSDimitry Andric 
pointsToLiteral() const578*700637cbSDimitry Andric bool Pointer::pointsToLiteral() const {
579*700637cbSDimitry Andric   if (isZero() || !isBlockPointer())
580*700637cbSDimitry Andric     return false;
581*700637cbSDimitry Andric 
582*700637cbSDimitry Andric   if (block()->isDynamic())
583*700637cbSDimitry Andric     return false;
584*700637cbSDimitry Andric 
585*700637cbSDimitry Andric   const Expr *E = block()->getDescriptor()->asExpr();
586*700637cbSDimitry Andric   return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
587*700637cbSDimitry Andric }
588*700637cbSDimitry Andric 
pointsToStringLiteral() const589*700637cbSDimitry Andric bool Pointer::pointsToStringLiteral() const {
590*700637cbSDimitry Andric   if (isZero() || !isBlockPointer())
591*700637cbSDimitry Andric     return false;
592*700637cbSDimitry Andric 
593*700637cbSDimitry Andric   if (block()->isDynamic())
594*700637cbSDimitry Andric     return false;
595*700637cbSDimitry Andric 
596*700637cbSDimitry Andric   const Expr *E = block()->getDescriptor()->asExpr();
597*700637cbSDimitry Andric   return E && isa<StringLiteral>(E);
598*700637cbSDimitry Andric }
599*700637cbSDimitry Andric 
600*700637cbSDimitry Andric std::optional<std::pair<Pointer, Pointer>>
computeSplitPoint(const Pointer & A,const Pointer & B)601*700637cbSDimitry Andric Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
602*700637cbSDimitry Andric   if (!A.isBlockPointer() || !B.isBlockPointer())
603*700637cbSDimitry Andric     return std::nullopt;
604*700637cbSDimitry Andric 
605*700637cbSDimitry Andric   if (A.asBlockPointer().Pointee != B.asBlockPointer().Pointee)
606*700637cbSDimitry Andric     return std::nullopt;
607*700637cbSDimitry Andric   if (A.isRoot() && B.isRoot())
608*700637cbSDimitry Andric     return std::nullopt;
609*700637cbSDimitry Andric 
610*700637cbSDimitry Andric   if (A == B)
611*700637cbSDimitry Andric     return std::make_pair(A, B);
612*700637cbSDimitry Andric 
613*700637cbSDimitry Andric   auto getBase = [](const Pointer &P) -> Pointer {
614*700637cbSDimitry Andric     if (P.isArrayElement())
615*700637cbSDimitry Andric       return P.expand().getArray();
616*700637cbSDimitry Andric     return P.getBase();
617*700637cbSDimitry Andric   };
618*700637cbSDimitry Andric 
619*700637cbSDimitry Andric   Pointer IterA = A;
620*700637cbSDimitry Andric   Pointer IterB = B;
621*700637cbSDimitry Andric   Pointer CurA = IterA;
622*700637cbSDimitry Andric   Pointer CurB = IterB;
623*700637cbSDimitry Andric   for (;;) {
624*700637cbSDimitry Andric     if (IterA.asBlockPointer().Base > IterB.asBlockPointer().Base) {
625*700637cbSDimitry Andric       CurA = IterA;
626*700637cbSDimitry Andric       IterA = getBase(IterA);
627*700637cbSDimitry Andric     } else {
628*700637cbSDimitry Andric       CurB = IterB;
629*700637cbSDimitry Andric       IterB = getBase(IterB);
630*700637cbSDimitry Andric     }
631*700637cbSDimitry Andric 
632*700637cbSDimitry Andric     if (IterA == IterB)
633*700637cbSDimitry Andric       return std::make_pair(CurA, CurB);
634*700637cbSDimitry Andric 
635*700637cbSDimitry Andric     if (IterA.isRoot() && IterB.isRoot())
636*700637cbSDimitry Andric       return std::nullopt;
637*700637cbSDimitry Andric   }
638*700637cbSDimitry Andric 
639*700637cbSDimitry Andric   llvm_unreachable("The loop above should've returned.");
640*700637cbSDimitry Andric }
641*700637cbSDimitry Andric 
toRValue(const Context & Ctx,QualType ResultType) const642*700637cbSDimitry Andric std::optional<APValue> Pointer::toRValue(const Context &Ctx,
643*700637cbSDimitry Andric                                          QualType ResultType) const {
644*700637cbSDimitry Andric   const ASTContext &ASTCtx = Ctx.getASTContext();
645*700637cbSDimitry Andric   assert(!ResultType.isNull());
646*700637cbSDimitry Andric   // Method to recursively traverse composites.
647*700637cbSDimitry Andric   std::function<bool(QualType, const Pointer &, APValue &)> Composite;
648*700637cbSDimitry Andric   Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
649*700637cbSDimitry Andric                                           APValue &R) {
650*700637cbSDimitry Andric     if (const auto *AT = Ty->getAs<AtomicType>())
651*700637cbSDimitry Andric       Ty = AT->getValueType();
652*700637cbSDimitry Andric 
653*700637cbSDimitry Andric     // Invalid pointers.
654*700637cbSDimitry Andric     if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
655*700637cbSDimitry Andric         Ptr.isPastEnd())
656*700637cbSDimitry Andric       return false;
657*700637cbSDimitry Andric 
658*700637cbSDimitry Andric     // Primitive values.
659*700637cbSDimitry Andric     if (std::optional<PrimType> T = Ctx.classify(Ty)) {
660*700637cbSDimitry Andric       TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
661*700637cbSDimitry Andric       return true;
662*700637cbSDimitry Andric     }
663*700637cbSDimitry Andric 
664*700637cbSDimitry Andric     if (const auto *RT = Ty->getAs<RecordType>()) {
665*700637cbSDimitry Andric       const auto *Record = Ptr.getRecord();
666*700637cbSDimitry Andric       assert(Record && "Missing record descriptor");
667*700637cbSDimitry Andric 
668*700637cbSDimitry Andric       bool Ok = true;
669*700637cbSDimitry Andric       if (RT->getDecl()->isUnion()) {
670*700637cbSDimitry Andric         const FieldDecl *ActiveField = nullptr;
671*700637cbSDimitry Andric         APValue Value;
672*700637cbSDimitry Andric         for (const auto &F : Record->fields()) {
673*700637cbSDimitry Andric           const Pointer &FP = Ptr.atField(F.Offset);
674*700637cbSDimitry Andric           QualType FieldTy = F.Decl->getType();
675*700637cbSDimitry Andric           if (FP.isActive()) {
676*700637cbSDimitry Andric             if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
677*700637cbSDimitry Andric               TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
678*700637cbSDimitry Andric             } else {
679*700637cbSDimitry Andric               Ok &= Composite(FieldTy, FP, Value);
680*700637cbSDimitry Andric             }
681*700637cbSDimitry Andric             ActiveField = FP.getFieldDesc()->asFieldDecl();
682*700637cbSDimitry Andric             break;
683*700637cbSDimitry Andric           }
684*700637cbSDimitry Andric         }
685*700637cbSDimitry Andric         R = APValue(ActiveField, Value);
686*700637cbSDimitry Andric       } else {
687*700637cbSDimitry Andric         unsigned NF = Record->getNumFields();
688*700637cbSDimitry Andric         unsigned NB = Record->getNumBases();
689*700637cbSDimitry Andric         unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
690*700637cbSDimitry Andric 
691*700637cbSDimitry Andric         R = APValue(APValue::UninitStruct(), NB, NF);
692*700637cbSDimitry Andric 
693*700637cbSDimitry Andric         for (unsigned I = 0; I < NF; ++I) {
694*700637cbSDimitry Andric           const Record::Field *FD = Record->getField(I);
695*700637cbSDimitry Andric           QualType FieldTy = FD->Decl->getType();
696*700637cbSDimitry Andric           const Pointer &FP = Ptr.atField(FD->Offset);
697*700637cbSDimitry Andric           APValue &Value = R.getStructField(I);
698*700637cbSDimitry Andric 
699*700637cbSDimitry Andric           if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
700*700637cbSDimitry Andric             TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
701*700637cbSDimitry Andric           } else {
702*700637cbSDimitry Andric             Ok &= Composite(FieldTy, FP, Value);
703*700637cbSDimitry Andric           }
704*700637cbSDimitry Andric         }
705*700637cbSDimitry Andric 
706*700637cbSDimitry Andric         for (unsigned I = 0; I < NB; ++I) {
707*700637cbSDimitry Andric           const Record::Base *BD = Record->getBase(I);
708*700637cbSDimitry Andric           QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
709*700637cbSDimitry Andric           const Pointer &BP = Ptr.atField(BD->Offset);
710*700637cbSDimitry Andric           Ok &= Composite(BaseTy, BP, R.getStructBase(I));
711*700637cbSDimitry Andric         }
712*700637cbSDimitry Andric 
713*700637cbSDimitry Andric         for (unsigned I = 0; I < NV; ++I) {
714*700637cbSDimitry Andric           const Record::Base *VD = Record->getVirtualBase(I);
715*700637cbSDimitry Andric           QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
716*700637cbSDimitry Andric           const Pointer &VP = Ptr.atField(VD->Offset);
717*700637cbSDimitry Andric           Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
718*700637cbSDimitry Andric         }
719*700637cbSDimitry Andric       }
720*700637cbSDimitry Andric       return Ok;
721*700637cbSDimitry Andric     }
722*700637cbSDimitry Andric 
723*700637cbSDimitry Andric     if (Ty->isIncompleteArrayType()) {
724*700637cbSDimitry Andric       R = APValue(APValue::UninitArray(), 0, 0);
725*700637cbSDimitry Andric       return true;
726*700637cbSDimitry Andric     }
727*700637cbSDimitry Andric 
728*700637cbSDimitry Andric     if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
729*700637cbSDimitry Andric       const size_t NumElems = Ptr.getNumElems();
730*700637cbSDimitry Andric       QualType ElemTy = AT->getElementType();
731*700637cbSDimitry Andric       R = APValue(APValue::UninitArray{}, NumElems, NumElems);
732*700637cbSDimitry Andric 
733*700637cbSDimitry Andric       bool Ok = true;
734*700637cbSDimitry Andric       for (unsigned I = 0; I < NumElems; ++I) {
735*700637cbSDimitry Andric         APValue &Slot = R.getArrayInitializedElt(I);
736*700637cbSDimitry Andric         const Pointer &EP = Ptr.atIndex(I);
737*700637cbSDimitry Andric         if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
738*700637cbSDimitry Andric           TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
739*700637cbSDimitry Andric         } else {
740*700637cbSDimitry Andric           Ok &= Composite(ElemTy, EP.narrow(), Slot);
741*700637cbSDimitry Andric         }
742*700637cbSDimitry Andric       }
743*700637cbSDimitry Andric       return Ok;
744*700637cbSDimitry Andric     }
745*700637cbSDimitry Andric 
746*700637cbSDimitry Andric     // Complex types.
747*700637cbSDimitry Andric     if (const auto *CT = Ty->getAs<ComplexType>()) {
748*700637cbSDimitry Andric       QualType ElemTy = CT->getElementType();
749*700637cbSDimitry Andric 
750*700637cbSDimitry Andric       if (ElemTy->isIntegerType()) {
751*700637cbSDimitry Andric         std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
752*700637cbSDimitry Andric         assert(ElemT);
753*700637cbSDimitry Andric         INT_TYPE_SWITCH(*ElemT, {
754*700637cbSDimitry Andric           auto V1 = Ptr.atIndex(0).deref<T>();
755*700637cbSDimitry Andric           auto V2 = Ptr.atIndex(1).deref<T>();
756*700637cbSDimitry Andric           R = APValue(V1.toAPSInt(), V2.toAPSInt());
757*700637cbSDimitry Andric           return true;
758*700637cbSDimitry Andric         });
759*700637cbSDimitry Andric       } else if (ElemTy->isFloatingType()) {
760*700637cbSDimitry Andric         R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
761*700637cbSDimitry Andric                     Ptr.atIndex(1).deref<Floating>().getAPFloat());
762*700637cbSDimitry Andric         return true;
763*700637cbSDimitry Andric       }
764*700637cbSDimitry Andric       return false;
765*700637cbSDimitry Andric     }
766*700637cbSDimitry Andric 
767*700637cbSDimitry Andric     // Vector types.
768*700637cbSDimitry Andric     if (const auto *VT = Ty->getAs<VectorType>()) {
769*700637cbSDimitry Andric       assert(Ptr.getFieldDesc()->isPrimitiveArray());
770*700637cbSDimitry Andric       QualType ElemTy = VT->getElementType();
771*700637cbSDimitry Andric       PrimType ElemT = *Ctx.classify(ElemTy);
772*700637cbSDimitry Andric 
773*700637cbSDimitry Andric       SmallVector<APValue> Values;
774*700637cbSDimitry Andric       Values.reserve(VT->getNumElements());
775*700637cbSDimitry Andric       for (unsigned I = 0; I != VT->getNumElements(); ++I) {
776*700637cbSDimitry Andric         TYPE_SWITCH(ElemT, {
777*700637cbSDimitry Andric           Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
778*700637cbSDimitry Andric         });
779*700637cbSDimitry Andric       }
780*700637cbSDimitry Andric 
781*700637cbSDimitry Andric       assert(Values.size() == VT->getNumElements());
782*700637cbSDimitry Andric       R = APValue(Values.data(), Values.size());
783*700637cbSDimitry Andric       return true;
784*700637cbSDimitry Andric     }
785*700637cbSDimitry Andric 
786*700637cbSDimitry Andric     llvm_unreachable("invalid value to return");
787*700637cbSDimitry Andric   };
788*700637cbSDimitry Andric 
789*700637cbSDimitry Andric   // Invalid to read from.
790*700637cbSDimitry Andric   if (isDummy() || !isLive() || isPastEnd())
791*700637cbSDimitry Andric     return std::nullopt;
792*700637cbSDimitry Andric 
793*700637cbSDimitry Andric   // We can return these as rvalues, but we can't deref() them.
794*700637cbSDimitry Andric   if (isZero() || isIntegralPointer())
795*700637cbSDimitry Andric     return toAPValue(ASTCtx);
796*700637cbSDimitry Andric 
797*700637cbSDimitry Andric   // Just load primitive types.
798*700637cbSDimitry Andric   if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
799*700637cbSDimitry Andric     TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
800*700637cbSDimitry Andric   }
801*700637cbSDimitry Andric 
802*700637cbSDimitry Andric   // Return the composite type.
803*700637cbSDimitry Andric   APValue Result;
804*700637cbSDimitry Andric   if (!Composite(ResultType, *this, Result))
805*700637cbSDimitry Andric     return std::nullopt;
806*700637cbSDimitry Andric   return Result;
807*700637cbSDimitry Andric }
808*700637cbSDimitry Andric 
atOffset(const ASTContext & ASTCtx,unsigned Offset) const809*700637cbSDimitry Andric IntPointer IntPointer::atOffset(const ASTContext &ASTCtx,
810*700637cbSDimitry Andric                                 unsigned Offset) const {
811*700637cbSDimitry Andric   if (!this->Desc)
812*700637cbSDimitry Andric     return *this;
813*700637cbSDimitry Andric   const Record *R = this->Desc->ElemRecord;
814*700637cbSDimitry Andric   if (!R)
815*700637cbSDimitry Andric     return *this;
816*700637cbSDimitry Andric 
817*700637cbSDimitry Andric   const Record::Field *F = nullptr;
818*700637cbSDimitry Andric   for (auto &It : R->fields()) {
819*700637cbSDimitry Andric     if (It.Offset == Offset) {
820*700637cbSDimitry Andric       F = &It;
821*700637cbSDimitry Andric       break;
822*700637cbSDimitry Andric     }
823*700637cbSDimitry Andric   }
824*700637cbSDimitry Andric   if (!F)
825*700637cbSDimitry Andric     return *this;
826*700637cbSDimitry Andric 
827*700637cbSDimitry Andric   const FieldDecl *FD = F->Decl;
828*700637cbSDimitry Andric   const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
829*700637cbSDimitry Andric   unsigned FieldIndex = FD->getFieldIndex();
830*700637cbSDimitry Andric   uint64_t FieldOffset =
831*700637cbSDimitry Andric       ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
832*700637cbSDimitry Andric           .getQuantity();
833*700637cbSDimitry Andric   return IntPointer{F->Desc, this->Value + FieldOffset};
834*700637cbSDimitry Andric }
835*700637cbSDimitry Andric 
baseCast(const ASTContext & ASTCtx,unsigned BaseOffset) const836*700637cbSDimitry Andric IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
837*700637cbSDimitry Andric                                 unsigned BaseOffset) const {
838*700637cbSDimitry Andric   if (!Desc) {
839*700637cbSDimitry Andric     assert(Value == 0);
840*700637cbSDimitry Andric     return *this;
841*700637cbSDimitry Andric   }
842*700637cbSDimitry Andric   const Record *R = Desc->ElemRecord;
843*700637cbSDimitry Andric   const Descriptor *BaseDesc = nullptr;
844*700637cbSDimitry Andric 
845*700637cbSDimitry Andric   // This iterates over bases and checks for the proper offset. That's
846*700637cbSDimitry Andric   // potentially slow but this case really shouldn't happen a lot.
847*700637cbSDimitry Andric   for (const Record::Base &B : R->bases()) {
848*700637cbSDimitry Andric     if (B.Offset == BaseOffset) {
849*700637cbSDimitry Andric       BaseDesc = B.Desc;
850*700637cbSDimitry Andric       break;
851*700637cbSDimitry Andric     }
852*700637cbSDimitry Andric   }
853*700637cbSDimitry Andric   assert(BaseDesc);
854*700637cbSDimitry Andric 
855*700637cbSDimitry Andric   // Adjust the offset value based on the information from the record layout.
856*700637cbSDimitry Andric   const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
857*700637cbSDimitry Andric   CharUnits BaseLayoutOffset =
858*700637cbSDimitry Andric       Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
859*700637cbSDimitry Andric 
860*700637cbSDimitry Andric   return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
861*700637cbSDimitry Andric }
862