clang 24.0.0git
Pointer.cpp
Go to the documentation of this file.
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"
24
25using namespace clang;
26using namespace clang::interp;
27
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, Base, nullptr, nullptr};
42 Pointee->addPointer(this);
43}
44
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(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(&P, 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
85 if (!isBlockPointer())
86 return;
87
88 if (Block *Pointee = BS.Pointee) {
89 Pointee->removePointer(this);
90 BS.Pointee = nullptr;
91 Pointee->cleanup();
92 }
93}
94
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(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(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
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(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(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
175
176 if (isZero())
178 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
179
180 switch (StorageKind) {
181 case Storage::Int:
182 return APValue(static_cast<const Expr *>(nullptr),
184 Path,
185 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
186 case Storage::Block:
187 // See below.
188 break;
189 case Storage::Fn: {
191 if (const FunctionDecl *FD = FP.Func->getDecl())
192 return APValue(FD, CharUnits::fromQuantity(Offset), {},
193 /*OnePastTheEnd=*/false, /*IsNull=*/false);
194 return APValue(FP.Func->getExpr(), CharUnits::fromQuantity(Offset), {},
195 /*OnePastTheEnd=*/false, /*IsNull=*/false);
196 } break;
197 case Storage::Typeid: {
200 TypeInfo, QualType(Typeid.TypeInfoType, 0)),
201 CharUnits::Zero(), {},
202 /*OnePastTheEnd=*/false, /*IsNull=*/false);
203 } break;
204 }
205
206 assert(isBlockPointer());
207 // Build the lvalue base from the block.
208 const Descriptor *Desc = getDeclDesc();
210 if (const auto *VD = Desc->asValueDecl())
211 Base = VD;
212 else if (const auto *E = Desc->asExpr()) {
213 if (block()->isDynamic()) {
214 QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
215 DynamicAllocLValue DA(*block()->DynAllocId);
216 Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
217 } else {
218 Base = E;
219 }
220 } else
221 llvm_unreachable("Invalid allocation type");
222
223 CharUnits Offset = CharUnits::Zero();
224
225 auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
226 // This shouldn't happen, but if it does, don't crash inside
227 // getASTRecordLayout.
228 if (FD->getParent()->isInvalidDecl())
229 return CharUnits::Zero();
230 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
231 unsigned FieldIndex = FD->getFieldIndex();
232 return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
233 };
234
235 // Build the path into the object.
236 bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
237
238 PtrView Ptr = view();
239 while (Ptr.isField() || Ptr.isArrayElement()) {
240
241 if (Ptr.isArrayRoot()) {
242 // An array root may still be an array element itself.
243 if (Ptr.isArrayElement()) {
244 Ptr = Ptr.expand();
245 const Descriptor *Desc = Ptr.getFieldDesc();
246 unsigned Index = Ptr.getIndex();
247 QualType ElemType = Desc->getElemQualType();
248 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
249 if (Ptr.getArray().getFieldDesc()->IsArray)
250 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
251 Ptr = Ptr.getArray();
252 } else {
253 const Descriptor *Desc = Ptr.getFieldDesc();
254 const auto *Dcl = Desc->asDecl();
255 Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
256
257 if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl))
258 Offset += getFieldOffset(FD);
259
260 Ptr = Ptr.getBase();
261 }
262 } else if (Ptr.isArrayElement()) {
263 Ptr = Ptr.expand();
264 const Descriptor *Desc = Ptr.getFieldDesc();
265 unsigned Index;
266 if (Ptr.isOnePastEnd()) {
267 Index = Ptr.getArray().getNumElems();
268 OnePastEnd = false;
269 } else
270 Index = Ptr.getIndex();
271
272 QualType ElemType = Desc->getElemQualType();
273 if (const auto *RD = ElemType->getAsRecordDecl();
274 RD && !RD->getDefinition()) {
275 // Ignore this for the offset.
276 } else {
277 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
278 }
279 if (Ptr.getArray().getFieldDesc()->IsArray)
280 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
281 Ptr = Ptr.getArray();
282 } else {
283 const Descriptor *Desc = Ptr.getFieldDesc();
284
285 // Create a path entry for the field.
286 if (const auto *BaseOrMember = Desc->asDecl()) {
287 bool IsVirtual = false;
288 if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
289 Ptr = Ptr.getBase();
290 Offset += getFieldOffset(FD);
291 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
292 IsVirtual = Ptr.isVirtualBaseClass();
293 Ptr = Ptr.getBase();
294 const Record *BaseRecord = Ptr.getRecord();
295
296 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
297 cast<CXXRecordDecl>(BaseRecord->getDecl()));
298 if (IsVirtual)
299 Offset += Layout.getVBaseClassOffset(RD);
300 else
301 Offset += Layout.getBaseClassOffset(RD);
302
303 } else {
304 Ptr = Ptr.getBase();
305 }
306 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
307 continue;
308 }
309 llvm_unreachable("Invalid field type");
310 }
311 }
312
313 // We assemble the LValuePath starting from the innermost pointer to the
314 // outermost one. SO in a.b.c, the first element in Path will refer to
315 // the field 'c', while later code expects it to refer to 'a'.
316 // Just invert the order of the elements.
317 std::reverse(Path.begin(), Path.end());
318
319 auto Result = APValue(Base, Offset, Path, OnePastEnd);
320 Result.setConstexprUnknown(isConstexprUnknown());
321 return Result;
322}
323
324void Pointer::print(llvm::raw_ostream &OS) const {
325 switch (StorageKind) {
326 case Storage::Block: {
327 const Block *B = BS.Pointee;
328 OS << "(Block) " << B << " {";
329
330 if (isRoot())
331 OS << "rootptr(" << BS.Base << "), ";
332 else
333 OS << BS.Base << ", ";
334
335 if (isElementPastEnd())
336 OS << "pastend, ";
337 else
338 OS << Offset << ", ";
339
340 if (B)
341 OS << B->getSize();
342 else
343 OS << "nullptr";
344 OS << "}";
345 } break;
346 case Storage::Int:
347 OS << "(Int) {" << Int.Value << " + " << Offset << ", " << Int.Ty << "}";
348 break;
349 case Storage::Fn:
350 OS << "(Fn) { " << Fn.Func << " + " << Offset << " }";
351 break;
352 case Storage::Typeid:
353 OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
354 << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
355 << "}";
356 }
357}
358
359/// Compute an offset that can be used to compare the pointer to another one
360/// with the same base. To get accurate results, we basically _have to_ compute
361/// the lvalue offset using the ASTRecordLayout.
362///
363/// This function will fail if we're trying to get the type size of a forward
364/// declaration.
365///
366// FIXME: We're still mixing values from the record layout with our internal
367// offsets, which will inevitably lead to cryptic errors.
368std::optional<size_t>
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:
378 case Storage::Typeid:
379 return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
380 }
381
382 auto getTypeSize = [&](QualType T) -> std::optional<size_t> {
383 if (const RecordType *RT = T->getAs<RecordType>()) {
384 // We cannot get the type size of a forward declaration.
385 if (!RT->getDecl()->getDefinition())
386 return std::nullopt;
387 }
388 return ASTCtx.getTypeSizeInChars(T).getQuantity();
389 };
390
391 size_t Result = 0;
392 PtrView P = view();
393 while (true) {
394 if (P.isVirtualBaseClass()) {
395 Result += getInlineDesc()->Offset;
396 P = P.getBase();
397 continue;
398 }
399
400 if (P.isBaseClass()) {
402 P = P.getBase();
403 continue;
404 }
405 if (P.isArrayElement()) {
406 P = P.expand();
407 Result += (P.getIndex() * P.elemSize());
408 P = P.getArray();
409 continue;
410 }
411
412 if (P.isRoot()) {
413 if (P.isOnePastEnd()) {
414 if (auto Size = getTypeSize(P.getDeclDesc()->getType()))
415 Result += *Size;
416 else
417 return std::nullopt;
418 }
419 break;
420 }
421
422 assert(P.getField());
423 const Record *R = P.getBase().getRecord();
424 assert(R);
425
426 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
427 Result += ASTCtx
430 .getQuantity();
431
432 if (P.isOnePastEnd()) {
433 if (auto Size = getTypeSize(P.getField()->getType()))
434 Result += *Size;
435 else
436 return std::nullopt;
437 }
438
439 P = P.getBase();
440 if (P.isRoot())
441 break;
442 }
443 return Result;
444}
445
446std::optional<size_t>
448 switch (StorageKind) {
449 case Storage::Int:
450 return Int.Value + Offset;
451 case Storage::Block:
452 // See below.
453 break;
454 case Storage::Fn:
456 case Storage::Typeid:
457 return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
458 }
459
460 auto getTypeSize = [&](QualType T) -> std::optional<size_t> {
461 if (const RecordType *RT = T->getAs<RecordType>()) {
462 // We cannot get the type size of a forward declaration.
463 if (!RT->getDecl()->getDefinition())
464 return std::nullopt;
465 }
466 return ASTCtx.getTypeSizeInChars(T).getQuantity();
467 };
468
469 auto getRecordDecl = [&](PtrView P) -> const CXXRecordDecl * {
470 if (const Record *R = P.getRecord())
471 return cast<CXXRecordDecl>(R->getDecl());
472 return cast<CXXRecordDecl>(P.getFieldDesc()->asDecl());
473 };
474
475 auto getRecordSize = [&](const RecordDecl *RD) -> unsigned {
476 CanQualType RecordTy = ASTCtx.getCanonicalTagType(RD);
477 return ASTCtx.getTypeSizeInChars(RecordTy).getQuantity();
478 };
479
480 size_t Result = 0;
481 PtrView P = view();
482 while (true) {
483 if (P.isBaseClass()) {
484 const ASTRecordLayout &Layout =
486 const CXXRecordDecl *RD = getRecordDecl(P);
487 if (P.isVirtualBaseClass())
488 Result += Layout.getVBaseClassOffset(RD).getQuantity();
489 else
490 Result += Layout.getBaseClassOffset(RD).getQuantity();
491
492 if (P.isOnePastEnd())
493 Result += getRecordSize(RD);
494
495 P = P.getBase();
496 continue;
497 }
498
499 if (P.isArrayElement()) {
500 P = P.expand();
501 assert(P.getFieldDesc()->isArray());
502 if (std::optional<size_t> ElemSize =
503 getTypeSize(P.getFieldDesc()->getElemQualType()))
504 Result += *ElemSize * P.getIndex();
505 else
506 return std::nullopt;
507
508 P = P.getArray();
509 continue;
510 }
511
512 if (P.isRoot()) {
513 if (P.isPastEnd() || P.isOnePastEnd()) {
514 if (std::optional<size_t> Size =
515 getTypeSize(P.getDeclDesc()->getType()))
516 Result += *Size * P.getIndex();
517 else
518 return std::nullopt;
519 }
520 break;
521 }
522
523 assert(P.getField());
524 const FieldDecl *F = P.getField();
525 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(F->getParent());
526 Result +=
528 .getQuantity();
529
530 if (P.isPastEnd() || P.isOnePastEnd()) {
531 if (std::optional<size_t> Size = getTypeSize(F->getType()))
532 Result += *Size * P.getIndex();
533 else
534 return std::nullopt;
535 }
536
537 P = P.getBase();
538 if (P.isRoot())
539 break;
540 }
541 return Result;
542}
543
544std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
545 if (isZero())
546 return "nullptr";
547
548 if (isIntegralPointer())
549 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
550
551 QualType Ty = getType();
552 if (Ty->isLValueReferenceType())
553 Ty = Ty->getPointeeType();
554 return toAPValue(Ctx).getAsString(Ctx, Ty);
555}
556
558 if (!isBlockPointer())
559 return true;
560
561 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
562 Offset == BS.Base) {
563 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
565 }
566
567 assert(BS.Pointee && "Cannot check if null pointer was initialized");
568 const Descriptor *Desc = getFieldDesc();
569 assert(Desc);
570 if (Desc->isPrimitiveArray())
572
573 if (asBlockPointer().Base == 0)
574 return true;
575 // Field has its bit in an inline descriptor.
576 return getInlineDesc()->IsInitialized;
577}
578
579bool PtrView::isElementInitialized(unsigned Index) const {
580 const Descriptor *Desc = getFieldDesc();
581 assert(Desc);
582
583 if (Pointee->isStatic() && Base == 0)
584 return true;
585
586 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
587 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
589 }
590
591 if (Desc->isPrimitiveArray()) {
592 InitMapPtr IM = getInitMap();
593
594 if (IM.allInitialized())
595 return true;
596
597 if (!IM.hasInitMap())
598 return false;
599 return IM->isElementInitialized(Index);
600 }
601 return isInitialized();
602}
603
604bool Pointer::isElementAlive(unsigned Index) const {
605 assert(getFieldDesc()->isPrimitiveArray());
606
607 InitMapPtr &IM = getInitMap();
608 if (!IM.hasInitMap())
609 return true;
610
611 if (IM.allInitialized())
612 return true;
613
614 return IM->isElementAlive(Index);
615}
616
618 if (Base < sizeof(InlineDescriptor))
619 return Lifetime::Started;
620
621 if (inArray() && !isArrayRoot()) {
622 InitMapPtr &IM = getInitMap();
623
624 if (!IM.hasInitMap()) {
625 if (IM.allInitialized())
626 return Lifetime::Started;
627 return getArray().getLifetime();
628 }
629
631 }
632
633 return getInlineDesc()->LifeState;
634}
635
637 if (Base < sizeof(InlineDescriptor))
638 return;
639
640 if (inArray() && !isArrayRoot()) {
641 assert(L == Lifetime::Started || L == Lifetime::Ended);
642 const Descriptor *Desc = getFieldDesc();
643 InitMapPtr &IM = getInitMap();
644 if (!IM.hasInitMap())
645 IM.setInitMap(new InitMap(Desc->getNumElems(), IM.allInitialized()));
646
647 if (L == Lifetime::Ended)
649 else if (L == Lifetime::Started)
651 assert(isArrayRoot() || (this->getLifetime() == L));
652 return;
653 }
654
656}
657
659 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
660 auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
662 return;
663 }
664
665 const Descriptor *Desc = getFieldDesc();
666 assert(Desc);
667 if (Desc->isPrimitiveArray()) {
668 if (Desc->getNumElems() != 0)
670 return;
671 }
672
673 // Field has its bit in an inline descriptor.
674 assert(Base != 0 && "Only composite fields can be initialised");
677}
678
679void PtrView::initializeElement(unsigned Index) const {
680 // Primitive global arrays don't have an initmap.
681 if (Pointee->isStatic() && Base == 0)
682 return;
683
684 assert(Index < getFieldDesc()->getNumElems());
685
686 InitMapPtr &IM = getInitMap();
687 if (IM.allInitialized())
688 return;
689
690 if (!IM.hasInitMap()) {
691 const Descriptor *Desc = getFieldDesc();
692 IM.setInitMap(new InitMap(Desc->getNumElems()));
693 }
694 assert(IM.hasInitMap());
695
696 if (IM->initializeElement(Index))
698}
699
701 assert(getFieldDesc()->isPrimitiveArray());
702 assert(isArrayRoot());
703
704 getInitMap().noteAllInitialized();
705}
706
708 assert(getFieldDesc()->isPrimitiveArray());
709 assert(isArrayRoot());
710
711 if (Pointee->isStatic() && Base == 0)
712 return true;
713
714 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
715 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
717 }
718
719 InitMapPtr IM = getInitMap();
720 return IM.allInitialized();
721}
722
724 assert(getFieldDesc()->isPrimitiveArray());
725 assert(isArrayRoot());
726
727 if (isStatic() && BS.Base == 0)
728 return true;
729
730 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
731 Offset == BS.Base) {
732 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
734 }
735
736 InitMapPtr &IM = getInitMap();
737 return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive());
738}
739
740void PtrView::activate() const {
741 // Field has its bit in an inline descriptor.
742 assert(Base != 0 && "Only composite fields can be activated");
743
744 if (isRoot() && Base == sizeof(GlobalInlineDescriptor))
745 return;
746 if (!getInlineDesc()->InUnion)
747 return;
748
750 activate = [&activate](PtrView P) -> void {
751 P.getInlineDesc()->IsActive = true;
752 P.startLifetime();
753 if (const Record *R = P.getRecord(); R && !R->isUnion()) {
754 for (const Record::Field &F : R->fields()) {
755 PtrView FieldPtr = P.atField(F.Offset);
756 if (!FieldPtr.getInlineDesc()->IsActive)
757 activate(FieldPtr);
758 }
759 // FIXME: Bases?
760 }
761 };
762
763 std::function<void(PtrView &)> deactivate;
764 deactivate = [&deactivate](PtrView &P) -> void {
765 P.getInlineDesc()->IsActive = false;
766
767 if (const Record *R = P.getRecord()) {
768 for (const Record::Field &F : R->fields()) {
769 PtrView FieldPtr = P.atField(F.Offset);
770 if (FieldPtr.getInlineDesc()->IsActive)
771 deactivate(FieldPtr);
772 }
773 // FIXME: Bases?
774 }
775 };
776
777 PtrView B = *this;
778 // Primitive array elements can't be activated individually, so
779 // look at the array root instead.
781 B = B.getArray();
782
783 while (!B.isRoot() && B.inUnion()) {
784 activate(B);
785
786 // When walking up the pointer chain, deactivate
787 // all union child pointers that aren't on our path.
788 PtrView Cur = B;
789 B = B.getBase();
790 if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
791 for (const Record::Field &F : BR->fields()) {
792 PtrView FieldPtr = B.atField(F.Offset);
793 if (FieldPtr != Cur)
794 deactivate(FieldPtr);
795 }
796 }
797 }
798}
799
800bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
801 // Two null pointers always have the same base.
802 if (A.isZero() && B.isZero())
803 return true;
804
806 return true;
808 return true;
809 if (A.isTypeidPointer() && B.isTypeidPointer())
811
812 if (A.StorageKind != B.StorageKind)
813 return false;
814
816}
817
818bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
819 if (!A.isBlockPointer() || !B.isBlockPointer())
820 return false;
821 return A.block() == B.block();
822}
823
824bool Pointer::elemsOfSameArray(const Pointer &A, const Pointer &B) {
825 assert(hasSameBase(A, B));
826 assert(A.isBlockPointer());
827 assert(B.isBlockPointer());
828
829 if (A.BS.Base == B.BS.Base)
830 return true;
831
832 if (A.isBaseClass() || B.isBaseClass())
833 return false;
834
835 if (A.getField() || B.getField())
836 return false;
837
838 auto closestArray = [](const Pointer &P) -> PtrView {
839 if (P.isArrayRoot())
840 return P.view();
841
842 PtrView V = P.view();
843 if (V.isArrayElement() || V.isOnePastEnd())
844 V = V.expand().getArray();
845
846 if (P.isRoot())
847 return P.view();
848
849 while (!V.isRoot() && !V.getFieldDesc()->IsArray) {
850 if (V.isArrayElement()) {
851 V = V.expand().getArray();
852 break;
853 }
854 V = V.getBase();
855 }
856 return V;
857 };
858
859 if (closestArray(A) != closestArray(B))
860 return false;
861
862 return true;
863}
864
866 if (isZero() || !isBlockPointer())
867 return false;
868
869 if (block()->isDynamic())
870 return false;
871
872 const Expr *E = block()->getDescriptor()->asExpr();
874}
875
877 if (isZero() || !isBlockPointer())
878 return false;
879
880 if (block()->isDynamic())
881 return false;
882
883 const Expr *E = block()->getDescriptor()->asExpr();
884 return isa_and_nonnull<StringLiteral>(E);
885}
886
888 if (isZero() || !isBlockPointer())
889 return false;
890
891 if (const Expr *E = BS.Pointee->getDescriptor()->asExpr())
892 return isa<AddrLabelExpr>(E);
893 return false;
894}
895
896std::optional<std::pair<PtrView, PtrView>>
898 if (!A.isBlockPointer() || !B.isBlockPointer())
899 return std::nullopt;
900
902 return std::nullopt;
903 if (A.isRoot() && B.isRoot())
904 return std::nullopt;
905
906 if (A == B)
907 return std::make_pair(A.view(), B.view());
908
909 auto getBase = [](PtrView P) -> PtrView {
910 if (P.isArrayElement())
911 return P.expand().getArray();
912 return P.getBase();
913 };
914
915 PtrView IterA = A.view();
916 PtrView IterB = B.view();
917 PtrView CurA = IterA;
918 PtrView CurB = IterB;
919 for (;;) {
920 if (IterA.Base > IterB.Base) {
921 CurA = IterA;
922 IterA = getBase(IterA);
923 } else {
924 CurB = IterB;
925 IterB = getBase(IterB);
926 }
927
928 if (IterA == IterB) {
929 // If the Iter is an array, CurA and CurB are both elements of the same
930 // array. That is fine, so return nullopt.
931 if (IterA.getFieldDesc()->isArray())
932 return std::nullopt;
933 return std::make_pair(CurA, CurB);
934 }
935
936 if (IterA.isRoot() && IterB.isRoot())
937 return std::nullopt;
938 }
939
940 llvm_unreachable("The loop above should've returned.");
941}
942
943std::optional<APValue> Pointer::toRValue(const Context &Ctx,
944 QualType ResultType) const {
945 const ASTContext &ASTCtx = Ctx.getASTContext();
946 assert(!ResultType.isNull());
947 // Method to recursively traverse composites.
948 std::function<bool(QualType, PtrView, APValue &)> Composite;
949 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, PtrView Ptr,
950 APValue &R) {
951 if (const auto *AT = Ty->getAs<AtomicType>())
952 Ty = AT->getValueType();
953
954 // Invalid pointers.
955 if (Ptr.isDummy() || !Ptr.isLive() || Ptr.isPastEnd())
956 return false;
957
958 // Primitives should never end up here.
959 assert(!Ctx.canClassify(Ty));
960 const Descriptor *FieldDesc = Ptr.getFieldDesc();
961 assert(FieldDesc);
962
963 if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
964 if (!FieldDesc->isRecord())
965 return false;
966 const auto *Record = Ptr.getRecord();
967 assert(Record && "Missing record descriptor");
968
969 bool Ok = true;
970 if (RT->getDecl()->isUnion()) {
971 const FieldDecl *ActiveField = nullptr;
973 for (const auto &F : Record->fields()) {
974 PtrView FP = Ptr.atField(F.Offset);
975 if (FP.isActive()) {
976 const Descriptor *Desc = F.Desc;
977 if (Desc->isPrimitive()) {
978 TYPE_SWITCH(Desc->getPrimType(),
979 Value = FP.deref<T>().toAPValue(ASTCtx));
980 } else {
981 QualType FieldTy = F.Decl->getType();
982 Ok &= Composite(FieldTy, FP, Value);
983 }
984 ActiveField = FP.getFieldDesc()->asFieldDecl();
985 break;
986 }
987 }
988 R = APValue(ActiveField, Value);
989 } else {
990 unsigned NF = Record->getNumFields();
991 unsigned NB = Record->getNumBases();
992 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
993
994 R = APValue(APValue::UninitStruct(), NB, NF, NV);
995
996 for (unsigned I = 0; I != NF; ++I) {
997 const Record::Field *FD = Record->getField(I);
998 const Descriptor *Desc = FD->Desc;
999 PtrView FP = Ptr.atField(FD->Offset);
1000 APValue &Value = R.getStructField(I);
1001 if (Desc->isPrimitive()) {
1002 TYPE_SWITCH(Desc->getPrimType(),
1003 Value = FP.deref<T>().toAPValue(ASTCtx));
1004 } else {
1005 QualType FieldTy = FD->Decl->getType();
1006 Ok &= Composite(FieldTy, FP, Value);
1007 }
1008 }
1009
1010 for (unsigned I = 0; I != NB; ++I) {
1011 const Record::Base *BD = Record->getBase(I);
1012 QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
1013 PtrView BP = Ptr.atField(BD->Offset);
1014 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
1015 }
1016
1017 for (unsigned I = 0; I != NV; ++I) {
1018 const Record::Base *VD = Record->getVirtualBase(I);
1019 assert(VD);
1020 QualType VirtBaseTy =
1021 Ctx.getASTContext().getCanonicalTagType(VD->Decl);
1022 PtrView VP = Ptr.atField(VD->Offset);
1023 Ok &= Composite(VirtBaseTy, VP, R.getStructVirtualBase(I));
1024 }
1025 }
1026 return Ok;
1027 }
1028
1029 if (Ty->isIncompleteArrayType()) {
1030 R = APValue(APValue::UninitArray(), 0, 0);
1031 return true;
1032 }
1033
1034 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
1035 if (!FieldDesc->isArray())
1036 return false;
1037 const size_t NumElems = Ptr.getNumElems();
1038 QualType ElemTy = AT->getElementType();
1039 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
1040
1041 bool Ok = true;
1042 OptPrimType ElemT = Ctx.classify(ElemTy);
1043 for (unsigned I = 0; I != NumElems; ++I) {
1044 APValue &Slot = R.getArrayInitializedElt(I);
1045 if (ElemT) {
1046 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
1047 } else {
1048 Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
1049 }
1050 }
1051 return Ok;
1052 }
1053
1054 // Complex types.
1055 if (Ty->isAnyComplexType()) {
1056 // Can happen via C casts.
1057 if (!FieldDesc->getType()->isAnyComplexType())
1058 return false;
1059
1060 PrimType ElemT = FieldDesc->getPrimType();
1061 if (isIntegerOrBoolType(ElemT)) {
1062 INT_TYPE_SWITCH(ElemT, {
1063 auto V1 = Ptr.elem<T>(0);
1064 auto V2 = Ptr.elem<T>(1);
1065 R = APValue(V1.toAPSInt(), V2.toAPSInt());
1066 return true;
1067 });
1068 } else if (ElemT == PT_Float) {
1069 R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
1070 Ptr.elem<Floating>(1).getAPFloat());
1071 return true;
1072 }
1073 return false;
1074 }
1075
1076 // Vector types.
1077 if (const auto *VT = Ty->getAs<VectorType>()) {
1078 if (!FieldDesc->isPrimitiveArray())
1079 return false;
1080
1081 PrimType ElemT = FieldDesc->getPrimType();
1082 SmallVector<APValue> Values;
1083 Values.reserve(VT->getNumElements());
1084 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
1085 TYPE_SWITCH(ElemT,
1086 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1087 }
1088
1089 assert(Values.size() == VT->getNumElements());
1090 R = APValue(Values.data(), Values.size());
1091 return true;
1092 }
1093
1094 // Constant Matrix types.
1095 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
1096 if (!FieldDesc->isPrimitiveArray())
1097 return false;
1098 PrimType ElemT = FieldDesc->getPrimType();
1099 unsigned NumElems = MT->getNumElementsFlattened();
1100
1101 SmallVector<APValue> Values;
1102 Values.reserve(NumElems);
1103 for (unsigned I = 0; I != NumElems; ++I) {
1104 TYPE_SWITCH(ElemT,
1105 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1106 }
1107
1108 R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
1109 return true;
1110 }
1111
1112 llvm_unreachable("invalid value to return");
1113 };
1114
1115 // Can't return functions as rvalues.
1116 if (ResultType->isFunctionType())
1117 return std::nullopt;
1118
1119 // Invalid to read from.
1120 if (isDummy() || !isLive() || isPastEnd() ||
1121 (isOnePastEnd() && !isZeroSizeArray()))
1122 return std::nullopt;
1123
1124 // We can return these as rvalues, but we can't deref() them.
1125 if (isZero() || isIntegralPointer())
1126 return toAPValue(ASTCtx);
1127
1128 // Just load primitive types.
1129 if (OptPrimType T = Ctx.classify(ResultType)) {
1130 if (!canDeref(*T))
1131 return std::nullopt;
1132 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
1133 }
1134
1135 // Return the composite type.
1137 if (!Composite(ResultType, view(), Result))
1138 return std::nullopt;
1139 return Result;
1140}
1141
1143 if (isBlockPointer())
1144 return getDeclDesc()->asVarDecl();
1145 return nullptr;
1146}
1147
1148std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx,
1149 unsigned Offset) const {
1150 QualType CurType = getPointeeType();
1151 if (CurType.isNull() || !CurType->isRecordType())
1152 return std::nullopt;
1153
1154 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1155 if (!R)
1156 return *this;
1157
1158 const Record::Field *F = R->findField(Offset);
1159 if (!F)
1160 return *this;
1161
1162 const FieldDecl *FD = F->Decl;
1163 if (FD->getParent()->isInvalidDecl())
1164 return std::nullopt;
1165
1166 const ASTContext &ASTCtx = Ctx.getASTContext();
1167 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
1168 unsigned FieldIndex = FD->getFieldIndex();
1169 uint64_t FieldOffset =
1170 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
1171 .getQuantity();
1172
1173 return IntPointer{FD->getType().getTypePtr(), this->Value + FieldOffset};
1174}
1175
1177 unsigned BaseOffset) const {
1178 if (!Ty)
1179 return *this;
1180
1181 QualType CurType = getPointeeType();
1182 if (CurType.isNull() || !CurType->isRecordType())
1183 return *this;
1184
1185 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1186
1187 // This iterates over bases and checks for the proper offset. That's
1188 // potentially slow but this case really shouldn't happen a lot.
1189 const Record::Base *B = R->findBase(BaseOffset);
1190 if (!B)
1191 return *this;
1192
1193 const Descriptor *BaseDesc = B->Desc;
1194 // Adjust the offset value based on the information from the record layout.
1195 const ASTContext &ASTCtx = Ctx.getASTContext();
1196 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
1197 CharUnits BaseLayoutOffset =
1198 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
1199
1200 const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
1202 std::nullopt, RD, false);
1203 return {T.getTypePtr(), Value + BaseLayoutOffset.getQuantity()};
1204}
#define V(N, I)
Defines the clang::Expr interface and subclasses for C++ expressions.
#define INT_TYPE_SWITCH(Expr, B)
Definition PrimType.h:244
#define TYPE_SWITCH(Expr, B)
Definition PrimType.h:223
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD)
static const RecordDecl * getRecordDecl(QualType QT)
Checks that the passed in QualType either is of RecordType or points to RecordType.
static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo)
Definition APValue.cpp:55
static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type)
Definition APValue.cpp:47
A non-discriminated union of a base, field, or array index.
Definition APValue.h:208
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition APValue.h:216
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
std::string getAsString(const ASTContext &Ctx, QualType Ty) const
Definition APValue.cpp:993
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType getTagType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag) const
CharUnits toCharUnitsFromBits(int64_t BitSize) const
Convert a size in bits to a size in characters.
CanQualType getCanonicalTagType(const TagDecl *TD) const
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition CharUnits.h:53
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4501
Decl()=delete
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
bool isInvalidDecl() const
Definition DeclBase.h:596
Symbolic representation of a dynamic allocation.
Definition APValue.h:65
This represents one expression.
Definition Expr.h:112
Represents a member of a struct/union/class.
Definition Decl.h:3294
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3379
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3530
Represents a function declaration or definition.
Definition Decl.h:2058
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8504
Represents a struct/union/class.
Definition Decl.h:4459
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition Decl.h:4643
Symbolic representation of typeid(T) for some type T.
Definition APValue.h:44
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isLValueReferenceType() const
Definition TypeBase.h:8769
bool isAnyComplexType() const
Definition TypeBase.h:8876
bool isFunctionType() const
Definition TypeBase.h:8737
bool isRecordType() const
Definition TypeBase.h:8868
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:932
Represents a GCC generic vector type.
Definition TypeBase.h:4289
unsigned getSize() const
Returns the size of the block.
Definition InterpBlock.h:87
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition InterpBlock.h:73
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:47
const Record * getRecord(const RecordDecl *D) const
Definition Context.cpp:776
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:107
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:465
bool canClassify(QualType T) const
Definition Context.h:129
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition Floating.h:35
APFloat getAPFloat() const
Definition Floating.h:64
const BlockExpr * getExpr() const
Definition Function.h:137
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition Function.h:134
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition Pointer.cpp:800
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:557
bool pointsToLabel() const
Whether this points to a block created for an AddrLabelExpr.
Definition Pointer.cpp:887
bool isStatic() const
Checks if the storage is static.
Definition Pointer.h:706
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition Pointer.h:721
const VarDecl * getRootVarDecl() const
Definition Pointer.cpp:1142
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:857
FunctionPointer Fn
Definition Pointer.h:1073
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:762
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition Pointer.cpp:324
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:824
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
Definition Pointer.h:866
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:875
const TypeidPointer & asTypeidPointer() const
Definition Pointer.h:674
bool isIntegralPointer() const
Definition Pointer.h:680
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:574
void initializeAllElements() const
Initialize all elements of a primitive array at once.
Definition Pointer.cpp:700
bool pointsToStringLiteral() const
Definition Pointer.cpp:876
std::optional< size_t > computeOffsetForComparison(const ASTContext &ASTCtx) const
Compute an integer that can be used to compare this pointer to another one.
Definition Pointer.cpp:369
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition Pointer.h:615
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:522
static bool elemsOfSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition Pointer.cpp:824
bool isElementAlive(unsigned Index) const
Definition Pointer.cpp:604
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition Pointer.cpp:865
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Compute the pointer offset as given by the ASTRecordLayout.
Definition Pointer.cpp:447
bool allElementsAlive() const
Definition Pointer.cpp:723
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:559
bool isTypeidPointer() const
Definition Pointer.h:682
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition Pointer.cpp:544
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:508
Pointer & operator=(const Pointer &P)
Definition Pointer.cpp:95
bool isConstexprUnknown() const
Definition Pointer.h:898
const IntPointer & asIntPointer() const
Definition Pointer.h:666
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:649
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:536
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition Pointer.cpp:818
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
Definition Pointer.cpp:173
bool isOnePastEnd() const
Checks if the index is one past end.
Definition Pointer.h:832
uint64_t getIntegerRepresentation() const
Definition Pointer.h:453
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition Pointer.h:846
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:693
friend class Block
Definition Pointer.h:1035
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:854
bool isBlockPointer() const
Definition Pointer.h:679
TypeidPointer Typeid
Definition Pointer.h:1074
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition Pointer.cpp:943
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:670
const Block * block() const
Definition Pointer.h:814
bool isFunctionPointer() const
Definition Pointer.h:681
Pointer getDeclPtr() const
Definition Pointer.h:590
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:564
PtrView view() const
Definition Pointer.h:461
bool isBaseClass() const
Checks if a structure is a base class.
Definition Pointer.h:758
const BlockPointer & asBlockPointer() const
Definition Pointer.h:662
static std::optional< std::pair< PtrView, PtrView > > computeSplitPoint(const Pointer &A, const Pointer &B)
Definition Pointer.cpp:897
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition Pointer.h:936
Structure/Class descriptor.
Definition Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition Record.h:65
bool isUnion() const
Checks if the record is a union.
Definition Record.h:69
const Field * getField(unsigned I) const
Definition Record.h:95
unsigned getNumBases() const
Definition Record.h:109
const Base * getBase(unsigned I) const
Definition Record.h:110
const Base * getVirtualBase(unsigned I) const
Definition Record.h:127
unsigned getNumFields() const
Definition Record.h:94
unsigned getNumVirtualBases() const
Definition Record.h:126
llvm::iterator_range< const_field_iter > fields() const
Definition Record.h:90
constexpr bool isIntegerOrBoolType(PrimType T)
Definition PrimType.h:52
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
@ None
No keyword precedes the qualified type name.
Definition TypeBase.h:6041
int const char * function
Definition c++config.h:31
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
unsigned Base
Start of the current subfield.
Definition Pointer.h:336
Block * Pointee
The block the pointer is pointing to.
Definition Pointer.h:334
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:258
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:272
QualType getElemQualType() const
const ValueDecl * asValueDecl() const
Definition Descriptor.h:214
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:210
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition Descriptor.h:255
QualType getDataType(const ASTContext &Ctx) const
const bool IsArray
Flag indicating if the block is an array.
Definition Descriptor.h:168
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:263
const FieldDecl * asFieldDecl() const
Definition Descriptor.h:222
const VarDecl * asVarDecl() const
Definition Descriptor.h:218
PrimType getPrimType() const
Definition Descriptor.h:240
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:277
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:153
const Expr * asExpr() const
Definition Descriptor.h:211
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:275
Descriptor used for global variables.
Definition Descriptor.h:49
A pointer-sized struct we use to allocate into data storage.
Definition InitMap.h:79
bool hasInitMap() const
Definition InitMap.h:88
bool allInitialized() const
Are all elements in the array already initialized?
Definition InitMap.h:92
void setInitMap(const InitMap *IM)
Definition InitMap.h:94
Bitfield tracking the initialisation status of elements of primitive arrays.
Definition InitMap.h:22
void startElementLifetime(unsigned I)
Definition InitMap.cpp:32
void endElementLifetime(unsigned I)
Definition InitMap.cpp:45
bool allElementsAlive() const
Definition InitMap.h:58
bool isElementInitialized(unsigned I) const
Checks if an element was initialized.
Definition InitMap.cpp:23
bool initializeElement(unsigned I)
Initializes an element. Returns true when object if fully initialized.
Definition InitMap.cpp:13
bool isElementAlive(unsigned I) const
Definition InitMap.h:52
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:67
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition Descriptor.h:89
unsigned Offset
Offset inside the structure/array.
Definition Descriptor.h:69
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition Descriptor.h:80
QualType getPointeeType() const
Definition Pointer.h:350
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
Definition Pointer.cpp:1176
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1148
const Descriptor * getDeclDesc() const
Definition Pointer.h:87
bool allElementsInitialized() const
Definition Pointer.cpp:707
PtrView atField(unsigned Offset) const
Definition Pointer.h:264
bool isField() const
Definition Pointer.h:163
size_t elemSize() const
Definition Pointer.h:89
const Record * getRecord() const
Definition Pointer.h:156
const Descriptor * getFieldDesc() const
Definition Pointer.h:81
const FieldDecl * getField() const
Definition Pointer.h:161
bool isElementInitialized(unsigned Index) const
Definition Pointer.cpp:579
bool isBaseClass() const
Definition Pointer.h:167
void activate() const
Definition Pointer.cpp:740
bool inArray() const
Definition Pointer.h:54
void startLifetime() const
Definition Pointer.h:321
bool isInitialized() const
Definition Pointer.h:292
bool isArrayElement() const
Definition Pointer.h:223
bool isPastEnd() const
Definition Pointer.h:175
PtrView getArray() const
Definition Pointer.h:151
unsigned getNumElems() const
Definition Pointer.h:221
InitMapPtr & getInitMap() const
Definition Pointer.h:313
InlineDescriptor * getInlineDesc() const
Definition Pointer.h:68
bool inUnion() const
Definition Pointer.h:53
void initializeElement(unsigned Index) const
Definition Pointer.cpp:679
void initialize() const
Definition Pointer.cpp:658
bool isOnePastEnd() const
Definition Pointer.h:191
bool isRoot() const
Definition Pointer.h:60
void setLifeState(Lifetime L) const
Definition Pointer.cpp:636
Lifetime getLifetime() const
Definition Pointer.cpp:617
PtrView getBase() const
Definition Pointer.h:259
bool isActive() const
Definition Pointer.h:46
PtrView expand() const
Definition Pointer.h:115
bool isVirtualBaseClass() const
Definition Pointer.h:168
bool isArrayRoot() const
Definition Pointer.h:47
T & deref() const
Definition Pointer.h:235
int64_t getIndex() const
Definition Pointer.h:209