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 "InitMap.h"
15#include "Integral.h"
16#include "InterpBlock.h"
17#include "MemberPointer.h"
18#include "PrimType.h"
19#include "Record.h"
20#include "clang/AST/Expr.h"
21#include "clang/AST/ExprCXX.h"
22#include "clang/AST/RecordLayout.h"
23
24using namespace clang;
25using namespace clang::interp;
26
27Pointer::Pointer(Block *Pointee)
28 : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
29 Pointee->getDescriptor()->getMetadataSize()) {}
30
31Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
32 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
33
34Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
35 : Offset(Offset), StorageKind(Storage::Block) {
36 assert(Pointee);
37 assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
38 assert(Base >= Pointee->getDescriptor()->getMetadataSize());
39
40 BS = {.Pointee: Pointee, .Base: Base, .Prev: nullptr, .Next: nullptr};
41 Pointee->addPointer(P: this);
42}
43
44Pointer::Pointer(const Pointer &P)
45 : Offset(P.Offset), StorageKind(P.StorageKind) {
46 switch (StorageKind) {
47 case Storage::Int:
48 Int = P.Int;
49 break;
50 case Storage::Block:
51 BS = P.BS;
52 if (BS.Pointee)
53 BS.Pointee->addPointer(P: this);
54 break;
55 case Storage::Fn:
56 Fn = P.Fn;
57 break;
58 case Storage::Typeid:
59 Typeid = P.Typeid;
60 break;
61 }
62}
63
64Pointer::Pointer(Pointer &&P) : Offset(P.Offset), StorageKind(P.StorageKind) {
65 switch (StorageKind) {
66 case Storage::Int:
67 Int = P.Int;
68 break;
69 case Storage::Block:
70 BS = P.BS;
71 if (BS.Pointee)
72 BS.Pointee->replacePointer(Old: &P, New: this);
73 break;
74 case Storage::Fn:
75 Fn = P.Fn;
76 break;
77 case Storage::Typeid:
78 Typeid = P.Typeid;
79 break;
80 }
81}
82
83Pointer::~Pointer() {
84 if (!isBlockPointer())
85 return;
86
87 if (Block *Pointee = BS.Pointee) {
88 Pointee->removePointer(P: this);
89 BS.Pointee = nullptr;
90 Pointee->cleanup();
91 }
92}
93
94Pointer &Pointer::operator=(const Pointer &P) {
95 // If the current storage type is Block, we need to remove
96 // this pointer from the block.
97 if (isBlockPointer()) {
98 if (P.isBlockPointer() && this->block() == P.block()) {
99 Offset = P.Offset;
100 BS.Base = P.BS.Base;
101 return *this;
102 }
103
104 if (Block *Pointee = BS.Pointee) {
105 Pointee->removePointer(P: this);
106 BS.Pointee = nullptr;
107 Pointee->cleanup();
108 }
109 }
110
111 StorageKind = P.StorageKind;
112 Offset = P.Offset;
113
114 switch (StorageKind) {
115 case Storage::Int:
116 Int = P.Int;
117 break;
118 case Storage::Block:
119 BS = P.BS;
120
121 if (BS.Pointee)
122 BS.Pointee->addPointer(P: this);
123 break;
124 case Storage::Fn:
125 Fn = P.Fn;
126 break;
127 case Storage::Typeid:
128 Typeid = P.Typeid;
129 }
130 return *this;
131}
132
133Pointer &Pointer::operator=(Pointer &&P) {
134 // If the current storage type is Block, we need to remove
135 // this pointer from the block.
136 if (isBlockPointer()) {
137 if (P.isBlockPointer() && this->block() == P.block()) {
138 Offset = P.Offset;
139 BS.Base = P.BS.Base;
140 return *this;
141 }
142
143 if (Block *Pointee = BS.Pointee) {
144 Pointee->removePointer(P: this);
145 BS.Pointee = nullptr;
146 Pointee->cleanup();
147 }
148 }
149
150 StorageKind = P.StorageKind;
151 Offset = P.Offset;
152
153 switch (StorageKind) {
154 case Storage::Int:
155 Int = P.Int;
156 break;
157 case Storage::Block:
158 BS = P.BS;
159
160 if (BS.Pointee)
161 BS.Pointee->addPointer(P: this);
162 break;
163 case Storage::Fn:
164 Fn = P.Fn;
165 break;
166 case Storage::Typeid:
167 Typeid = P.Typeid;
168 }
169 return *this;
170}
171
172APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
173 llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
174
175 if (isZero())
176 return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
177 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
178 if (isIntegralPointer())
179 return APValue(static_cast<const Expr *>(nullptr),
180 CharUnits::fromQuantity(Quantity: asIntPointer().Value + this->Offset),
181 Path,
182 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
183 if (isFunctionPointer()) {
184 const FunctionPointer &FP = asFunctionPointer();
185 if (const FunctionDecl *FD = FP.Func->getDecl())
186 return APValue(FD, CharUnits::fromQuantity(Quantity: Offset), {},
187 /*OnePastTheEnd=*/false, /*IsNull=*/false);
188 return APValue(FP.Func->getExpr(), CharUnits::fromQuantity(Quantity: Offset), {},
189 /*OnePastTheEnd=*/false, /*IsNull=*/false);
190 }
191
192 if (isTypeidPointer()) {
193 TypeInfoLValue TypeInfo(Typeid.TypePtr);
194 return APValue(APValue::LValueBase::getTypeInfo(
195 LV: TypeInfo, TypeInfo: QualType(Typeid.TypeInfoType, 0)),
196 CharUnits::Zero(), {},
197 /*OnePastTheEnd=*/false, /*IsNull=*/false);
198 }
199
200 // Build the lvalue base from the block.
201 const Descriptor *Desc = getDeclDesc();
202 APValue::LValueBase Base;
203 if (const auto *VD = Desc->asValueDecl())
204 Base = VD;
205 else if (const auto *E = Desc->asExpr()) {
206 if (block()->isDynamic()) {
207 QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(Ctx: ASTCtx);
208 DynamicAllocLValue DA(*block()->DynAllocId);
209 Base = APValue::LValueBase::getDynamicAlloc(LV: DA, Type: AllocatedType);
210 } else {
211 Base = E;
212 }
213 } else
214 llvm_unreachable("Invalid allocation type");
215
216 if (isUnknownSizeArray())
217 return APValue(Base, CharUnits::Zero(), Path,
218 /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
219
220 CharUnits Offset = CharUnits::Zero();
221
222 auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
223 // This shouldn't happen, but if it does, don't crash inside
224 // getASTRecordLayout.
225 if (FD->getParent()->isInvalidDecl())
226 return CharUnits::Zero();
227 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: FD->getParent());
228 unsigned FieldIndex = FD->getFieldIndex();
229 return ASTCtx.toCharUnitsFromBits(BitSize: Layout.getFieldOffset(FieldNo: FieldIndex));
230 };
231
232 bool UsePath = true;
233 if (const ValueDecl *VD = getDeclDesc()->asValueDecl();
234 VD && VD->getType()->isReferenceType())
235 UsePath = false;
236
237 // Build the path into the object.
238 bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
239 Pointer Ptr = *this;
240 while (Ptr.isField() || Ptr.isArrayElement()) {
241
242 if (Ptr.isArrayRoot()) {
243 // An array root may still be an array element itself.
244 if (Ptr.isArrayElement()) {
245 Ptr = Ptr.expand();
246 const Descriptor *Desc = Ptr.getFieldDesc();
247 unsigned Index = Ptr.getIndex();
248 QualType ElemType = Desc->getElemQualType();
249 Offset += (Index * ASTCtx.getTypeSizeInChars(T: ElemType));
250 if (Ptr.getArray().getFieldDesc()->IsArray)
251 Path.push_back(Elt: APValue::LValuePathEntry::ArrayIndex(Index));
252 Ptr = Ptr.getArray();
253 } else {
254 const Descriptor *Desc = Ptr.getFieldDesc();
255 const auto *Dcl = Desc->asDecl();
256 Path.push_back(Elt: APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
257
258 if (const auto *FD = dyn_cast_if_present<FieldDecl>(Val: Dcl))
259 Offset += getFieldOffset(FD);
260
261 Ptr = Ptr.getBase();
262 }
263 } else if (Ptr.isArrayElement()) {
264 Ptr = Ptr.expand();
265 const Descriptor *Desc = Ptr.getFieldDesc();
266 unsigned Index;
267 if (Ptr.isOnePastEnd()) {
268 Index = Ptr.getArray().getNumElems();
269 OnePastEnd = false;
270 } else
271 Index = Ptr.getIndex();
272
273 QualType ElemType = Desc->getElemQualType();
274 if (const auto *RD = ElemType->getAsRecordDecl();
275 RD && !RD->getDefinition()) {
276 // Ignore this for the offset.
277 } else {
278 Offset += (Index * ASTCtx.getTypeSizeInChars(T: ElemType));
279 }
280 if (Ptr.getArray().getFieldDesc()->IsArray)
281 Path.push_back(Elt: APValue::LValuePathEntry::ArrayIndex(Index));
282 Ptr = Ptr.getArray();
283 } else {
284 const Descriptor *Desc = Ptr.getFieldDesc();
285
286 // Create a path entry for the field.
287 if (const auto *BaseOrMember = Desc->asDecl()) {
288 bool IsVirtual = false;
289 if (const auto *FD = dyn_cast<FieldDecl>(Val: BaseOrMember)) {
290 Ptr = Ptr.getBase();
291 Offset += getFieldOffset(FD);
292 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(Val: BaseOrMember)) {
293 IsVirtual = Ptr.isVirtualBaseClass();
294 Ptr = Ptr.getBase();
295 const Record *BaseRecord = Ptr.getRecord();
296
297 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
298 D: cast<CXXRecordDecl>(Val: BaseRecord->getDecl()));
299 if (IsVirtual)
300 Offset += Layout.getVBaseClassOffset(VBase: RD);
301 else
302 Offset += Layout.getBaseClassOffset(Base: RD);
303
304 } else {
305 Ptr = Ptr.getBase();
306 }
307 Path.push_back(Elt: APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
308 continue;
309 }
310 llvm_unreachable("Invalid field type");
311 }
312 }
313
314 // We assemble the LValuePath starting from the innermost pointer to the
315 // outermost one. SO in a.b.c, the first element in Path will refer to
316 // the field 'c', while later code expects it to refer to 'a'.
317 // Just invert the order of the elements.
318 std::reverse(first: Path.begin(), last: Path.end());
319
320 if (UsePath)
321 return APValue(Base, Offset, Path, OnePastEnd);
322
323 return APValue(Base, Offset, APValue::NoLValuePath());
324}
325
326void Pointer::print(llvm::raw_ostream &OS) const {
327 switch (StorageKind) {
328 case Storage::Block: {
329 const Block *B = BS.Pointee;
330 OS << "(Block) " << B << " {";
331
332 if (isRoot())
333 OS << "rootptr(" << BS.Base << "), ";
334 else
335 OS << BS.Base << ", ";
336
337 if (isElementPastEnd())
338 OS << "pastend, ";
339 else
340 OS << Offset << ", ";
341
342 if (B)
343 OS << B->getSize();
344 else
345 OS << "nullptr";
346 OS << "}";
347 } break;
348 case Storage::Int:
349 OS << "(Int) {";
350 OS << Int.Value << " + " << Offset << ", " << Int.Desc;
351 OS << "}";
352 break;
353 case Storage::Fn:
354 OS << "(Fn) { " << Fn.Func << " + " << Offset << " }";
355 break;
356 case Storage::Typeid:
357 OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
358 << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
359 << "}";
360 }
361}
362
363/// Compute an offset that can be used to compare the pointer to another one
364/// with the same base. To get accurate results, we basically _have to_ compute
365/// the lvalue offset using the ASTRecordLayout.
366///
367/// FIXME: We're still mixing values from the record layout with our internal
368/// offsets, which will inevitably lead to cryptic errors.
369size_t Pointer::computeOffsetForComparison(const ASTContext &ASTCtx) const {
370 switch (StorageKind) {
371 case Storage::Int:
372 return Int.Value + Offset;
373 case Storage::Block:
374 // See below.
375 break;
376 case Storage::Fn:
377 return getIntegerRepresentation();
378 case Storage::Typeid:
379 return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
380 }
381
382 size_t Result = 0;
383 Pointer P = *this;
384 while (true) {
385 if (P.isVirtualBaseClass()) {
386 Result += getInlineDesc()->Offset;
387 P = P.getBase();
388 continue;
389 }
390
391 if (P.isBaseClass()) {
392 if (P.getRecord()->getNumVirtualBases() > 0)
393 Result += P.getInlineDesc()->Offset;
394 P = P.getBase();
395 continue;
396 }
397 if (P.isArrayElement()) {
398 P = P.expand();
399 Result += (P.getIndex() * P.elemSize());
400 P = P.getArray();
401 continue;
402 }
403
404 if (P.isRoot()) {
405 if (P.isOnePastEnd())
406 Result +=
407 ASTCtx.getTypeSizeInChars(T: P.getDeclDesc()->getType()).getQuantity();
408 break;
409 }
410
411 assert(P.getField());
412 const Record *R = P.getBase().getRecord();
413 assert(R);
414
415 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: R->getDecl());
416 Result += ASTCtx
417 .toCharUnitsFromBits(
418 BitSize: Layout.getFieldOffset(FieldNo: P.getField()->getFieldIndex()))
419 .getQuantity();
420
421 if (P.isOnePastEnd())
422 Result +=
423 ASTCtx.getTypeSizeInChars(T: P.getField()->getType()).getQuantity();
424
425 P = P.getBase();
426 if (P.isRoot())
427 break;
428 }
429 return Result;
430}
431
432std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
433 if (isZero())
434 return "nullptr";
435
436 if (isIntegralPointer())
437 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
438
439 return toAPValue(ASTCtx: Ctx).getAsString(Ctx, Ty: getType());
440}
441
442bool Pointer::isInitialized() const {
443 if (!isBlockPointer())
444 return true;
445
446 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
447 Offset == BS.Base) {
448 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
449 return GD.InitState == GlobalInitState::Initialized;
450 }
451
452 assert(BS.Pointee && "Cannot check if null pointer was initialized");
453 const Descriptor *Desc = getFieldDesc();
454 assert(Desc);
455 if (Desc->isPrimitiveArray())
456 return isElementInitialized(Index: getIndex());
457
458 if (asBlockPointer().Base == 0)
459 return true;
460 // Field has its bit in an inline descriptor.
461 return getInlineDesc()->IsInitialized;
462}
463
464bool Pointer::isElementInitialized(unsigned Index) const {
465 if (!isBlockPointer())
466 return true;
467
468 const Descriptor *Desc = getFieldDesc();
469 assert(Desc);
470
471 if (isStatic() && BS.Base == 0)
472 return true;
473
474 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
475 Offset == BS.Base) {
476 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
477 return GD.InitState == GlobalInitState::Initialized;
478 }
479
480 if (Desc->isPrimitiveArray()) {
481 InitMapPtr IM = getInitMap();
482
483 if (IM.allInitialized())
484 return true;
485
486 if (!IM.hasInitMap())
487 return false;
488 return IM->isElementInitialized(I: Index);
489 }
490 return isInitialized();
491}
492
493bool Pointer::isElementAlive(unsigned Index) const {
494 assert(getFieldDesc()->isPrimitiveArray());
495
496 InitMapPtr &IM = getInitMap();
497 if (!IM.hasInitMap())
498 return true;
499
500 if (IM.allInitialized())
501 return true;
502
503 return IM->isElementAlive(I: Index);
504}
505
506void Pointer::startLifetime() const {
507 if (!isBlockPointer())
508 return;
509 if (BS.Base < sizeof(InlineDescriptor))
510 return;
511
512 if (inArray()) {
513 const Descriptor *Desc = getFieldDesc();
514 InitMapPtr &IM = getInitMap();
515 if (!IM.hasInitMap())
516 IM.setInitMap(new InitMap(Desc->getNumElems(), IM.allInitialized()));
517
518 IM->startElementLifetime(I: getIndex());
519 assert(isArrayRoot() || (this->getLifetime() == Lifetime::Started));
520 return;
521 }
522
523 getInlineDesc()->LifeState = Lifetime::Started;
524}
525
526void Pointer::endLifetime() const {
527 if (!isBlockPointer())
528 return;
529 if (BS.Base < sizeof(InlineDescriptor))
530 return;
531
532 if (inArray()) {
533 const Descriptor *Desc = getFieldDesc();
534 InitMapPtr &IM = getInitMap();
535 if (!IM.hasInitMap())
536 IM.setInitMap(new InitMap(Desc->getNumElems(), IM.allInitialized()));
537
538 IM->endElementLifetime(I: getIndex());
539 assert(isArrayRoot() || (this->getLifetime() == Lifetime::Ended));
540 return;
541 }
542
543 getInlineDesc()->LifeState = Lifetime::Ended;
544}
545
546void Pointer::initialize() const {
547 if (!isBlockPointer())
548 return;
549
550 assert(BS.Pointee && "Cannot initialize null pointer");
551
552 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
553 Offset == BS.Base) {
554 auto &GD = BS.Pointee->getBlockDesc<GlobalInlineDescriptor>();
555 GD.InitState = GlobalInitState::Initialized;
556 return;
557 }
558
559 const Descriptor *Desc = getFieldDesc();
560 assert(Desc);
561 if (Desc->isPrimitiveArray()) {
562 if (Desc->getNumElems() != 0)
563 initializeElement(Index: getIndex());
564 return;
565 }
566
567 // Field has its bit in an inline descriptor.
568 assert(BS.Base != 0 && "Only composite fields can be initialised");
569 getInlineDesc()->IsInitialized = true;
570}
571
572void Pointer::initializeElement(unsigned Index) const {
573 // Primitive global arrays don't have an initmap.
574 if (isStatic() && BS.Base == 0)
575 return;
576
577 assert(Index < getFieldDesc()->getNumElems());
578
579 InitMapPtr &IM = getInitMap();
580 if (IM.allInitialized())
581 return;
582
583 if (!IM.hasInitMap()) {
584 const Descriptor *Desc = getFieldDesc();
585 IM.setInitMap(new InitMap(Desc->getNumElems()));
586 }
587 assert(IM.hasInitMap());
588
589 if (IM->initializeElement(I: Index))
590 IM.noteAllInitialized();
591}
592
593void Pointer::initializeAllElements() const {
594 assert(getFieldDesc()->isPrimitiveArray());
595 assert(isArrayRoot());
596
597 getInitMap().noteAllInitialized();
598}
599
600bool Pointer::allElementsInitialized() const {
601 assert(getFieldDesc()->isPrimitiveArray());
602 assert(isArrayRoot());
603
604 if (isStatic() && BS.Base == 0)
605 return true;
606
607 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
608 Offset == BS.Base) {
609 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
610 return GD.InitState == GlobalInitState::Initialized;
611 }
612
613 InitMapPtr IM = getInitMap();
614 return IM.allInitialized();
615}
616
617bool Pointer::allElementsAlive() const {
618 assert(getFieldDesc()->isPrimitiveArray());
619 assert(isArrayRoot());
620
621 if (isStatic() && BS.Base == 0)
622 return true;
623
624 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
625 Offset == BS.Base) {
626 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
627 return GD.InitState == GlobalInitState::Initialized;
628 }
629
630 InitMapPtr &IM = getInitMap();
631 return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive());
632}
633
634void Pointer::activate() const {
635 // Field has its bit in an inline descriptor.
636 assert(BS.Base != 0 && "Only composite fields can be activated");
637
638 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
639 return;
640 if (!getInlineDesc()->InUnion)
641 return;
642
643 std::function<void(Pointer &)> activate;
644 activate = [&activate](Pointer &P) -> void {
645 P.getInlineDesc()->IsActive = true;
646 if (const Record *R = P.getRecord(); R && !R->isUnion()) {
647 for (const Record::Field &F : R->fields()) {
648 Pointer FieldPtr = P.atField(Off: F.Offset);
649 if (!FieldPtr.getInlineDesc()->IsActive)
650 activate(FieldPtr);
651 }
652 // FIXME: Bases?
653 }
654 };
655
656 std::function<void(Pointer &)> deactivate;
657 deactivate = [&deactivate](Pointer &P) -> void {
658 P.getInlineDesc()->IsActive = false;
659
660 if (const Record *R = P.getRecord()) {
661 for (const Record::Field &F : R->fields()) {
662 Pointer FieldPtr = P.atField(Off: F.Offset);
663 if (FieldPtr.getInlineDesc()->IsActive)
664 deactivate(FieldPtr);
665 }
666 // FIXME: Bases?
667 }
668 };
669
670 Pointer B = *this;
671 while (!B.isRoot() && B.inUnion()) {
672 activate(B);
673
674 // When walking up the pointer chain, deactivate
675 // all union child pointers that aren't on our path.
676 Pointer Cur = B;
677 B = B.getBase();
678 if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
679 for (const Record::Field &F : BR->fields()) {
680 Pointer FieldPtr = B.atField(Off: F.Offset);
681 if (FieldPtr != Cur)
682 deactivate(FieldPtr);
683 }
684 }
685 }
686}
687
688void Pointer::deactivate() const {
689 // TODO: this only appears in constructors, so nothing to deactivate.
690}
691
692bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
693 // Two null pointers always have the same base.
694 if (A.isZero() && B.isZero())
695 return true;
696
697 if (A.isIntegralPointer() && B.isIntegralPointer())
698 return true;
699 if (A.isFunctionPointer() && B.isFunctionPointer())
700 return true;
701 if (A.isTypeidPointer() && B.isTypeidPointer())
702 return true;
703
704 if (A.StorageKind != B.StorageKind)
705 return false;
706
707 return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
708}
709
710bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
711 if (!A.isBlockPointer() || !B.isBlockPointer())
712 return false;
713 return A.block() == B.block();
714}
715
716bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
717 return hasSameBase(A, B) && A.BS.Base == B.BS.Base &&
718 A.getFieldDesc()->IsArray;
719}
720
721bool Pointer::pointsToLiteral() const {
722 if (isZero() || !isBlockPointer())
723 return false;
724
725 if (block()->isDynamic())
726 return false;
727
728 const Expr *E = block()->getDescriptor()->asExpr();
729 return E && !isa<MaterializeTemporaryExpr, StringLiteral>(Val: E);
730}
731
732bool Pointer::pointsToStringLiteral() const {
733 if (isZero() || !isBlockPointer())
734 return false;
735
736 if (block()->isDynamic())
737 return false;
738
739 const Expr *E = block()->getDescriptor()->asExpr();
740 return isa_and_nonnull<StringLiteral>(Val: E);
741}
742
743std::optional<std::pair<Pointer, Pointer>>
744Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
745 if (!A.isBlockPointer() || !B.isBlockPointer())
746 return std::nullopt;
747
748 if (A.asBlockPointer().Pointee != B.asBlockPointer().Pointee)
749 return std::nullopt;
750 if (A.isRoot() && B.isRoot())
751 return std::nullopt;
752
753 if (A == B)
754 return std::make_pair(x: A, y: B);
755
756 auto getBase = [](const Pointer &P) -> Pointer {
757 if (P.isArrayElement())
758 return P.expand().getArray();
759 return P.getBase();
760 };
761
762 Pointer IterA = A;
763 Pointer IterB = B;
764 Pointer CurA = IterA;
765 Pointer CurB = IterB;
766 for (;;) {
767 if (IterA.asBlockPointer().Base > IterB.asBlockPointer().Base) {
768 CurA = IterA;
769 IterA = getBase(IterA);
770 } else {
771 CurB = IterB;
772 IterB = getBase(IterB);
773 }
774
775 if (IterA == IterB)
776 return std::make_pair(x&: CurA, y&: CurB);
777
778 if (IterA.isRoot() && IterB.isRoot())
779 return std::nullopt;
780 }
781
782 llvm_unreachable("The loop above should've returned.");
783}
784
785std::optional<APValue> Pointer::toRValue(const Context &Ctx,
786 QualType ResultType) const {
787 const ASTContext &ASTCtx = Ctx.getASTContext();
788 assert(!ResultType.isNull());
789 // Method to recursively traverse composites.
790 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
791 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
792 APValue &R) {
793 if (const auto *AT = Ty->getAs<AtomicType>())
794 Ty = AT->getValueType();
795
796 // Invalid pointers.
797 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
798 Ptr.isPastEnd())
799 return false;
800
801 // Primitives should never end up here.
802 assert(!Ctx.canClassify(Ty));
803
804 if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
805 const auto *Record = Ptr.getRecord();
806 assert(Record && "Missing record descriptor");
807
808 bool Ok = true;
809 if (RT->getDecl()->isUnion()) {
810 const FieldDecl *ActiveField = nullptr;
811 APValue Value;
812 for (const auto &F : Record->fields()) {
813 const Pointer &FP = Ptr.atField(Off: F.Offset);
814 if (FP.isActive()) {
815 const Descriptor *Desc = F.Desc;
816 if (Desc->isPrimitive()) {
817 TYPE_SWITCH(Desc->getPrimType(),
818 Value = FP.deref<T>().toAPValue(ASTCtx));
819 } else {
820 QualType FieldTy = F.Decl->getType();
821 Ok &= Composite(FieldTy, FP, Value);
822 }
823 ActiveField = FP.getFieldDesc()->asFieldDecl();
824 break;
825 }
826 }
827 R = APValue(ActiveField, Value);
828 } else {
829 unsigned NF = Record->getNumFields();
830 unsigned NB = Record->getNumBases();
831 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
832
833 R = APValue(APValue::UninitStruct(), NB, NF);
834
835 for (unsigned I = 0; I != NF; ++I) {
836 const Record::Field *FD = Record->getField(I);
837 const Descriptor *Desc = FD->Desc;
838 const Pointer &FP = Ptr.atField(Off: FD->Offset);
839 APValue &Value = R.getStructField(i: I);
840 if (Desc->isPrimitive()) {
841 TYPE_SWITCH(Desc->getPrimType(),
842 Value = FP.deref<T>().toAPValue(ASTCtx));
843 } else {
844 QualType FieldTy = FD->Decl->getType();
845 Ok &= Composite(FieldTy, FP, Value);
846 }
847 }
848
849 for (unsigned I = 0; I != NB; ++I) {
850 const Record::Base *BD = Record->getBase(I);
851 QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(TD: BD->Decl);
852 const Pointer &BP = Ptr.atField(Off: BD->Offset);
853 Ok &= Composite(BaseTy, BP, R.getStructBase(i: I));
854 }
855
856 for (unsigned I = 0; I != NV; ++I) {
857 const Record::Base *VD = Record->getVirtualBase(I);
858 QualType VirtBaseTy =
859 Ctx.getASTContext().getCanonicalTagType(TD: VD->Decl);
860 const Pointer &VP = Ptr.atField(Off: VD->Offset);
861 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(i: NB + I));
862 }
863 }
864 return Ok;
865 }
866
867 if (Ty->isIncompleteArrayType()) {
868 R = APValue(APValue::UninitArray(), 0, 0);
869 return true;
870 }
871
872 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
873 const size_t NumElems = Ptr.getNumElems();
874 QualType ElemTy = AT->getElementType();
875 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
876
877 bool Ok = true;
878 OptPrimType ElemT = Ctx.classify(T: ElemTy);
879 for (unsigned I = 0; I != NumElems; ++I) {
880 APValue &Slot = R.getArrayInitializedElt(I);
881 if (ElemT) {
882 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
883 } else {
884 Ok &= Composite(ElemTy, Ptr.atIndex(Idx: I).narrow(), Slot);
885 }
886 }
887 return Ok;
888 }
889
890 // Complex types.
891 if (Ty->isAnyComplexType()) {
892 const Descriptor *Desc = Ptr.getFieldDesc();
893 // Can happen via C casts.
894 if (!Desc->isPrimitiveArray())
895 return false;
896
897 PrimType ElemT = Desc->getPrimType();
898 if (isIntegerOrBoolType(T: ElemT)) {
899 PrimType ElemT = Desc->getPrimType();
900 INT_TYPE_SWITCH(ElemT, {
901 auto V1 = Ptr.elem<T>(0);
902 auto V2 = Ptr.elem<T>(1);
903 R = APValue(V1.toAPSInt(), V2.toAPSInt());
904 return true;
905 });
906 } else if (ElemT == PT_Float) {
907 R = APValue(Ptr.elem<Floating>(I: 0).getAPFloat(),
908 Ptr.elem<Floating>(I: 1).getAPFloat());
909 return true;
910 }
911 return false;
912 }
913
914 // Vector types.
915 if (const auto *VT = Ty->getAs<VectorType>()) {
916 const Descriptor *Desc = Ptr.getFieldDesc();
917 assert(Ptr.getFieldDesc()->isPrimitiveArray());
918 PrimType ElemT = Desc->getPrimType();
919
920 SmallVector<APValue> Values;
921 Values.reserve(N: VT->getNumElements());
922 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
923 TYPE_SWITCH(ElemT,
924 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
925 }
926
927 assert(Values.size() == VT->getNumElements());
928 R = APValue(Values.data(), Values.size());
929 return true;
930 }
931
932 // Constant Matrix types.
933 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
934 assert(Ptr.getFieldDesc()->isPrimitiveArray());
935 const Descriptor *Desc = Ptr.getFieldDesc();
936 PrimType ElemT = Desc->getPrimType();
937 unsigned NumElems = MT->getNumElementsFlattened();
938
939 SmallVector<APValue> Values;
940 Values.reserve(N: NumElems);
941 for (unsigned I = 0; I != NumElems; ++I) {
942 TYPE_SWITCH(ElemT,
943 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
944 }
945
946 R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
947 return true;
948 }
949
950 llvm_unreachable("invalid value to return");
951 };
952
953 // Can't return functions as rvalues.
954 if (ResultType->isFunctionType())
955 return std::nullopt;
956
957 // Invalid to read from.
958 if (isDummy() || !isLive() || isPastEnd())
959 return std::nullopt;
960
961 // We can return these as rvalues, but we can't deref() them.
962 if (isZero() || isIntegralPointer())
963 return toAPValue(ASTCtx);
964
965 // Just load primitive types.
966 if (OptPrimType T = Ctx.classify(T: ResultType)) {
967 if (!canDeref(T: *T))
968 return std::nullopt;
969 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
970 }
971
972 // Return the composite type.
973 APValue Result;
974 if (!Composite(ResultType, *this, Result))
975 return std::nullopt;
976 return Result;
977}
978
979std::optional<IntPointer> IntPointer::atOffset(const ASTContext &ASTCtx,
980 unsigned Offset) const {
981 if (!this->Desc)
982 return *this;
983 const Record *R = this->Desc->ElemRecord;
984 if (!R)
985 return *this;
986
987 const Record::Field *F = nullptr;
988 for (auto &It : R->fields()) {
989 if (It.Offset == Offset) {
990 F = &It;
991 break;
992 }
993 }
994 if (!F)
995 return *this;
996
997 const FieldDecl *FD = F->Decl;
998 if (FD->getParent()->isInvalidDecl())
999 return std::nullopt;
1000
1001 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: FD->getParent());
1002 unsigned FieldIndex = FD->getFieldIndex();
1003 uint64_t FieldOffset =
1004 ASTCtx.toCharUnitsFromBits(BitSize: Layout.getFieldOffset(FieldNo: FieldIndex))
1005 .getQuantity();
1006 return IntPointer{.Desc: F->Desc, .Value: this->Value + FieldOffset};
1007}
1008
1009IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
1010 unsigned BaseOffset) const {
1011 if (!Desc) {
1012 assert(Value == 0);
1013 return *this;
1014 }
1015 const Record *R = Desc->ElemRecord;
1016 const Descriptor *BaseDesc = nullptr;
1017
1018 // This iterates over bases and checks for the proper offset. That's
1019 // potentially slow but this case really shouldn't happen a lot.
1020 for (const Record::Base &B : R->bases()) {
1021 if (B.Offset == BaseOffset) {
1022 BaseDesc = B.Desc;
1023 break;
1024 }
1025 }
1026 assert(BaseDesc);
1027
1028 // Adjust the offset value based on the information from the record layout.
1029 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: R->getDecl());
1030 CharUnits BaseLayoutOffset =
1031 Layout.getBaseClassOffset(Base: cast<CXXRecordDecl>(Val: BaseDesc->asDecl()));
1032
1033 return {.Desc: BaseDesc, .Value: Value + BaseLayoutOffset.getQuantity()};
1034}
1035