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