clang 23.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())
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),
182 Path,
183 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
184 if (isFunctionPointer()) {
186 if (const FunctionDecl *FD = FP.Func->getDecl())
187 return APValue(FD, CharUnits::fromQuantity(Offset), {},
188 /*OnePastTheEnd=*/false, /*IsNull=*/false);
189 return APValue(FP.Func->getExpr(), CharUnits::fromQuantity(Offset), {},
190 /*OnePastTheEnd=*/false, /*IsNull=*/false);
191 }
192
193 if (isTypeidPointer()) {
196 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();
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(ASTCtx);
209 DynamicAllocLValue DA(*block()->DynAllocId);
210 Base = APValue::LValueBase::getDynamicAlloc(DA, 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(FD->getParent());
225 unsigned FieldIndex = FD->getFieldIndex();
226 return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(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(ElemType));
243 if (Ptr.getArray().getFieldDesc()->IsArray)
244 Path.push_back(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(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
250
251 if (const auto *FD = dyn_cast_if_present<FieldDecl>(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(ElemType));
272 }
273 if (Ptr.getArray().getFieldDesc()->IsArray)
274 Path.push_back(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>(BaseOrMember)) {
283 Ptr = Ptr.getBase();
284 Offset += getFieldOffset(FD);
285 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
286 IsVirtual = Ptr.isVirtualBaseClass();
287 Ptr = Ptr.getBase();
288 const Record *BaseRecord = Ptr.getRecord();
289
290 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
291 cast<CXXRecordDecl>(BaseRecord->getDecl()));
292 if (IsVirtual)
293 Offset += Layout.getVBaseClassOffset(RD);
294 else
295 Offset += Layout.getBaseClassOffset(RD);
296
297 } else {
298 Ptr = Ptr.getBase();
299 }
300 Path.push_back(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(Path.begin(), 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>
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:
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()) {
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(R->getDecl());
421 Result += ASTCtx
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(Ctx).getAsString(Ctx, Ty);
451}
452
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>();
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())
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>();
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(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(Index);
511}
512
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
527 }
528
529 return getInlineDesc()->LifeState;
530}
531
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)
545 else if (L == Lifetime::Started)
547 assert(isArrayRoot() || (this->getLifetime() == L));
548 return;
549 }
550
552}
553
555 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
556 auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
558 return;
559 }
560
561 const Descriptor *Desc = getFieldDesc();
562 assert(Desc);
563 if (Desc->isPrimitiveArray()) {
564 if (Desc->getNumElems() != 0)
566 return;
567 }
568
569 // Field has its bit in an inline descriptor.
570 assert(Base != 0 && "Only composite fields can be initialised");
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(Index))
594}
595
597 assert(getFieldDesc()->isPrimitiveArray());
598 assert(isArrayRoot());
599
600 getInitMap().noteAllInitialized();
601}
602
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>();
613 }
614
615 InitMapPtr IM = getInitMap();
616 return IM.allInitialized();
617}
618
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>();
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
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(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(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.
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(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
702 return true;
704 return true;
705 if (A.isTypeidPointer() && B.isTypeidPointer())
706 return true;
707
708 if (A.StorageKind != B.StorageKind)
709 return false;
710
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 &&
723}
724
726 if (isZero() || !isBlockPointer())
727 return false;
728
729 if (block()->isDynamic())
730 return false;
731
732 const Expr *E = block()->getDescriptor()->asExpr();
734}
735
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>(E);
745}
746
748 if (isZero() || !isBlockPointer())
749 return false;
750
751 if (const Expr *E = BS.Pointee->getDescriptor()->asExpr())
752 return isa<AddrLabelExpr>(E);
753 return false;
754}
755
756std::optional<std::pair<PtrView, PtrView>>
758 if (!A.isBlockPointer() || !B.isBlockPointer())
759 return std::nullopt;
760
762 return std::nullopt;
763 if (A.isRoot() && B.isRoot())
764 return std::nullopt;
765
766 if (A == B)
767 return std::make_pair(A.view(), 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(CurA, 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;
829 for (const auto &F : Record->fields()) {
830 PtrView FP = Ptr.atField(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(FD->Offset);
856 APValue &Value = R.getStructField(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(BD->Decl);
869 PtrView BP = Ptr.atField(BD->Offset);
870 Ok &= Composite(BaseTy, BP, R.getStructBase(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(VD->Decl);
878 PtrView VP = Ptr.atField(VD->Offset);
879 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(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(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(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(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>(0).getAPFloat(),
926 Ptr.elem<Floating>(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
939 Values.reserve(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
958 Values.reserve(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() ||
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(ResultType)) {
986 if (!canDeref(*T))
987 return std::nullopt;
988 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
989 }
990
991 // Return the composite type.
993 if (!Composite(ResultType, view(), Result))
994 return std::nullopt;
995 return Result;
996}
997
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(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(FD->getParent());
1030 unsigned FieldIndex = FD->getFieldIndex();
1031 uint64_t FieldOffset =
1032 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
1033 .getQuantity();
1034
1035 return IntPointer{FD->getType().getTypePtr(), this->Value + FieldOffset};
1036}
1037
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(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(R->getDecl());
1063 CharUnits BaseLayoutOffset =
1064 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
1065
1066 const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
1068 std::nullopt, RD, false);
1069 return {T.getTypePtr(), Value + BaseLayoutOffset.getQuantity()};
1070}
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 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:974
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.
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:4451
Decl()=delete
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:547
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:3182
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3267
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3418
Represents a function declaration or definition.
Definition Decl.h:2018
A (possibly-)qualified type.
Definition TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8447
Represents a struct/union/class.
Definition Decl.h:4347
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition Decl.h:4531
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:8712
bool isAnyComplexType() const
Definition TypeBase.h:8819
bool isFunctionType() const
Definition TypeBase.h:8680
bool isRecordType() const
Definition TypeBase.h:8811
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:924
Represents a GCC generic vector type.
Definition TypeBase.h:4239
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:735
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:101
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:424
bool canClassify(QualType T) const
Definition Context.h:123
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:696
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:453
bool pointsToLabel() const
Whether this points to a block created for an AddrLabelExpr.
Definition Pointer.cpp:747
bool isStatic() const
Checks if the storage is static.
Definition Pointer.h:695
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition Pointer.h:710
const VarDecl * getRootVarDecl() const
Definition Pointer.cpp:998
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:846
FunctionPointer Fn
Definition Pointer.h:1078
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:751
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition Pointer.cpp:318
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:813
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
Definition Pointer.h:855
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:864
const TypeidPointer & asTypeidPointer() const
Definition Pointer.h:663
bool isIntegralPointer() const
Definition Pointer.h:669
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:563
void initializeAllElements() const
Initialize all elements of a primitive array at once.
Definition Pointer.cpp:596
bool pointsToStringLiteral() const
Definition Pointer.cpp:736
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:363
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition Pointer.h:604
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:511
bool isElementAlive(unsigned Index) const
Definition Pointer.cpp:500
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition Pointer.cpp:725
bool allElementsAlive() const
Definition Pointer.cpp:619
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:548
bool isTypeidPointer() const
Definition Pointer.h:671
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition Pointer.cpp:440
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:497
Pointer & operator=(const Pointer &P)
Definition Pointer.cpp:95
bool isConstexprUnknown() const
Definition Pointer.h:887
const IntPointer & asIntPointer() const
Definition Pointer.h:655
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:638
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:525
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition Pointer.cpp:714
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:821
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition Pointer.cpp:720
uint64_t getIntegerRepresentation() const
Definition Pointer.h:442
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition Pointer.h:835
friend class Block
Definition Pointer.h:1040
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:843
bool isBlockPointer() const
Definition Pointer.h:668
TypeidPointer Typeid
Definition Pointer.h:1079
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition Pointer.cpp:803
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:659
const Block * block() const
Definition Pointer.h:803
bool isFunctionPointer() const
Definition Pointer.h:670
Pointer getDeclPtr() const
Definition Pointer.h:579
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:553
PtrView view() const
Definition Pointer.h:450
const BlockPointer & asBlockPointer() const
Definition Pointer.h:651
static std::optional< std::pair< PtrView, PtrView > > computeSplitPoint(const Pointer &A, const Pointer &B)
Definition Pointer.cpp:757
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition Pointer.h:925
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:106
const Base * getBase(unsigned I) const
Definition Record.h:107
const Base * getVirtualBase(unsigned I) const
Definition Record.h:122
unsigned getNumFields() const
Definition Record.h:94
unsigned getNumVirtualBases() const
Definition Record.h:121
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
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Result
The result type of a method or function.
Definition TypeBase.h:905
U cast(CodeGen::Address addr)
Definition Address.h:327
@ None
No keyword precedes the qualified type name.
Definition TypeBase.h:5991
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:325
Block * Pointee
The block the pointer is pointing to.
Definition Pointer.h:323
Describes a memory block created by an allocation site.
Definition Descriptor.h:123
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:260
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:274
QualType getElemQualType() const
const ValueDecl * asValueDecl() const
Definition Descriptor.h:216
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:212
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition Descriptor.h:257
QualType getDataType(const ASTContext &Ctx) const
const bool IsArray
Flag indicating if the block is an array.
Definition Descriptor.h:169
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:265
const FieldDecl * asFieldDecl() const
Definition Descriptor.h:224
const VarDecl * asVarDecl() const
Definition Descriptor.h:220
PrimType getPrimType() const
Definition Descriptor.h:242
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:154
const Expr * asExpr() const
Definition Descriptor.h:213
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:277
Descriptor used for global variables.
Definition Descriptor.h:50
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:68
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition Descriptor.h:90
unsigned Offset
Offset inside the structure/array.
Definition Descriptor.h:70
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition Descriptor.h:81
QualType getPointeeType() const
Definition Pointer.h:339
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
Definition Pointer.cpp:1038
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1004
const Descriptor * getDeclDesc() const
Definition Pointer.h:83
bool allElementsInitialized() const
Definition Pointer.cpp:603
PtrView atField(unsigned Offset) const
Definition Pointer.h:253
bool isField() const
Definition Pointer.h:152
size_t elemSize() const
Definition Pointer.h:85
const Record * getRecord() const
Definition Pointer.h:145
const Descriptor * getFieldDesc() const
Definition Pointer.h:77
const FieldDecl * getField() const
Definition Pointer.h:150
bool isElementInitialized(unsigned Index) const
Definition Pointer.cpp:475
bool isBaseClass() const
Definition Pointer.h:156
void activate() const
Definition Pointer.cpp:636
bool inArray() const
Definition Pointer.h:54
void startLifetime() const
Definition Pointer.h:310
bool isInitialized() const
Definition Pointer.h:281
bool isArrayElement() const
Definition Pointer.h:212
PtrView getArray() const
Definition Pointer.h:140
unsigned getNumElems() const
Definition Pointer.h:210
InitMapPtr & getInitMap() const
Definition Pointer.h:302
InlineDescriptor * getInlineDesc() const
Definition Pointer.h:64
bool inUnion() const
Definition Pointer.h:53
void initializeElement(unsigned Index) const
Definition Pointer.cpp:575
void initialize() const
Definition Pointer.cpp:554
bool isOnePastEnd() const
Definition Pointer.h:180
bool isRoot() const
Definition Pointer.h:60
void setLifeState(Lifetime L) const
Definition Pointer.cpp:532
Lifetime getLifetime() const
Definition Pointer.cpp:513
PtrView getBase() const
Definition Pointer.h:248
bool isActive() const
Definition Pointer.h:46
PtrView expand() const
Definition Pointer.h:111
bool isVirtualBaseClass() const
Definition Pointer.h:157
bool isArrayRoot() const
Definition Pointer.h:47
T & deref() const
Definition Pointer.h:224
int64_t getIndex() const
Definition Pointer.h:198