xref: /llvm-project/clang/lib/AST/ByteCode/Pointer.cpp (revision 51c7338cc671c90ba9345b53c7ca01dc461341ed)
1a07aba5dSTimm Baeder //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder 
9a07aba5dSTimm Baeder #include "Pointer.h"
10a07aba5dSTimm Baeder #include "Boolean.h"
11a07aba5dSTimm Baeder #include "Context.h"
12a07aba5dSTimm Baeder #include "Floating.h"
13a07aba5dSTimm Baeder #include "Function.h"
14a07aba5dSTimm Baeder #include "Integral.h"
15a07aba5dSTimm Baeder #include "InterpBlock.h"
16a07aba5dSTimm Baeder #include "MemberPointer.h"
17a07aba5dSTimm Baeder #include "PrimType.h"
18a07aba5dSTimm Baeder #include "Record.h"
19a07aba5dSTimm Baeder #include "clang/AST/ExprCXX.h"
20a07aba5dSTimm Baeder #include "clang/AST/RecordLayout.h"
21a07aba5dSTimm Baeder 
22a07aba5dSTimm Baeder using namespace clang;
23a07aba5dSTimm Baeder using namespace clang::interp;
24a07aba5dSTimm Baeder 
25a07aba5dSTimm Baeder Pointer::Pointer(Block *Pointee)
26a07aba5dSTimm Baeder     : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
27a07aba5dSTimm Baeder               Pointee->getDescriptor()->getMetadataSize()) {}
28a07aba5dSTimm Baeder 
29a07aba5dSTimm Baeder Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
30a07aba5dSTimm Baeder     : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
31a07aba5dSTimm Baeder 
32a07aba5dSTimm Baeder Pointer::Pointer(const Pointer &P)
33a07aba5dSTimm Baeder     : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
34a07aba5dSTimm Baeder       StorageKind(P.StorageKind) {
35a07aba5dSTimm Baeder 
36a07aba5dSTimm Baeder   if (isBlockPointer() && PointeeStorage.BS.Pointee)
37a07aba5dSTimm Baeder     PointeeStorage.BS.Pointee->addPointer(this);
38a07aba5dSTimm Baeder }
39a07aba5dSTimm Baeder 
40a07aba5dSTimm Baeder Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
41a07aba5dSTimm Baeder     : Offset(Offset), StorageKind(Storage::Block) {
42a07aba5dSTimm Baeder   assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
43a07aba5dSTimm Baeder 
44a07aba5dSTimm Baeder   PointeeStorage.BS = {Pointee, Base};
45a07aba5dSTimm Baeder 
46a07aba5dSTimm Baeder   if (Pointee)
47a07aba5dSTimm Baeder     Pointee->addPointer(this);
48a07aba5dSTimm Baeder }
49a07aba5dSTimm Baeder 
50a07aba5dSTimm Baeder Pointer::Pointer(Pointer &&P)
51a07aba5dSTimm Baeder     : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
52a07aba5dSTimm Baeder       StorageKind(P.StorageKind) {
53a07aba5dSTimm Baeder 
54a07aba5dSTimm Baeder   if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
55a07aba5dSTimm Baeder     PointeeStorage.BS.Pointee->replacePointer(&P, this);
56a07aba5dSTimm Baeder }
57a07aba5dSTimm Baeder 
58a07aba5dSTimm Baeder Pointer::~Pointer() {
59a07aba5dSTimm Baeder   if (!isBlockPointer())
60a07aba5dSTimm Baeder     return;
61a07aba5dSTimm Baeder 
62a07aba5dSTimm Baeder   if (Block *Pointee = PointeeStorage.BS.Pointee) {
63a07aba5dSTimm Baeder     Pointee->removePointer(this);
64a07aba5dSTimm Baeder     PointeeStorage.BS.Pointee = nullptr;
65a07aba5dSTimm Baeder     Pointee->cleanup();
66a07aba5dSTimm Baeder   }
67a07aba5dSTimm Baeder }
68a07aba5dSTimm Baeder 
69a07aba5dSTimm Baeder void Pointer::operator=(const Pointer &P) {
70a07aba5dSTimm Baeder   // If the current storage type is Block, we need to remove
71a07aba5dSTimm Baeder   // this pointer from the block.
72a07aba5dSTimm Baeder   if (isBlockPointer()) {
73a07aba5dSTimm Baeder     if (P.isBlockPointer() && this->block() == P.block()) {
74a07aba5dSTimm Baeder       Offset = P.Offset;
75a07aba5dSTimm Baeder       PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
76a07aba5dSTimm Baeder       return;
77a07aba5dSTimm Baeder     }
78a07aba5dSTimm Baeder 
79a07aba5dSTimm Baeder     if (Block *Pointee = PointeeStorage.BS.Pointee) {
80a07aba5dSTimm Baeder       Pointee->removePointer(this);
81a07aba5dSTimm Baeder       PointeeStorage.BS.Pointee = nullptr;
82a07aba5dSTimm Baeder       Pointee->cleanup();
83a07aba5dSTimm Baeder     }
84a07aba5dSTimm Baeder   }
85a07aba5dSTimm Baeder 
86a07aba5dSTimm Baeder   StorageKind = P.StorageKind;
87a07aba5dSTimm Baeder   Offset = P.Offset;
88a07aba5dSTimm Baeder 
89a07aba5dSTimm Baeder   if (P.isBlockPointer()) {
90a07aba5dSTimm Baeder     PointeeStorage.BS = P.PointeeStorage.BS;
91a07aba5dSTimm Baeder     PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
92a07aba5dSTimm Baeder 
93a07aba5dSTimm Baeder     if (PointeeStorage.BS.Pointee)
94a07aba5dSTimm Baeder       PointeeStorage.BS.Pointee->addPointer(this);
95a07aba5dSTimm Baeder   } else if (P.isIntegralPointer()) {
96a07aba5dSTimm Baeder     PointeeStorage.Int = P.PointeeStorage.Int;
97a07aba5dSTimm Baeder   } else if (P.isFunctionPointer()) {
98a07aba5dSTimm Baeder     PointeeStorage.Fn = P.PointeeStorage.Fn;
99e86b68ffSTimm Baeder   } else if (P.isTypeidPointer()) {
100e86b68ffSTimm Baeder     PointeeStorage.Typeid = P.PointeeStorage.Typeid;
101a07aba5dSTimm Baeder   } else {
102a07aba5dSTimm Baeder     assert(false && "Unhandled storage kind");
103a07aba5dSTimm Baeder   }
104a07aba5dSTimm Baeder }
105a07aba5dSTimm Baeder 
106a07aba5dSTimm Baeder void Pointer::operator=(Pointer &&P) {
107a07aba5dSTimm Baeder   // If the current storage type is Block, we need to remove
108a07aba5dSTimm Baeder   // this pointer from the block.
109a07aba5dSTimm Baeder   if (isBlockPointer()) {
110a07aba5dSTimm Baeder     if (P.isBlockPointer() && this->block() == P.block()) {
111a07aba5dSTimm Baeder       Offset = P.Offset;
112a07aba5dSTimm Baeder       PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
113a07aba5dSTimm Baeder       return;
114a07aba5dSTimm Baeder     }
115a07aba5dSTimm Baeder 
116a07aba5dSTimm Baeder     if (Block *Pointee = PointeeStorage.BS.Pointee) {
117a07aba5dSTimm Baeder       assert(P.block() != this->block());
118a07aba5dSTimm Baeder       Pointee->removePointer(this);
119a07aba5dSTimm Baeder       PointeeStorage.BS.Pointee = nullptr;
120a07aba5dSTimm Baeder       Pointee->cleanup();
121a07aba5dSTimm Baeder     }
122a07aba5dSTimm Baeder   }
123a07aba5dSTimm Baeder 
124a07aba5dSTimm Baeder   StorageKind = P.StorageKind;
125a07aba5dSTimm Baeder   Offset = P.Offset;
126a07aba5dSTimm Baeder 
127a07aba5dSTimm Baeder   if (P.isBlockPointer()) {
128a07aba5dSTimm Baeder     PointeeStorage.BS = P.PointeeStorage.BS;
129a07aba5dSTimm Baeder     PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
130a07aba5dSTimm Baeder 
131a07aba5dSTimm Baeder     if (PointeeStorage.BS.Pointee)
132a07aba5dSTimm Baeder       PointeeStorage.BS.Pointee->addPointer(this);
133a07aba5dSTimm Baeder   } else if (P.isIntegralPointer()) {
134a07aba5dSTimm Baeder     PointeeStorage.Int = P.PointeeStorage.Int;
135a07aba5dSTimm Baeder   } else if (P.isFunctionPointer()) {
136a07aba5dSTimm Baeder     PointeeStorage.Fn = P.PointeeStorage.Fn;
137e86b68ffSTimm Baeder   } else if (P.isTypeidPointer()) {
138e86b68ffSTimm Baeder     PointeeStorage.Typeid = P.PointeeStorage.Typeid;
139a07aba5dSTimm Baeder   } else {
140a07aba5dSTimm Baeder     assert(false && "Unhandled storage kind");
141a07aba5dSTimm Baeder   }
142a07aba5dSTimm Baeder }
143a07aba5dSTimm Baeder 
144a07aba5dSTimm Baeder APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
145a07aba5dSTimm Baeder   llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
146a07aba5dSTimm Baeder 
147a07aba5dSTimm Baeder   if (isZero())
148a07aba5dSTimm Baeder     return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
149a07aba5dSTimm Baeder                    /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
150a07aba5dSTimm Baeder   if (isIntegralPointer())
151a07aba5dSTimm Baeder     return APValue(static_cast<const Expr *>(nullptr),
152a07aba5dSTimm Baeder                    CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
153a07aba5dSTimm Baeder                    Path,
154a07aba5dSTimm Baeder                    /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
155a07aba5dSTimm Baeder   if (isFunctionPointer())
156a07aba5dSTimm Baeder     return asFunctionPointer().toAPValue(ASTCtx);
157a07aba5dSTimm Baeder 
158e86b68ffSTimm Baeder   if (isTypeidPointer()) {
159e86b68ffSTimm Baeder     TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr);
160e86b68ffSTimm Baeder     return APValue(
161e86b68ffSTimm Baeder         APValue::LValueBase::getTypeInfo(
162e86b68ffSTimm Baeder             TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)),
163e86b68ffSTimm Baeder         CharUnits::Zero(), APValue::NoLValuePath{});
164e86b68ffSTimm Baeder   }
165e86b68ffSTimm Baeder 
166a07aba5dSTimm Baeder   // Build the lvalue base from the block.
167a07aba5dSTimm Baeder   const Descriptor *Desc = getDeclDesc();
168a07aba5dSTimm Baeder   APValue::LValueBase Base;
169a07aba5dSTimm Baeder   if (const auto *VD = Desc->asValueDecl())
170a07aba5dSTimm Baeder     Base = VD;
171a07aba5dSTimm Baeder   else if (const auto *E = Desc->asExpr()) {
172a07aba5dSTimm Baeder     // Create a DynamicAlloc base of the right type.
173a07aba5dSTimm Baeder     if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
174a07aba5dSTimm Baeder       QualType AllocatedType;
175a07aba5dSTimm Baeder       if (NewExpr->isArray()) {
176a07aba5dSTimm Baeder         assert(Desc->isArray());
177a07aba5dSTimm Baeder         APInt ArraySize(64, static_cast<uint64_t>(Desc->getNumElems()),
178a07aba5dSTimm Baeder                         /*IsSigned=*/false);
179a07aba5dSTimm Baeder         AllocatedType =
180a07aba5dSTimm Baeder             ASTCtx.getConstantArrayType(NewExpr->getAllocatedType(), ArraySize,
181a07aba5dSTimm Baeder                                         nullptr, ArraySizeModifier::Normal, 0);
182a07aba5dSTimm Baeder       } else {
183a07aba5dSTimm Baeder         AllocatedType = NewExpr->getAllocatedType();
184a07aba5dSTimm Baeder       }
185a07aba5dSTimm Baeder       // FIXME: Suboptimal counting of dynamic allocations. Move this to Context
186a07aba5dSTimm Baeder       // or InterpState?
187a07aba5dSTimm Baeder       static int ReportedDynamicAllocs = 0;
188a07aba5dSTimm Baeder       DynamicAllocLValue DA(ReportedDynamicAllocs++);
189a07aba5dSTimm Baeder       Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
190a07aba5dSTimm Baeder     } else {
191a07aba5dSTimm Baeder       Base = E;
192a07aba5dSTimm Baeder     }
193a07aba5dSTimm Baeder   } else
194a07aba5dSTimm Baeder     llvm_unreachable("Invalid allocation type");
195a07aba5dSTimm Baeder 
196a07aba5dSTimm Baeder   if (isUnknownSizeArray())
197a07aba5dSTimm Baeder     return APValue(Base, CharUnits::Zero(), Path,
198a07aba5dSTimm Baeder                    /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
199a07aba5dSTimm Baeder 
200a07aba5dSTimm Baeder   CharUnits Offset = CharUnits::Zero();
201a07aba5dSTimm Baeder 
202a07aba5dSTimm Baeder   auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
203a07aba5dSTimm Baeder     // This shouldn't happen, but if it does, don't crash inside
204a07aba5dSTimm Baeder     // getASTRecordLayout.
205a07aba5dSTimm Baeder     if (FD->getParent()->isInvalidDecl())
206a07aba5dSTimm Baeder       return CharUnits::Zero();
207a07aba5dSTimm Baeder     const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
208a07aba5dSTimm Baeder     unsigned FieldIndex = FD->getFieldIndex();
209a07aba5dSTimm Baeder     return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
210a07aba5dSTimm Baeder   };
211a07aba5dSTimm Baeder 
212*51c7338cSTimm Baeder   bool UsePath = true;
213*51c7338cSTimm Baeder   if (getType()->isLValueReferenceType())
214*51c7338cSTimm Baeder     UsePath = false;
215*51c7338cSTimm Baeder 
216a07aba5dSTimm Baeder   // Build the path into the object.
217a07aba5dSTimm Baeder   Pointer Ptr = *this;
218a07aba5dSTimm Baeder   while (Ptr.isField() || Ptr.isArrayElement()) {
2192c820799STimm Baeder 
220a07aba5dSTimm Baeder     if (Ptr.isArrayRoot()) {
2212c820799STimm Baeder       // An array root may still be an array element itself.
2222c820799STimm Baeder       if (Ptr.isArrayElement()) {
2232c820799STimm Baeder         Ptr = Ptr.expand();
224*51c7338cSTimm Baeder         const Descriptor *Desc = Ptr.getFieldDesc();
2252c820799STimm Baeder         unsigned Index = Ptr.getIndex();
226*51c7338cSTimm Baeder         QualType ElemType = Desc->getElemQualType();
2272c820799STimm Baeder         Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
228*51c7338cSTimm Baeder         if (Ptr.getArray().getType()->isArrayType())
229*51c7338cSTimm Baeder           Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
2302c820799STimm Baeder         Ptr = Ptr.getArray();
2312c820799STimm Baeder       } else {
232*51c7338cSTimm Baeder         const Descriptor *Desc = Ptr.getFieldDesc();
233*51c7338cSTimm Baeder         const auto *Dcl = Desc->asDecl();
234*51c7338cSTimm Baeder         Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
235a07aba5dSTimm Baeder 
236*51c7338cSTimm Baeder         if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl))
237a07aba5dSTimm Baeder           Offset += getFieldOffset(FD);
238a07aba5dSTimm Baeder 
239a07aba5dSTimm Baeder         Ptr = Ptr.getBase();
2402c820799STimm Baeder       }
241a07aba5dSTimm Baeder     } else if (Ptr.isArrayElement()) {
242800b0739STimm Baeder       Ptr = Ptr.expand();
243*51c7338cSTimm Baeder       const Descriptor *Desc = Ptr.getFieldDesc();
244a07aba5dSTimm Baeder       unsigned Index;
245a07aba5dSTimm Baeder       if (Ptr.isOnePastEnd())
246a07aba5dSTimm Baeder         Index = Ptr.getArray().getNumElems();
247a07aba5dSTimm Baeder       else
248a07aba5dSTimm Baeder         Index = Ptr.getIndex();
249a07aba5dSTimm Baeder 
250*51c7338cSTimm Baeder       QualType ElemType = Desc->getElemQualType();
251800b0739STimm Baeder       Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
252*51c7338cSTimm Baeder       if (Ptr.getArray().getType()->isArrayType())
253a07aba5dSTimm Baeder         Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
254a07aba5dSTimm Baeder       Ptr = Ptr.getArray();
255a07aba5dSTimm Baeder     } else {
256*51c7338cSTimm Baeder       const Descriptor *Desc = Ptr.getFieldDesc();
257a07aba5dSTimm Baeder       bool IsVirtual = false;
258a07aba5dSTimm Baeder 
259a07aba5dSTimm Baeder       // Create a path entry for the field.
260a07aba5dSTimm Baeder       if (const auto *BaseOrMember = Desc->asDecl()) {
261a07aba5dSTimm Baeder         if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
262a07aba5dSTimm Baeder           Ptr = Ptr.getBase();
263a07aba5dSTimm Baeder           Offset += getFieldOffset(FD);
264a07aba5dSTimm Baeder         } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
265a07aba5dSTimm Baeder           IsVirtual = Ptr.isVirtualBaseClass();
266a07aba5dSTimm Baeder           Ptr = Ptr.getBase();
267a07aba5dSTimm Baeder           const Record *BaseRecord = Ptr.getRecord();
268a07aba5dSTimm Baeder 
269a07aba5dSTimm Baeder           const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
270a07aba5dSTimm Baeder               cast<CXXRecordDecl>(BaseRecord->getDecl()));
271a07aba5dSTimm Baeder           if (IsVirtual)
272a07aba5dSTimm Baeder             Offset += Layout.getVBaseClassOffset(RD);
273a07aba5dSTimm Baeder           else
274a07aba5dSTimm Baeder             Offset += Layout.getBaseClassOffset(RD);
275a07aba5dSTimm Baeder 
276a07aba5dSTimm Baeder         } else {
277a07aba5dSTimm Baeder           Ptr = Ptr.getBase();
278a07aba5dSTimm Baeder         }
279a07aba5dSTimm Baeder         Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
280a07aba5dSTimm Baeder         continue;
281a07aba5dSTimm Baeder       }
282a07aba5dSTimm Baeder       llvm_unreachable("Invalid field type");
283a07aba5dSTimm Baeder     }
284a07aba5dSTimm Baeder   }
285a07aba5dSTimm Baeder 
286a07aba5dSTimm Baeder   // We assemble the LValuePath starting from the innermost pointer to the
287a07aba5dSTimm Baeder   // outermost one. SO in a.b.c, the first element in Path will refer to
288a07aba5dSTimm Baeder   // the field 'c', while later code expects it to refer to 'a'.
289a07aba5dSTimm Baeder   // Just invert the order of the elements.
290a07aba5dSTimm Baeder   std::reverse(Path.begin(), Path.end());
291a07aba5dSTimm Baeder 
292*51c7338cSTimm Baeder   if (UsePath)
293*51c7338cSTimm Baeder     return APValue(Base, Offset, Path,
294*51c7338cSTimm Baeder                    /*IsOnePastEnd=*/!isElementPastEnd() && isOnePastEnd());
295*51c7338cSTimm Baeder 
296*51c7338cSTimm Baeder   return APValue(Base, Offset, APValue::NoLValuePath());
297a07aba5dSTimm Baeder }
298a07aba5dSTimm Baeder 
299a07aba5dSTimm Baeder void Pointer::print(llvm::raw_ostream &OS) const {
30007bd3bb9STimm Bäder   switch (StorageKind) {
30107bd3bb9STimm Bäder   case Storage::Block: {
302a07aba5dSTimm Baeder     const Block *B = PointeeStorage.BS.Pointee;
30307bd3bb9STimm Bäder     OS << "(Block) " << B << " {";
304a07aba5dSTimm Baeder 
305a07aba5dSTimm Baeder     if (isRoot())
306a07aba5dSTimm Baeder       OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
307a07aba5dSTimm Baeder     else
308a07aba5dSTimm Baeder       OS << PointeeStorage.BS.Base << ", ";
309a07aba5dSTimm Baeder 
310a07aba5dSTimm Baeder     if (isElementPastEnd())
311a07aba5dSTimm Baeder       OS << "pastend, ";
312a07aba5dSTimm Baeder     else
313a07aba5dSTimm Baeder       OS << Offset << ", ";
314a07aba5dSTimm Baeder 
315a07aba5dSTimm Baeder     if (B)
316a07aba5dSTimm Baeder       OS << B->getSize();
317a07aba5dSTimm Baeder     else
318a07aba5dSTimm Baeder       OS << "nullptr";
319a07aba5dSTimm Baeder     OS << "}";
32007bd3bb9STimm Bäder   } break;
32107bd3bb9STimm Bäder   case Storage::Int:
32207bd3bb9STimm Bäder     OS << "(Int) {";
32307bd3bb9STimm Bäder     OS << PointeeStorage.Int.Value << " + " << Offset << ", "
32407bd3bb9STimm Bäder        << PointeeStorage.Int.Desc;
32507bd3bb9STimm Bäder     OS << "}";
32607bd3bb9STimm Bäder     break;
32707bd3bb9STimm Bäder   case Storage::Fn:
32807bd3bb9STimm Bäder     OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
32907bd3bb9STimm Bäder        << " }";
3303496e96fSTimm Bäder     break;
331e86b68ffSTimm Baeder   case Storage::Typeid:
332e86b68ffSTimm Baeder     OS << "(Typeid)";
33307bd3bb9STimm Bäder   }
334a07aba5dSTimm Baeder }
335a07aba5dSTimm Baeder 
336a07aba5dSTimm Baeder std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
337a07aba5dSTimm Baeder   if (isZero())
338a07aba5dSTimm Baeder     return "nullptr";
339a07aba5dSTimm Baeder 
340a07aba5dSTimm Baeder   if (isIntegralPointer())
341a07aba5dSTimm Baeder     return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
342a07aba5dSTimm Baeder 
343a07aba5dSTimm Baeder   return toAPValue(Ctx).getAsString(Ctx, getType());
344a07aba5dSTimm Baeder }
345a07aba5dSTimm Baeder 
346a07aba5dSTimm Baeder bool Pointer::isInitialized() const {
347a07aba5dSTimm Baeder   if (!isBlockPointer())
348a07aba5dSTimm Baeder     return true;
349a07aba5dSTimm Baeder 
350a07aba5dSTimm Baeder   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
351a07aba5dSTimm Baeder     const GlobalInlineDescriptor &GD =
352a07aba5dSTimm Baeder         *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
353a07aba5dSTimm Baeder     return GD.InitState == GlobalInitState::Initialized;
354a07aba5dSTimm Baeder   }
355a07aba5dSTimm Baeder 
356a07aba5dSTimm Baeder   assert(PointeeStorage.BS.Pointee &&
357a07aba5dSTimm Baeder          "Cannot check if null pointer was initialized");
358a07aba5dSTimm Baeder   const Descriptor *Desc = getFieldDesc();
359a07aba5dSTimm Baeder   assert(Desc);
360a07aba5dSTimm Baeder   if (Desc->isPrimitiveArray()) {
361a07aba5dSTimm Baeder     if (isStatic() && PointeeStorage.BS.Base == 0)
362a07aba5dSTimm Baeder       return true;
363a07aba5dSTimm Baeder 
364a07aba5dSTimm Baeder     InitMapPtr &IM = getInitMap();
365a07aba5dSTimm Baeder 
366a07aba5dSTimm Baeder     if (!IM)
367a07aba5dSTimm Baeder       return false;
368a07aba5dSTimm Baeder 
369a07aba5dSTimm Baeder     if (IM->first)
370a07aba5dSTimm Baeder       return true;
371a07aba5dSTimm Baeder 
372a07aba5dSTimm Baeder     return IM->second->isElementInitialized(getIndex());
373a07aba5dSTimm Baeder   }
374a07aba5dSTimm Baeder 
375a07aba5dSTimm Baeder   if (asBlockPointer().Base == 0)
376a07aba5dSTimm Baeder     return true;
377a07aba5dSTimm Baeder 
378a07aba5dSTimm Baeder   // Field has its bit in an inline descriptor.
379a07aba5dSTimm Baeder   return getInlineDesc()->IsInitialized;
380a07aba5dSTimm Baeder }
381a07aba5dSTimm Baeder 
382a07aba5dSTimm Baeder void Pointer::initialize() const {
383a07aba5dSTimm Baeder   if (!isBlockPointer())
384a07aba5dSTimm Baeder     return;
385a07aba5dSTimm Baeder 
386a07aba5dSTimm Baeder   assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
387a07aba5dSTimm Baeder   const Descriptor *Desc = getFieldDesc();
388a07aba5dSTimm Baeder 
389a07aba5dSTimm Baeder   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
390a07aba5dSTimm Baeder     GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
391a07aba5dSTimm Baeder         asBlockPointer().Pointee->rawData());
392a07aba5dSTimm Baeder     GD.InitState = GlobalInitState::Initialized;
393a07aba5dSTimm Baeder     return;
394a07aba5dSTimm Baeder   }
395a07aba5dSTimm Baeder 
396a07aba5dSTimm Baeder   assert(Desc);
397a07aba5dSTimm Baeder   if (Desc->isPrimitiveArray()) {
398a07aba5dSTimm Baeder     // Primitive global arrays don't have an initmap.
399a07aba5dSTimm Baeder     if (isStatic() && PointeeStorage.BS.Base == 0)
400a07aba5dSTimm Baeder       return;
401a07aba5dSTimm Baeder 
402a07aba5dSTimm Baeder     // Nothing to do for these.
403a07aba5dSTimm Baeder     if (Desc->getNumElems() == 0)
404a07aba5dSTimm Baeder       return;
405a07aba5dSTimm Baeder 
406a07aba5dSTimm Baeder     InitMapPtr &IM = getInitMap();
407a07aba5dSTimm Baeder     if (!IM)
408a07aba5dSTimm Baeder       IM =
409a07aba5dSTimm Baeder           std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
410a07aba5dSTimm Baeder 
411a07aba5dSTimm Baeder     assert(IM);
412a07aba5dSTimm Baeder 
413a07aba5dSTimm Baeder     // All initialized.
414a07aba5dSTimm Baeder     if (IM->first)
415a07aba5dSTimm Baeder       return;
416a07aba5dSTimm Baeder 
417a07aba5dSTimm Baeder     if (IM->second->initializeElement(getIndex())) {
418a07aba5dSTimm Baeder       IM->first = true;
419a07aba5dSTimm Baeder       IM->second.reset();
420a07aba5dSTimm Baeder     }
421a07aba5dSTimm Baeder     return;
422a07aba5dSTimm Baeder   }
423a07aba5dSTimm Baeder 
424a07aba5dSTimm Baeder   // Field has its bit in an inline descriptor.
425a07aba5dSTimm Baeder   assert(PointeeStorage.BS.Base != 0 &&
426a07aba5dSTimm Baeder          "Only composite fields can be initialised");
427a07aba5dSTimm Baeder   getInlineDesc()->IsInitialized = true;
428a07aba5dSTimm Baeder }
429a07aba5dSTimm Baeder 
430a07aba5dSTimm Baeder void Pointer::activate() const {
431a07aba5dSTimm Baeder   // Field has its bit in an inline descriptor.
432a07aba5dSTimm Baeder   assert(PointeeStorage.BS.Base != 0 &&
433a07aba5dSTimm Baeder          "Only composite fields can be activated");
434a07aba5dSTimm Baeder 
435a07aba5dSTimm Baeder   if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
436a07aba5dSTimm Baeder     return;
437a07aba5dSTimm Baeder   if (!getInlineDesc()->InUnion)
438a07aba5dSTimm Baeder     return;
439a07aba5dSTimm Baeder 
440a07aba5dSTimm Baeder   getInlineDesc()->IsActive = true;
441a07aba5dSTimm Baeder 
442a07aba5dSTimm Baeder   // Get the union, iterate over its fields and DEactivate all others.
443a07aba5dSTimm Baeder   Pointer UnionPtr = getBase();
444a07aba5dSTimm Baeder   while (!UnionPtr.getFieldDesc()->isUnion())
445a07aba5dSTimm Baeder     UnionPtr = UnionPtr.getBase();
446a07aba5dSTimm Baeder 
447a07aba5dSTimm Baeder   const Record *UnionRecord = UnionPtr.getRecord();
448a07aba5dSTimm Baeder   for (const Record::Field &F : UnionRecord->fields()) {
449a07aba5dSTimm Baeder     Pointer FieldPtr = UnionPtr.atField(F.Offset);
450a07aba5dSTimm Baeder     if (FieldPtr == *this) {
451a07aba5dSTimm Baeder     } else {
452a07aba5dSTimm Baeder       FieldPtr.getInlineDesc()->IsActive = false;
453a07aba5dSTimm Baeder       // FIXME: Recurse.
454a07aba5dSTimm Baeder     }
455a07aba5dSTimm Baeder   }
456a07aba5dSTimm Baeder 
457a07aba5dSTimm Baeder   Pointer B = getBase();
458a07aba5dSTimm Baeder   while (!B.isRoot() && B.inUnion()) {
459a07aba5dSTimm Baeder     // FIXME: Need to de-activate other fields of parent records.
460a07aba5dSTimm Baeder     B.getInlineDesc()->IsActive = true;
461a07aba5dSTimm Baeder     assert(B.isActive());
462a07aba5dSTimm Baeder     B = B.getBase();
463a07aba5dSTimm Baeder   }
464a07aba5dSTimm Baeder }
465a07aba5dSTimm Baeder 
466a07aba5dSTimm Baeder void Pointer::deactivate() const {
467a07aba5dSTimm Baeder   // TODO: this only appears in constructors, so nothing to deactivate.
468a07aba5dSTimm Baeder }
469a07aba5dSTimm Baeder 
470a07aba5dSTimm Baeder bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
471a07aba5dSTimm Baeder   // Two null pointers always have the same base.
472a07aba5dSTimm Baeder   if (A.isZero() && B.isZero())
473a07aba5dSTimm Baeder     return true;
474a07aba5dSTimm Baeder 
475a07aba5dSTimm Baeder   if (A.isIntegralPointer() && B.isIntegralPointer())
476a07aba5dSTimm Baeder     return true;
477a07aba5dSTimm Baeder   if (A.isFunctionPointer() && B.isFunctionPointer())
478a07aba5dSTimm Baeder     return true;
479e86b68ffSTimm Baeder   if (A.isTypeidPointer() && B.isTypeidPointer())
480e86b68ffSTimm Baeder     return true;
481a07aba5dSTimm Baeder 
482a07aba5dSTimm Baeder   if (A.isIntegralPointer() || B.isIntegralPointer())
483a07aba5dSTimm Baeder     return A.getSource() == B.getSource();
484a07aba5dSTimm Baeder 
485a07aba5dSTimm Baeder   if (A.StorageKind != B.StorageKind)
486a07aba5dSTimm Baeder     return false;
487a07aba5dSTimm Baeder 
488a07aba5dSTimm Baeder   return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
489a07aba5dSTimm Baeder }
490a07aba5dSTimm Baeder 
491a07aba5dSTimm Baeder bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
492a07aba5dSTimm Baeder   if (!A.isBlockPointer() || !B.isBlockPointer())
493a07aba5dSTimm Baeder     return false;
494a07aba5dSTimm Baeder   return A.block() == B.block();
495a07aba5dSTimm Baeder }
496a07aba5dSTimm Baeder 
497a07aba5dSTimm Baeder bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
498a07aba5dSTimm Baeder   return hasSameBase(A, B) &&
499a07aba5dSTimm Baeder          A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
500a07aba5dSTimm Baeder          A.getFieldDesc()->IsArray;
501a07aba5dSTimm Baeder }
502a07aba5dSTimm Baeder 
503360e4abfSTimm Baeder bool Pointer::pointsToLiteral() const {
504360e4abfSTimm Baeder   if (isZero() || !isBlockPointer())
505360e4abfSTimm Baeder     return false;
506360e4abfSTimm Baeder 
507360e4abfSTimm Baeder   if (block()->isDynamic())
508360e4abfSTimm Baeder     return false;
509360e4abfSTimm Baeder 
51039e8953fSTimm Baeder   const Expr *E = block()->getDescriptor()->asExpr();
511360e4abfSTimm Baeder   return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
512360e4abfSTimm Baeder }
513360e4abfSTimm Baeder 
514a07aba5dSTimm Baeder std::optional<APValue> Pointer::toRValue(const Context &Ctx,
515a07aba5dSTimm Baeder                                          QualType ResultType) const {
516a07aba5dSTimm Baeder   const ASTContext &ASTCtx = Ctx.getASTContext();
517a07aba5dSTimm Baeder   assert(!ResultType.isNull());
518a07aba5dSTimm Baeder   // Method to recursively traverse composites.
519a07aba5dSTimm Baeder   std::function<bool(QualType, const Pointer &, APValue &)> Composite;
520a07aba5dSTimm Baeder   Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
521a07aba5dSTimm Baeder                                           APValue &R) {
522a07aba5dSTimm Baeder     if (const auto *AT = Ty->getAs<AtomicType>())
523a07aba5dSTimm Baeder       Ty = AT->getValueType();
524a07aba5dSTimm Baeder 
525a07aba5dSTimm Baeder     // Invalid pointers.
526a07aba5dSTimm Baeder     if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
527a07aba5dSTimm Baeder         Ptr.isPastEnd())
528a07aba5dSTimm Baeder       return false;
529a07aba5dSTimm Baeder 
530a07aba5dSTimm Baeder     // Primitive values.
531a07aba5dSTimm Baeder     if (std::optional<PrimType> T = Ctx.classify(Ty)) {
532a07aba5dSTimm Baeder       TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
533a07aba5dSTimm Baeder       return true;
534a07aba5dSTimm Baeder     }
535a07aba5dSTimm Baeder 
536a07aba5dSTimm Baeder     if (const auto *RT = Ty->getAs<RecordType>()) {
537a07aba5dSTimm Baeder       const auto *Record = Ptr.getRecord();
538a07aba5dSTimm Baeder       assert(Record && "Missing record descriptor");
539a07aba5dSTimm Baeder 
540a07aba5dSTimm Baeder       bool Ok = true;
541a07aba5dSTimm Baeder       if (RT->getDecl()->isUnion()) {
542a07aba5dSTimm Baeder         const FieldDecl *ActiveField = nullptr;
543a07aba5dSTimm Baeder         APValue Value;
544a07aba5dSTimm Baeder         for (const auto &F : Record->fields()) {
545a07aba5dSTimm Baeder           const Pointer &FP = Ptr.atField(F.Offset);
546a07aba5dSTimm Baeder           QualType FieldTy = F.Decl->getType();
547a07aba5dSTimm Baeder           if (FP.isActive()) {
548a07aba5dSTimm Baeder             if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
549a07aba5dSTimm Baeder               TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
550a07aba5dSTimm Baeder             } else {
551a07aba5dSTimm Baeder               Ok &= Composite(FieldTy, FP, Value);
552a07aba5dSTimm Baeder             }
553a07aba5dSTimm Baeder             ActiveField = FP.getFieldDesc()->asFieldDecl();
554a07aba5dSTimm Baeder             break;
555a07aba5dSTimm Baeder           }
556a07aba5dSTimm Baeder         }
557a07aba5dSTimm Baeder         R = APValue(ActiveField, Value);
558a07aba5dSTimm Baeder       } else {
559a07aba5dSTimm Baeder         unsigned NF = Record->getNumFields();
560a07aba5dSTimm Baeder         unsigned NB = Record->getNumBases();
561a07aba5dSTimm Baeder         unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
562a07aba5dSTimm Baeder 
563a07aba5dSTimm Baeder         R = APValue(APValue::UninitStruct(), NB, NF);
564a07aba5dSTimm Baeder 
565a07aba5dSTimm Baeder         for (unsigned I = 0; I < NF; ++I) {
566a07aba5dSTimm Baeder           const Record::Field *FD = Record->getField(I);
567a07aba5dSTimm Baeder           QualType FieldTy = FD->Decl->getType();
568a07aba5dSTimm Baeder           const Pointer &FP = Ptr.atField(FD->Offset);
569a07aba5dSTimm Baeder           APValue &Value = R.getStructField(I);
570a07aba5dSTimm Baeder 
571a07aba5dSTimm Baeder           if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
572a07aba5dSTimm Baeder             TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
573a07aba5dSTimm Baeder           } else {
574a07aba5dSTimm Baeder             Ok &= Composite(FieldTy, FP, Value);
575a07aba5dSTimm Baeder           }
576a07aba5dSTimm Baeder         }
577a07aba5dSTimm Baeder 
578a07aba5dSTimm Baeder         for (unsigned I = 0; I < NB; ++I) {
579a07aba5dSTimm Baeder           const Record::Base *BD = Record->getBase(I);
580a07aba5dSTimm Baeder           QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
581a07aba5dSTimm Baeder           const Pointer &BP = Ptr.atField(BD->Offset);
582a07aba5dSTimm Baeder           Ok &= Composite(BaseTy, BP, R.getStructBase(I));
583a07aba5dSTimm Baeder         }
584a07aba5dSTimm Baeder 
585a07aba5dSTimm Baeder         for (unsigned I = 0; I < NV; ++I) {
586a07aba5dSTimm Baeder           const Record::Base *VD = Record->getVirtualBase(I);
587a07aba5dSTimm Baeder           QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
588a07aba5dSTimm Baeder           const Pointer &VP = Ptr.atField(VD->Offset);
589a07aba5dSTimm Baeder           Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
590a07aba5dSTimm Baeder         }
591a07aba5dSTimm Baeder       }
592a07aba5dSTimm Baeder       return Ok;
593a07aba5dSTimm Baeder     }
594a07aba5dSTimm Baeder 
595a07aba5dSTimm Baeder     if (Ty->isIncompleteArrayType()) {
596a07aba5dSTimm Baeder       R = APValue(APValue::UninitArray(), 0, 0);
597a07aba5dSTimm Baeder       return true;
598a07aba5dSTimm Baeder     }
599a07aba5dSTimm Baeder 
600a07aba5dSTimm Baeder     if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
601a07aba5dSTimm Baeder       const size_t NumElems = Ptr.getNumElems();
602a07aba5dSTimm Baeder       QualType ElemTy = AT->getElementType();
603a07aba5dSTimm Baeder       R = APValue(APValue::UninitArray{}, NumElems, NumElems);
604a07aba5dSTimm Baeder 
605a07aba5dSTimm Baeder       bool Ok = true;
606a07aba5dSTimm Baeder       for (unsigned I = 0; I < NumElems; ++I) {
607a07aba5dSTimm Baeder         APValue &Slot = R.getArrayInitializedElt(I);
608a07aba5dSTimm Baeder         const Pointer &EP = Ptr.atIndex(I);
609a07aba5dSTimm Baeder         if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
610a07aba5dSTimm Baeder           TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
611a07aba5dSTimm Baeder         } else {
612a07aba5dSTimm Baeder           Ok &= Composite(ElemTy, EP.narrow(), Slot);
613a07aba5dSTimm Baeder         }
614a07aba5dSTimm Baeder       }
615a07aba5dSTimm Baeder       return Ok;
616a07aba5dSTimm Baeder     }
617a07aba5dSTimm Baeder 
618a07aba5dSTimm Baeder     // Complex types.
619a07aba5dSTimm Baeder     if (const auto *CT = Ty->getAs<ComplexType>()) {
620a07aba5dSTimm Baeder       QualType ElemTy = CT->getElementType();
621a07aba5dSTimm Baeder 
622a07aba5dSTimm Baeder       if (ElemTy->isIntegerType()) {
623a07aba5dSTimm Baeder         std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
624a07aba5dSTimm Baeder         assert(ElemT);
625a07aba5dSTimm Baeder         INT_TYPE_SWITCH(*ElemT, {
626a07aba5dSTimm Baeder           auto V1 = Ptr.atIndex(0).deref<T>();
627a07aba5dSTimm Baeder           auto V2 = Ptr.atIndex(1).deref<T>();
628a07aba5dSTimm Baeder           R = APValue(V1.toAPSInt(), V2.toAPSInt());
629a07aba5dSTimm Baeder           return true;
630a07aba5dSTimm Baeder         });
631a07aba5dSTimm Baeder       } else if (ElemTy->isFloatingType()) {
632a07aba5dSTimm Baeder         R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
633a07aba5dSTimm Baeder                     Ptr.atIndex(1).deref<Floating>().getAPFloat());
634a07aba5dSTimm Baeder         return true;
635a07aba5dSTimm Baeder       }
636a07aba5dSTimm Baeder       return false;
637a07aba5dSTimm Baeder     }
638a07aba5dSTimm Baeder 
639a07aba5dSTimm Baeder     // Vector types.
640a07aba5dSTimm Baeder     if (const auto *VT = Ty->getAs<VectorType>()) {
641a07aba5dSTimm Baeder       assert(Ptr.getFieldDesc()->isPrimitiveArray());
642a07aba5dSTimm Baeder       QualType ElemTy = VT->getElementType();
643a07aba5dSTimm Baeder       PrimType ElemT = *Ctx.classify(ElemTy);
644a07aba5dSTimm Baeder 
645a07aba5dSTimm Baeder       SmallVector<APValue> Values;
646a07aba5dSTimm Baeder       Values.reserve(VT->getNumElements());
647a07aba5dSTimm Baeder       for (unsigned I = 0; I != VT->getNumElements(); ++I) {
648a07aba5dSTimm Baeder         TYPE_SWITCH(ElemT, {
649a07aba5dSTimm Baeder           Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
650a07aba5dSTimm Baeder         });
651a07aba5dSTimm Baeder       }
652a07aba5dSTimm Baeder 
653a07aba5dSTimm Baeder       assert(Values.size() == VT->getNumElements());
654a07aba5dSTimm Baeder       R = APValue(Values.data(), Values.size());
655a07aba5dSTimm Baeder       return true;
656a07aba5dSTimm Baeder     }
657a07aba5dSTimm Baeder 
658a07aba5dSTimm Baeder     llvm_unreachable("invalid value to return");
659a07aba5dSTimm Baeder   };
660a07aba5dSTimm Baeder 
661a07aba5dSTimm Baeder   // Invalid to read from.
662a07aba5dSTimm Baeder   if (isDummy() || !isLive() || isPastEnd())
663a07aba5dSTimm Baeder     return std::nullopt;
664a07aba5dSTimm Baeder 
665a07aba5dSTimm Baeder   // We can return these as rvalues, but we can't deref() them.
666a07aba5dSTimm Baeder   if (isZero() || isIntegralPointer())
667a07aba5dSTimm Baeder     return toAPValue(ASTCtx);
668a07aba5dSTimm Baeder 
669a07aba5dSTimm Baeder   // Just load primitive types.
670a07aba5dSTimm Baeder   if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
671a07aba5dSTimm Baeder     TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
672a07aba5dSTimm Baeder   }
673a07aba5dSTimm Baeder 
674a07aba5dSTimm Baeder   // Return the composite type.
675a07aba5dSTimm Baeder   APValue Result;
676df8b7858STimm Baeder   if (!Composite(ResultType, *this, Result))
677a07aba5dSTimm Baeder     return std::nullopt;
678a07aba5dSTimm Baeder   return Result;
679a07aba5dSTimm Baeder }
680a07aba5dSTimm Baeder 
681a07aba5dSTimm Baeder IntPointer IntPointer::atOffset(const ASTContext &ASTCtx,
682a07aba5dSTimm Baeder                                 unsigned Offset) const {
683a07aba5dSTimm Baeder   if (!this->Desc)
684a07aba5dSTimm Baeder     return *this;
685a07aba5dSTimm Baeder   const Record *R = this->Desc->ElemRecord;
686a07aba5dSTimm Baeder   if (!R)
687a07aba5dSTimm Baeder     return *this;
688a07aba5dSTimm Baeder 
689a07aba5dSTimm Baeder   const Record::Field *F = nullptr;
690a07aba5dSTimm Baeder   for (auto &It : R->fields()) {
691a07aba5dSTimm Baeder     if (It.Offset == Offset) {
692a07aba5dSTimm Baeder       F = &It;
693a07aba5dSTimm Baeder       break;
694a07aba5dSTimm Baeder     }
695a07aba5dSTimm Baeder   }
696a07aba5dSTimm Baeder   if (!F)
697a07aba5dSTimm Baeder     return *this;
698a07aba5dSTimm Baeder 
699a07aba5dSTimm Baeder   const FieldDecl *FD = F->Decl;
700a07aba5dSTimm Baeder   const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
701a07aba5dSTimm Baeder   unsigned FieldIndex = FD->getFieldIndex();
702a07aba5dSTimm Baeder   uint64_t FieldOffset =
703a07aba5dSTimm Baeder       ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
704a07aba5dSTimm Baeder           .getQuantity();
705904f58e6STimm Baeder   return IntPointer{F->Desc, this->Value + FieldOffset};
706a07aba5dSTimm Baeder }
70743fd2c40STimm Baeder 
70843fd2c40STimm Baeder IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
70943fd2c40STimm Baeder                                 unsigned BaseOffset) const {
71043fd2c40STimm Baeder   const Record *R = Desc->ElemRecord;
71143fd2c40STimm Baeder   const Descriptor *BaseDesc = nullptr;
71243fd2c40STimm Baeder 
71343fd2c40STimm Baeder   // This iterates over bases and checks for the proper offset. That's
71443fd2c40STimm Baeder   // potentially slow but this case really shouldn't happen a lot.
71543fd2c40STimm Baeder   for (const Record::Base &B : R->bases()) {
71643fd2c40STimm Baeder     if (B.Offset == BaseOffset) {
71743fd2c40STimm Baeder       BaseDesc = B.Desc;
71843fd2c40STimm Baeder       break;
71943fd2c40STimm Baeder     }
72043fd2c40STimm Baeder   }
72143fd2c40STimm Baeder   assert(BaseDesc);
72243fd2c40STimm Baeder 
72343fd2c40STimm Baeder   // Adjust the offset value based on the information from the record layout.
72443fd2c40STimm Baeder   const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
72543fd2c40STimm Baeder   CharUnits BaseLayoutOffset =
72643fd2c40STimm Baeder       Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
72743fd2c40STimm Baeder 
72843fd2c40STimm Baeder   return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
72943fd2c40STimm Baeder }
730