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::optional<size_t>
442 switch (StorageKind) {
443 case Storage::Int:
444 return Int.Value + Offset;
445 case Storage::Block:
446 // See below.
447 break;
448 case Storage::Fn:
450 case Storage::Typeid:
451 return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
452 }
453
454 auto getTypeSize = [&](QualType T) -> std::optional<size_t> {
455 if (const RecordType *RT = T->getAs<RecordType>()) {
456 // We cannot get the type size of a forward declaration.
457 if (!RT->getDecl()->getDefinition())
458 return std::nullopt;
459 }
460 return ASTCtx.getTypeSizeInChars(T).getQuantity();
461 };
462
463 auto getRecordDecl = [&](PtrView P) -> const CXXRecordDecl * {
464 if (const Record *R = P.getRecord())
465 return cast<CXXRecordDecl>(R->getDecl());
466 return cast<CXXRecordDecl>(P.getFieldDesc()->asDecl());
467 };
468
469 auto getRecordSize = [&](const RecordDecl *RD) -> unsigned {
470 CanQualType RecordTy = ASTCtx.getCanonicalTagType(RD);
471 return ASTCtx.getTypeSizeInChars(RecordTy).getQuantity();
472 };
473
474 size_t Result = 0;
475 PtrView P = view();
476 while (true) {
477 if (P.isBaseClass()) {
478 const ASTRecordLayout &Layout =
480 const CXXRecordDecl *RD = getRecordDecl(P);
481 if (P.isVirtualBaseClass())
482 Result += Layout.getVBaseClassOffset(RD).getQuantity();
483 else
484 Result += Layout.getBaseClassOffset(RD).getQuantity();
485
486 if (P.isOnePastEnd())
487 Result += getRecordSize(RD);
488
489 P = P.getBase();
490 continue;
491 }
492
493 if (P.isArrayElement()) {
494 P = P.expand();
495 assert(P.getFieldDesc()->isArray());
496 if (std::optional<size_t> ElemSize =
497 getTypeSize(P.getFieldDesc()->getElemQualType()))
498 Result += *ElemSize * P.getIndex();
499 else
500 return std::nullopt;
501
502 P = P.getArray();
503 continue;
504 }
505
506 if (P.isRoot()) {
507 if (P.isPastEnd() || P.isOnePastEnd()) {
508 if (std::optional<size_t> Size =
509 getTypeSize(P.getDeclDesc()->getType()))
510 Result += *Size * P.getIndex();
511 else
512 return std::nullopt;
513 }
514 break;
515 }
516
517 assert(P.getField());
518 const FieldDecl *F = P.getField();
519 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(F->getParent());
520 Result +=
522 .getQuantity();
523
524 if (P.isPastEnd() || P.isOnePastEnd()) {
525 if (std::optional<size_t> Size = getTypeSize(F->getType()))
526 Result += *Size * P.getIndex();
527 else
528 return std::nullopt;
529 }
530
531 P = P.getBase();
532 if (P.isRoot())
533 break;
534 }
535 return Result;
536}
537
538std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
539 if (isZero())
540 return "nullptr";
541
542 if (isIntegralPointer())
543 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
544
545 QualType Ty = getType();
546 if (Ty->isLValueReferenceType())
547 Ty = Ty->getPointeeType();
548 return toAPValue(Ctx).getAsString(Ctx, Ty);
549}
550
552 if (!isBlockPointer())
553 return true;
554
555 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
556 Offset == BS.Base) {
557 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
559 }
560
561 assert(BS.Pointee && "Cannot check if null pointer was initialized");
562 const Descriptor *Desc = getFieldDesc();
563 assert(Desc);
564 if (Desc->isPrimitiveArray())
566
567 if (asBlockPointer().Base == 0)
568 return true;
569 // Field has its bit in an inline descriptor.
570 return getInlineDesc()->IsInitialized;
571}
572
573bool PtrView::isElementInitialized(unsigned Index) const {
574 const Descriptor *Desc = getFieldDesc();
575 assert(Desc);
576
577 if (Pointee->isStatic() && Base == 0)
578 return true;
579
580 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
581 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
583 }
584
585 if (Desc->isPrimitiveArray()) {
586 InitMapPtr IM = getInitMap();
587
588 if (IM.allInitialized())
589 return true;
590
591 if (!IM.hasInitMap())
592 return false;
593 return IM->isElementInitialized(Index);
594 }
595 return isInitialized();
596}
597
598bool Pointer::isElementAlive(unsigned Index) const {
599 assert(getFieldDesc()->isPrimitiveArray());
600
601 InitMapPtr &IM = getInitMap();
602 if (!IM.hasInitMap())
603 return true;
604
605 if (IM.allInitialized())
606 return true;
607
608 return IM->isElementAlive(Index);
609}
610
612 if (Base < sizeof(InlineDescriptor))
613 return Lifetime::Started;
614
615 if (inArray() && !isArrayRoot()) {
616 InitMapPtr &IM = getInitMap();
617
618 if (!IM.hasInitMap()) {
619 if (IM.allInitialized())
620 return Lifetime::Started;
621 return getArray().getLifetime();
622 }
623
625 }
626
627 return getInlineDesc()->LifeState;
628}
629
631 if (Base < sizeof(InlineDescriptor))
632 return;
633
634 if (inArray() && !isArrayRoot()) {
635 assert(L == Lifetime::Started || L == Lifetime::Ended);
636 const Descriptor *Desc = getFieldDesc();
637 InitMapPtr &IM = getInitMap();
638 if (!IM.hasInitMap())
639 IM.setInitMap(new InitMap(Desc->getNumElems(), IM.allInitialized()));
640
641 if (L == Lifetime::Ended)
643 else if (L == Lifetime::Started)
645 assert(isArrayRoot() || (this->getLifetime() == L));
646 return;
647 }
648
650}
651
653 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
654 auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
656 return;
657 }
658
659 const Descriptor *Desc = getFieldDesc();
660 assert(Desc);
661 if (Desc->isPrimitiveArray()) {
662 if (Desc->getNumElems() != 0)
664 return;
665 }
666
667 // Field has its bit in an inline descriptor.
668 assert(Base != 0 && "Only composite fields can be initialised");
671}
672
673void PtrView::initializeElement(unsigned Index) const {
674 // Primitive global arrays don't have an initmap.
675 if (Pointee->isStatic() && Base == 0)
676 return;
677
678 assert(Index < getFieldDesc()->getNumElems());
679
680 InitMapPtr &IM = getInitMap();
681 if (IM.allInitialized())
682 return;
683
684 if (!IM.hasInitMap()) {
685 const Descriptor *Desc = getFieldDesc();
686 IM.setInitMap(new InitMap(Desc->getNumElems()));
687 }
688 assert(IM.hasInitMap());
689
690 if (IM->initializeElement(Index))
692}
693
695 assert(getFieldDesc()->isPrimitiveArray());
696 assert(isArrayRoot());
697
698 getInitMap().noteAllInitialized();
699}
700
702 assert(getFieldDesc()->isPrimitiveArray());
703 assert(isArrayRoot());
704
705 if (Pointee->isStatic() && Base == 0)
706 return true;
707
708 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
709 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
711 }
712
713 InitMapPtr IM = getInitMap();
714 return IM.allInitialized();
715}
716
718 assert(getFieldDesc()->isPrimitiveArray());
719 assert(isArrayRoot());
720
721 if (isStatic() && BS.Base == 0)
722 return true;
723
724 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
725 Offset == BS.Base) {
726 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
728 }
729
730 InitMapPtr &IM = getInitMap();
731 return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive());
732}
733
734void PtrView::activate() const {
735 // Field has its bit in an inline descriptor.
736 assert(Base != 0 && "Only composite fields can be activated");
737
738 if (isRoot() && Base == sizeof(GlobalInlineDescriptor))
739 return;
740 if (!getInlineDesc()->InUnion)
741 return;
742
744 activate = [&activate](PtrView P) -> void {
745 P.getInlineDesc()->IsActive = true;
746 P.startLifetime();
747 if (const Record *R = P.getRecord(); R && !R->isUnion()) {
748 for (const Record::Field &F : R->fields()) {
749 PtrView FieldPtr = P.atField(F.Offset);
750 if (!FieldPtr.getInlineDesc()->IsActive)
751 activate(FieldPtr);
752 }
753 // FIXME: Bases?
754 }
755 };
756
757 std::function<void(PtrView &)> deactivate;
758 deactivate = [&deactivate](PtrView &P) -> void {
759 P.getInlineDesc()->IsActive = false;
760
761 if (const Record *R = P.getRecord()) {
762 for (const Record::Field &F : R->fields()) {
763 PtrView FieldPtr = P.atField(F.Offset);
764 if (FieldPtr.getInlineDesc()->IsActive)
765 deactivate(FieldPtr);
766 }
767 // FIXME: Bases?
768 }
769 };
770
771 PtrView B = *this;
772 // Primitive array elements can't be activated individually, so
773 // look at the array root instead.
775 B = B.getArray();
776
777 while (!B.isRoot() && B.inUnion()) {
778 activate(B);
779
780 // When walking up the pointer chain, deactivate
781 // all union child pointers that aren't on our path.
782 PtrView Cur = B;
783 B = B.getBase();
784 if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
785 for (const Record::Field &F : BR->fields()) {
786 PtrView FieldPtr = B.atField(F.Offset);
787 if (FieldPtr != Cur)
788 deactivate(FieldPtr);
789 }
790 }
791 }
792}
793
794bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
795 // Two null pointers always have the same base.
796 if (A.isZero() && B.isZero())
797 return true;
798
800 return true;
802 return true;
803 if (A.isTypeidPointer() && B.isTypeidPointer())
805
806 if (A.StorageKind != B.StorageKind)
807 return false;
808
810}
811
812bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
813 if (!A.isBlockPointer() || !B.isBlockPointer())
814 return false;
815 return A.block() == B.block();
816}
817
818bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
819 return hasSameBase(A, B) && A.BS.Base == B.BS.Base &&
821}
822
824 if (isZero() || !isBlockPointer())
825 return false;
826
827 if (block()->isDynamic())
828 return false;
829
830 const Expr *E = block()->getDescriptor()->asExpr();
832}
833
835 if (isZero() || !isBlockPointer())
836 return false;
837
838 if (block()->isDynamic())
839 return false;
840
841 const Expr *E = block()->getDescriptor()->asExpr();
842 return isa_and_nonnull<StringLiteral>(E);
843}
844
846 if (isZero() || !isBlockPointer())
847 return false;
848
849 if (const Expr *E = BS.Pointee->getDescriptor()->asExpr())
850 return isa<AddrLabelExpr>(E);
851 return false;
852}
853
854std::optional<std::pair<PtrView, PtrView>>
856 if (!A.isBlockPointer() || !B.isBlockPointer())
857 return std::nullopt;
858
860 return std::nullopt;
861 if (A.isRoot() && B.isRoot())
862 return std::nullopt;
863
864 if (A == B)
865 return std::make_pair(A.view(), B.view());
866
867 auto getBase = [](PtrView P) -> PtrView {
868 if (P.isArrayElement())
869 return P.expand().getArray();
870 return P.getBase();
871 };
872
873 PtrView IterA = A.view();
874 PtrView IterB = B.view();
875 PtrView CurA = IterA;
876 PtrView CurB = IterB;
877 for (;;) {
878 if (IterA.Base > IterB.Base) {
879 CurA = IterA;
880 IterA = getBase(IterA);
881 } else {
882 CurB = IterB;
883 IterB = getBase(IterB);
884 }
885
886 if (IterA == IterB) {
887 // If the Iter is an array, CurA and CurB are both elements of the same
888 // array. That is fine, so return nullopt.
889 if (IterA.getFieldDesc()->isArray())
890 return std::nullopt;
891 return std::make_pair(CurA, CurB);
892 }
893
894 if (IterA.isRoot() && IterB.isRoot())
895 return std::nullopt;
896 }
897
898 llvm_unreachable("The loop above should've returned.");
899}
900
901std::optional<APValue> Pointer::toRValue(const Context &Ctx,
902 QualType ResultType) const {
903 const ASTContext &ASTCtx = Ctx.getASTContext();
904 assert(!ResultType.isNull());
905 // Method to recursively traverse composites.
906 std::function<bool(QualType, PtrView, APValue &)> Composite;
907 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, PtrView Ptr,
908 APValue &R) {
909 if (const auto *AT = Ty->getAs<AtomicType>())
910 Ty = AT->getValueType();
911
912 // Invalid pointers.
913 if (Ptr.isDummy() || !Ptr.isLive() || Ptr.isPastEnd())
914 return false;
915
916 // Primitives should never end up here.
917 assert(!Ctx.canClassify(Ty));
918 const Descriptor *FieldDesc = Ptr.getFieldDesc();
919 assert(FieldDesc);
920
921 if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
922 if (!FieldDesc->isRecord())
923 return false;
924 const auto *Record = Ptr.getRecord();
925 assert(Record && "Missing record descriptor");
926
927 bool Ok = true;
928 if (RT->getDecl()->isUnion()) {
929 const FieldDecl *ActiveField = nullptr;
931 for (const auto &F : Record->fields()) {
932 PtrView FP = Ptr.atField(F.Offset);
933 if (FP.isActive()) {
934 const Descriptor *Desc = F.Desc;
935 if (Desc->isPrimitive()) {
936 TYPE_SWITCH(Desc->getPrimType(),
937 Value = FP.deref<T>().toAPValue(ASTCtx));
938 } else {
939 QualType FieldTy = F.Decl->getType();
940 Ok &= Composite(FieldTy, FP, Value);
941 }
942 ActiveField = FP.getFieldDesc()->asFieldDecl();
943 break;
944 }
945 }
946 R = APValue(ActiveField, Value);
947 } else {
948 unsigned NF = Record->getNumFields();
949 unsigned NB = Record->getNumBases();
950 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
951
952 R = APValue(APValue::UninitStruct(), NB, NF);
953
954 for (unsigned I = 0; I != NF; ++I) {
955 const Record::Field *FD = Record->getField(I);
956 const Descriptor *Desc = FD->Desc;
957 PtrView FP = Ptr.atField(FD->Offset);
958 APValue &Value = R.getStructField(I);
959 if (Desc->isPrimitive()) {
960 TYPE_SWITCH(Desc->getPrimType(),
961 Value = FP.deref<T>().toAPValue(ASTCtx));
962 } else {
963 QualType FieldTy = FD->Decl->getType();
964 Ok &= Composite(FieldTy, FP, Value);
965 }
966 }
967
968 for (unsigned I = 0; I != NB; ++I) {
969 const Record::Base *BD = Record->getBase(I);
970 QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
971 PtrView BP = Ptr.atField(BD->Offset);
972 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
973 }
974
975 for (unsigned I = 0; I != NV; ++I) {
976 const Record::Base *VD = Record->getVirtualBase(I);
977 assert(VD);
978 QualType VirtBaseTy =
979 Ctx.getASTContext().getCanonicalTagType(VD->Decl);
980 PtrView VP = Ptr.atField(VD->Offset);
981 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
982 }
983 }
984 return Ok;
985 }
986
987 if (Ty->isIncompleteArrayType()) {
988 R = APValue(APValue::UninitArray(), 0, 0);
989 return true;
990 }
991
992 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
993 if (!FieldDesc->isArray())
994 return false;
995 const size_t NumElems = Ptr.getNumElems();
996 QualType ElemTy = AT->getElementType();
997 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
998
999 bool Ok = true;
1000 OptPrimType ElemT = Ctx.classify(ElemTy);
1001 for (unsigned I = 0; I != NumElems; ++I) {
1002 APValue &Slot = R.getArrayInitializedElt(I);
1003 if (ElemT) {
1004 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
1005 } else {
1006 Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
1007 }
1008 }
1009 return Ok;
1010 }
1011
1012 // Complex types.
1013 if (Ty->isAnyComplexType()) {
1014 // Can happen via C casts.
1015 if (!FieldDesc->getType()->isAnyComplexType())
1016 return false;
1017
1018 PrimType ElemT = FieldDesc->getPrimType();
1019 if (isIntegerOrBoolType(ElemT)) {
1020 INT_TYPE_SWITCH(ElemT, {
1021 auto V1 = Ptr.elem<T>(0);
1022 auto V2 = Ptr.elem<T>(1);
1023 R = APValue(V1.toAPSInt(), V2.toAPSInt());
1024 return true;
1025 });
1026 } else if (ElemT == PT_Float) {
1027 R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
1028 Ptr.elem<Floating>(1).getAPFloat());
1029 return true;
1030 }
1031 return false;
1032 }
1033
1034 // Vector types.
1035 if (const auto *VT = Ty->getAs<VectorType>()) {
1036 if (!FieldDesc->isPrimitiveArray())
1037 return false;
1038
1039 PrimType ElemT = FieldDesc->getPrimType();
1040 SmallVector<APValue> Values;
1041 Values.reserve(VT->getNumElements());
1042 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
1043 TYPE_SWITCH(ElemT,
1044 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1045 }
1046
1047 assert(Values.size() == VT->getNumElements());
1048 R = APValue(Values.data(), Values.size());
1049 return true;
1050 }
1051
1052 // Constant Matrix types.
1053 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
1054 if (!FieldDesc->isPrimitiveArray())
1055 return false;
1056 PrimType ElemT = FieldDesc->getPrimType();
1057 unsigned NumElems = MT->getNumElementsFlattened();
1058
1059 SmallVector<APValue> Values;
1060 Values.reserve(NumElems);
1061 for (unsigned I = 0; I != NumElems; ++I) {
1062 TYPE_SWITCH(ElemT,
1063 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1064 }
1065
1066 R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
1067 return true;
1068 }
1069
1070 llvm_unreachable("invalid value to return");
1071 };
1072
1073 // Can't return functions as rvalues.
1074 if (ResultType->isFunctionType())
1075 return std::nullopt;
1076
1077 // Invalid to read from.
1078 if (isDummy() || !isLive() || isPastEnd() ||
1079 (isOnePastEnd() && !isZeroSizeArray()))
1080 return std::nullopt;
1081
1082 // We can return these as rvalues, but we can't deref() them.
1083 if (isZero() || isIntegralPointer())
1084 return toAPValue(ASTCtx);
1085
1086 // Just load primitive types.
1087 if (OptPrimType T = Ctx.classify(ResultType)) {
1088 if (!canDeref(*T))
1089 return std::nullopt;
1090 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
1091 }
1092
1093 // Return the composite type.
1095 if (!Composite(ResultType, view(), Result))
1096 return std::nullopt;
1097 return Result;
1098}
1099
1101 if (isBlockPointer())
1102 return getDeclDesc()->asVarDecl();
1103 return nullptr;
1104}
1105
1106std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx,
1107 unsigned Offset) const {
1108 QualType CurType = getPointeeType();
1109 if (CurType.isNull() || !CurType->isRecordType())
1110 return std::nullopt;
1111
1112 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1113 if (!R)
1114 return *this;
1115
1116 const Record::Field *F = nullptr;
1117 for (auto &It : R->fields()) {
1118 if (It.Offset == Offset) {
1119 F = &It;
1120 break;
1121 }
1122 }
1123 if (!F)
1124 return *this;
1125
1126 const FieldDecl *FD = F->Decl;
1127 if (FD->getParent()->isInvalidDecl())
1128 return std::nullopt;
1129
1130 const ASTContext &ASTCtx = Ctx.getASTContext();
1131 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
1132 unsigned FieldIndex = FD->getFieldIndex();
1133 uint64_t FieldOffset =
1134 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
1135 .getQuantity();
1136
1137 return IntPointer{FD->getType().getTypePtr(), this->Value + FieldOffset};
1138}
1139
1141 unsigned BaseOffset) const {
1142 if (!Ty)
1143 return *this;
1144
1145 QualType CurType = getPointeeType();
1146 if (CurType.isNull() || !CurType->isRecordType())
1147 return *this;
1148
1149 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1150 const Descriptor *BaseDesc = nullptr;
1151
1152 // This iterates over bases and checks for the proper offset. That's
1153 // potentially slow but this case really shouldn't happen a lot.
1154 for (const Record::Base &B : R->bases()) {
1155 if (B.Offset == BaseOffset) {
1156 BaseDesc = B.Desc;
1157 break;
1158 }
1159 }
1160 assert(BaseDesc);
1161
1162 // Adjust the offset value based on the information from the record layout.
1163 const ASTContext &ASTCtx = Ctx.getASTContext();
1164 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
1165 CharUnits BaseLayoutOffset =
1166 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
1167
1168 const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
1170 std::nullopt, RD, false);
1171 return {T.getTypePtr(), Value + BaseLayoutOffset.getQuantity()};
1172}
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: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.
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: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:3195
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3280
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3431
Represents a function declaration or definition.
Definition Decl.h:2027
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:4360
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition Decl.h:4544
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:932
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:776
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:107
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:464
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:794
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:551
bool pointsToLabel() const
Whether this points to a block created for an AddrLabelExpr.
Definition Pointer.cpp:845
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:1100
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:857
FunctionPointer Fn
Definition Pointer.h:1089
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:318
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:694
bool pointsToStringLiteral() const
Definition Pointer.cpp:834
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:615
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:522
bool isElementAlive(unsigned Index) const
Definition Pointer.cpp:598
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition Pointer.cpp:823
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Compute the pointer offset as given by the ASTRecordLayout.
Definition Pointer.cpp:441
bool allElementsAlive() const
Definition Pointer.cpp:717
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:538
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:812
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
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition Pointer.cpp:818
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
friend class Block
Definition Pointer.h:1051
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:1090
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition Pointer.cpp:901
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
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:855
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: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.
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: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: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: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
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:279
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:350
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
Definition Pointer.cpp:1140
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1106
const Descriptor * getDeclDesc() const
Definition Pointer.h:87
bool allElementsInitialized() const
Definition Pointer.cpp:701
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:573
bool isBaseClass() const
Definition Pointer.h:167
void activate() const
Definition Pointer.cpp:734
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:673
void initialize() const
Definition Pointer.cpp:652
bool isOnePastEnd() const
Definition Pointer.h:191
bool isRoot() const
Definition Pointer.h:60
void setLifeState(Lifetime L) const
Definition Pointer.cpp:630
Lifetime getLifetime() const
Definition Pointer.cpp:611
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