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