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