clang 24.0.0git
Pointer.h
Go to the documentation of this file.
1//===--- Pointer.h - 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// Defines the classes responsible for pointer tracking.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CLANG_AST_INTERP_POINTER_H
14#define LLVM_CLANG_AST_INTERP_POINTER_H
15
16#include "Block.h"
17#include "Descriptor.h"
18#include "Function.h"
19#include "InitMap.h"
21#include "clang/AST/Decl.h"
22#include "clang/AST/DeclCXX.h"
23#include "clang/AST/Expr.h"
24#include "llvm/Support/raw_ostream.h"
25
26namespace clang {
27namespace interp {
28class Block;
29class DeadBlock;
30class Pointer;
31class Context;
32
33class Pointer;
34inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);
35
36struct PtrView {
37 static constexpr unsigned PastEndMark = ~0u;
38
40 unsigned Base;
41 uint64_t Offset;
42
43 bool isZero() const { return !Pointee; }
44 bool isLive() const { return Pointee && !Pointee->isDead(); }
45 bool isActive() const { return isRoot() || getInlineDesc()->IsActive; }
46 bool isArrayRoot() const { return inArray() && Offset == Base; }
47 bool isElementPastEnd() const { return Offset == PastEndMark; }
48 bool isZeroSizeArray() const { return getFieldDesc()->isZeroSizeArray(); }
49 bool isMutable() const {
50 return !isRoot() && getInlineDesc()->IsFieldMutable;
51 }
52 bool isExtern() const { return Pointee && Pointee->isExtern(); }
53 bool isVolatile() const {
55 }
56 bool inUnion() const { return getInlineDesc()->InUnion; };
57 bool inArray() const { return getFieldDesc()->IsArray; }
58 bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
59 bool canBeInitialized() const { return Pointee; }
60 const Block *block() const { return Pointee; }
61
62 unsigned getEvalID() { return Pointee->getEvalID(); }
63
64 bool isRoot() const { return Base == 0; }
65
66 bool isConst() const {
68 }
69
72 assert(Base != 0);
73 return getDescriptor(Base);
74 }
75
77 assert(Offset != 0 && "Not a nested pointer");
78 assert(Offset >= sizeof(InlineDescriptor));
79 return reinterpret_cast<InlineDescriptor *>(Pointee->data() + Offset) - 1;
80 }
81
82 const Descriptor *getFieldDesc() const {
83 if (isRoot())
84 return Pointee->getDescriptor();
85 return getInlineDesc()->Desc;
86 }
87
88 const Descriptor *getDeclDesc() const { return Pointee->getDescriptor(); }
89
90 size_t elemSize() const { return getFieldDesc()->getElemSize(); }
91
92 [[nodiscard]] PtrView narrow() const {
93 // Null pointers cannot be narrowed.
94 if (isZero() || isUnknownSizeArray())
95 return *this;
96
97 if (inArray()) {
98 // Pointer is one past end - magic offset marks that.
99 if (isOnePastEnd())
101
102 if (Offset != Base) {
103 // If we're pointing to a primitive array element, there's nothing to
104 // do.
105 if (inPrimitiveArray())
106 return *this;
107 // Pointer is to a composite array element - enter it.
108 return PtrView{Pointee, static_cast<unsigned>(Offset), Offset};
109 }
110 }
111 // Otherwise, we're pointing to a non-array element or
112 // are already narrowed to a composite array element. Nothing to do.
113 return *this;
114 }
115
116 [[nodiscard]] PtrView expand() const {
117 if (isElementPastEnd()) {
118 // Revert to an outer one-past-end pointer.
119 unsigned Adjust;
120 if (inPrimitiveArray())
121 Adjust = sizeof(InitMapPtr);
122 else
123 Adjust = sizeof(InlineDescriptor);
124 return PtrView{Pointee, Base, Base + getSize() + Adjust};
125 }
126
127 // Do not step out of array elements.
128 if (Base != Offset)
129 return *this;
130
131 if (isRoot())
132 return PtrView{Pointee, Base, Base};
133
134 // Step into the containing array, if inside one.
135 unsigned Next = Base - getInlineDesc()->Offset;
136 const Descriptor *Desc =
137 (Next == 0) ? getDeclDesc() : getDescriptor(Next)->Desc;
138 if (!Desc->IsArray)
139 return *this;
140 return PtrView{Pointee, Next, Offset};
141 }
142
143 [[nodiscard]] PtrView stripBaseCasts() const {
144 PtrView V = *this;
145 while (V.isBaseClass())
146 V = V.getBase();
147 return V;
148 }
149
150 [[nodiscard]] PtrView getArray() const {
151 assert(Offset != Base && "not an array element");
152 return PtrView{Pointee, Base, Base};
153 }
154
155 const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
156 const Record *getElemRecord() const {
157 const Descriptor *ElemDesc = getFieldDesc()->ElemDesc;
158 return ElemDesc ? ElemDesc->ElemRecord : nullptr;
159 }
160 const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
161
162 bool isField() const {
163 return !isZero() && !isRoot() && getFieldDesc()->asDecl();
164 }
165
166 bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
167 bool isVirtualBaseClass() const {
168 return isField() && getInlineDesc()->IsVirtualBase;
169 }
170 bool isUnknownSizeArray() const {
172 }
173
174 bool isPastEnd() const { return Offset > Pointee->getSize(); }
175
176 unsigned getOffset() const {
177 assert(Offset != PastEndMark);
178
179 unsigned Adjust = 0;
180 if (Offset != Base) {
181 if (getFieldDesc()->ElemDesc)
182 Adjust = sizeof(InlineDescriptor);
183 else
184 Adjust = sizeof(InitMapPtr);
185 }
186 return Offset - Base - Adjust;
187 }
188 size_t getSize() const { return getFieldDesc()->getSize(); }
189
190 bool isOnePastEnd() const {
191 if (!Pointee)
192 return false;
193
194 const Descriptor *Desc = getFieldDesc();
195 if (Desc->isUnknownSizeArray())
196 return false;
197
198 if (isPastEnd())
199 return true;
200
201 if (Offset != Base) {
202 unsigned Adjust =
203 Desc->ElemDesc ? sizeof(InlineDescriptor) : sizeof(InitMapPtr);
204 unsigned Off = Offset - Base - Adjust;
205 return Desc->getSize() == Off;
206 }
207
208 return Desc->getSize() == 0;
209 }
210
211 PtrView atIndex(unsigned Idx) const {
212 unsigned Off = Idx * elemSize();
213 if (getFieldDesc()->ElemDesc)
214 Off += sizeof(InlineDescriptor);
215 else
216 Off += sizeof(InitMapPtr);
217 return PtrView{Pointee, Base, Base + Off};
218 }
219
220 int64_t getIndex() const {
221 if (isZero())
222 return 0;
223 // narrow()ed element in a composite array.
224 if (Base != 0 && Base == Offset)
225 return 0;
226
227 if (auto ElemSize = elemSize())
228 return getOffset() / ElemSize;
229 return 0;
230 }
231
232 unsigned getNumElems() const { return getSize() / elemSize(); }
233
234 bool isArrayElement() const {
235 if (inArray() && Base != Offset)
236 return true;
237
238 // Might be a narrow()'ed element in a composite array.
239 // Check the inline descriptor.
240 if (Base != 0 && getInlineDesc()->IsArrayElement)
241 return true;
242
243 return false;
244 }
245
246 template <typename T> T &deref() const {
247 assert(isLive() && "Invalid pointer");
248 assert(Pointee);
249
250 if (isArrayRoot())
251 return *reinterpret_cast<T *>(Pointee->data() + Base +
252 sizeof(InitMapPtr));
253
254 return *reinterpret_cast<T *>(Pointee->data() + Offset);
255 }
256
257 template <typename T> T &elem(unsigned I) const {
258 assert(isLive() && "Invalid pointer");
259 assert(Pointee);
260 assert(getFieldDesc()->isPrimitiveArray());
261 assert(I < getFieldDesc()->getNumElems());
262
263 unsigned ElemByteOffset = I * getFieldDesc()->getElemSize();
264 unsigned ReadOffset = Base + sizeof(InitMapPtr) + ElemByteOffset;
265 assert(ReadOffset + sizeof(T) <= Pointee->getSize());
266
267 return *reinterpret_cast<T *>(Pointee->data() + ReadOffset);
268 }
269
270 [[nodiscard]] PtrView getBase() const {
271 unsigned NewBase = Base - getInlineDesc()->Offset;
272 return PtrView{Pointee, NewBase, NewBase};
273 }
274
275 [[nodiscard]] PtrView atField(unsigned Offset) const {
276 unsigned F = this->Offset + Offset;
277 return PtrView{Pointee, F, F};
278 }
279
281 if (isRoot() && Base == Offset) {
282 // If this pointer points to the root of a declaration, try to consult
283 // the ValueDecl directly, since that has a type with more information,
284 // e.g. the correct ElaboratedTypeKeyword.
285 if (const ValueDecl *VD = getDeclDesc()->asValueDecl())
286 return VD->getType();
287 return getDeclDesc()->getType();
288 }
289 if (inPrimitiveArray() && Offset != Base) {
290 // Unfortunately, complex and vector types are not array types in clang,
291 // but they are for us.
292 if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
293 return AT->getElementType();
294 if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>())
295 return CT->getElementType();
296 if (const auto *CT = getFieldDesc()->getType()->getAs<VectorType>())
297 return CT->getElementType();
298 }
299
300 return getFieldDesc()->getType();
301 }
302
303 bool isInitialized() const {
304 if (!Pointee->isInitialized())
305 return false;
306
307 if (Offset == 0) {
308 if (Pointee->isGlobal()) {
309 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
311 }
312 if (Pointee->isLocal()) {
313 const auto &LD = Pointee->getBlockDesc<InlineDescriptor>();
314 return LD.IsInitialized;
315 }
316 return true;
317 }
318
319 assert(Pointee && "Cannot check if null pointer was initialized");
320 const Descriptor *Desc = getFieldDesc();
321 assert(Desc);
322 if (Offset != Base && Desc->isPrimitiveArray())
324
325 // Field has its bit in an inline descriptor.
327 }
328
329 void initializeElement(unsigned Index) const;
330 bool allElementsInitialized() const;
331 bool isElementInitialized(unsigned Index) const;
333 return *reinterpret_cast<InitMapPtr *>(Pointee->data() + Base);
334 }
335 void initialize() const;
336 void activate() const;
337
338 void setLifeState(Lifetime L) const;
339 Lifetime getLifetime() const;
342
343 bool operator==(const PtrView &Other) const {
344 return Other.Pointee == Pointee && Base == Other.Base &&
345 Offset == Other.Offset;
346 }
347
348 bool operator!=(const PtrView &Other) const { return !(Other == *this); }
349};
350
352 /// The block the pointer is pointing to.
354 /// Start of the current subfield.
355 unsigned Base;
356 /// Previous link in the pointer chain.
358 /// Next link in the pointer chain.
360};
361
363 llvm::PointerIntPair<const Type *, 1, bool> TypeAndIsNull;
364 uint64_t Value;
365
366 std::optional<IntPointer> atOffset(const Context &Ctx, unsigned Offset) const;
367 IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const;
368
369 const Type *getType() const { return TypeAndIsNull.getPointer(); }
370 bool isNull() const { return TypeAndIsNull.getInt(); }
371
373 if (!getType())
374 return QualType();
375
376 QualType QT(getType(), 0);
377 if (QT->isPointerOrReferenceType())
378 QT = QT->getPointeeType();
379 else if (QT->isArrayType())
381
382 return QT.IgnoreParens();
383 }
384};
385
388};
389
391 const Type *TypePtr;
393};
394
396 const Expr *Base = nullptr;
397 unsigned ID = 0;
398 bool Decayed = false;
399
400 StringPointer decay() const { return StringPointer{Base, ID, true}; }
401 const StringLiteral *getLiteral() const {
402 if (const auto *PE = dyn_cast<PredefinedExpr>(Base))
403 return PE->getFunctionName();
405 }
406};
407
409 enum { Base, Field, Array, NegativeArray } Kind;
410 union {
411 uint64_t Index;
412 const FieldDecl *FD;
413 llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> RD = {};
414 };
415
416 static PointerPathEntry base(const CXXRecordDecl *RD, bool Virtual = false) {
418 E.Kind = Base;
419 E.RD = {RD, Virtual};
420 return E;
421 }
422
423 static PointerPathEntry array(int64_t Index) {
425 E.Kind = Array;
426 E.Index = Index;
427 return E;
428 }
429
433 E.Index = Index;
434 return E;
435 }
436
439 E.Kind = Field;
440 E.FD = FD;
441 return E;
442 }
443};
444
447 // FieldType and IsOnePastEnd/IsConstexprUnknown bits.
448 llvm::PointerIntPair<const Type *, 2, unsigned> FieldType = {};
449 const PointerPathEntry *Path = nullptr;
450 unsigned PathLength = 0;
451
453 bool hasDeclBase() const { return Base.isDecl(); }
454 const ValueDecl *getBaseDecl() const { return Base.asValueDecl(); }
455 const VarDecl *getBaseVarDecl() const { return Base.asVarDecl(); }
456 const Expr *getBaseExpr() const { return Base.asExpr(); }
457 bool hasValidBase() const;
458
460 withFieldType(const Type *FieldTy,
461 std::optional<bool> PastEnd = std::nullopt) const {
462 unsigned NewBitFieldValue = FieldType.getInt();
463 if (PastEnd)
464 NewBitFieldValue =
465 (isConstexprUnknown() ? 2u : 0u) + static_cast<unsigned>(*PastEnd);
466 return OpaquePointer{Base, {FieldTy, NewBitFieldValue}, Path, PathLength};
467 }
468
470 const Type *FieldTy,
471 std::optional<bool> PastEnd = std::nullopt) const {
472 unsigned NewBitFieldValue = FieldType.getInt();
473 if (PastEnd)
474 NewBitFieldValue =
475 (isConstexprUnknown() ? 2u : 0u) + static_cast<unsigned>(*PastEnd);
476 return OpaquePointer{Base, {FieldTy, NewBitFieldValue}, Path, PathLength};
477 }
478
479 OpaquePointer withPastEnd(bool PastEnd) const {
480 return OpaquePointer{Base,
481 {FieldType.getPointer(),
482 FieldType.getInt() | static_cast<unsigned>(PastEnd)},
483 Path,
484 PathLength};
485 }
486
488 QualType T = Base.getType();
489 if (T->isPointerOrReferenceType())
490 return T->getPointeeType();
491 return T;
492 }
493
495 if (FieldType.getPointer()->isPointerOrReferenceType() && Base.isDecl())
496 return FieldType.getPointer()->getPointeeType();
497 return QualType(FieldType.getPointer(), 0);
498 }
499
500 bool isArrayElement() const {
501 return PathLength != 0 &&
503 }
504
505 std::optional<size_t> computeLayoutOffset(const ASTContext &ASTCtx) const;
506 /// If this is pointing to an array element, return the array.
508
509 bool isOnePastEnd() const { return FieldType.getInt() & 1u; }
510 bool isOnePastEndOrElementPastEnd() const;
511 bool isConstexprUnknown() const { return FieldType.getInt() & 2u; }
512 bool isUnknownSizeArray() const;
513 bool isRoot() const;
514};
515
516enum class Storage { Int, Block, Fn, Typeid, String, Opaque };
517
518/// A pointer to a memory block, live or dead.
519///
520/// This object can be allocated into interpreter stack frames. If pointing to
521/// a live block, it is a link in the chain of pointers pointing to the block.
522///
523/// In the simplest form, a Pointer has a Block* (the pointee) and both Base
524/// and Offset are 0, which means it will point to raw data.
525///
526/// The Base field is used to access metadata about the data. For primitive
527/// arrays, the Base is followed by an InitMap. In a variety of cases, the
528/// Base is preceded by an InlineDescriptor, which is used to track the
529/// initialization state, among other things.
530///
531/// The Offset field is used to access the actual data. In other words, the
532/// data the pointer decribes can be found at
533/// Pointee->data() + Pointer.Offset.
534///
535/// \verbatim
536/// Pointee Offset
537/// │ │
538/// │ │
539/// ▼ ▼
540/// ┌───────┬────────────┬─────────┬────────────────────────────┐
541/// │ Block │ InlineDesc │ InitMap │ Actual Data │
542/// └───────┴────────────┴─────────┴────────────────────────────┘
543/// ▲
544/// │
545/// │
546/// Base
547/// \endverbatim
548class Pointer {
549public:
550 Pointer() : StorageKind(Storage::Int), Int{{nullptr, true}, 0} {}
552 : StorageKind(Storage::Int), Int(std::move(IntPtr)) {}
553 Pointer(Block *B);
554 Pointer(Block *B, uint64_t BaseAndOffset);
555 Pointer(const Pointer &P);
556 Pointer(Pointer &&P);
557 Pointer(uint64_t Address, const Type *Ty, uint64_t Offset = 0,
558 std::optional<bool> IsNull = std::nullopt)
559 : Offset(Offset), StorageKind(Storage::Int),
560 Int{{Ty, IsNull.value_or(Address == 0)}, Address} {}
561 Pointer(const Function *F, uint64_t Offset = 0)
562 : Offset(Offset), StorageKind(Storage::Fn), Fn{F} {}
563 Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
564 : Offset(Offset), StorageKind(Storage::Typeid) {
565 Typeid.TypePtr = TypePtr;
566 Typeid.TypeInfoType = TypeInfoType;
567 }
568 Pointer(const Expr *Base, unsigned Id)
569 : Offset(0), StorageKind(Storage::String), Str{Base, Id} {}
570 Pointer(StringPointer Str, uint64_t Offset = 0)
571 : Offset(Offset), StorageKind(Storage::String), Str(Str) {}
572
573 Pointer(DeclOrExpr DOE, bool ConstexprUnknown = false)
574 : Offset(0), StorageKind(Storage::Opaque) {
575 Opaque.Base = DOE;
576 Opaque.FieldType = {DOE.getType().getTypePtr(), ConstexprUnknown ? 2u : 0u};
577 Opaque.Path = nullptr;
578 Opaque.PathLength = 0;
579 }
580 Pointer(OpaquePointer OP, uint64_t Offset = 0)
581 : Offset(Offset), StorageKind(Storage::Opaque), Opaque(OP) {}
582
583 Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
584 explicit Pointer(PtrView V) : Pointer(V.Pointee, V.Base, V.Offset) {}
585 ~Pointer();
586
587 Pointer &operator=(const Pointer &P);
588 Pointer &operator=(Pointer &&P);
589
590 bool operator==(const Pointer &P) const;
591 bool operator!=(const Pointer &P) const { return !(P == *this); }
592
593 /// Converts the pointer to an APValue.
594 APValue toAPValue(const ASTContext &ASTCtx) const;
595
596 /// Converts the pointer to a string usable in diagnostics.
597 std::string toDiagnosticString(const ASTContext &Ctx) const;
598
599 uint64_t getIntegerRepresentation() const {
600 if (isIntegralPointer())
601 return Int.Value + (Offset * elemSize());
602 if (isFunctionPointer())
603 return reinterpret_cast<uint64_t>(Fn.Func) + Offset;
604 return reinterpret_cast<uint64_t>(BS.Pointee) + Offset;
605 }
606
607 PtrView view() const {
608 assert(isBlockPointer());
609 return PtrView{BS.Pointee, BS.Base, Offset};
610 }
611
612 /// Converts the pointer to an APValue that is an rvalue.
613 std::optional<APValue> toRValue(const Context &Ctx,
614 QualType ResultType) const;
615
616 /// Offsets a pointer inside an array.
617 [[nodiscard]] Pointer atIndex(uint64_t Idx) const {
618 switch (StorageKind) {
619 case Storage::Int:
620 return Pointer(Int.Value, Int.getType(), Idx);
621 case Storage::Block:
622 return Pointer(view().atIndex(Idx));
623 case Storage::Fn:
624 return Pointer(Fn.Func, Idx);
625 case Storage::String:
626 return Pointer(Str, Idx);
627 default:
628 llvm_unreachable("Unexpected pointer type in atIndex()");
629 }
630 }
631
632 /// Creates a pointer to a field.
633 [[nodiscard]] Pointer atField(unsigned Off) const {
634 return Pointer(view().atField(Off));
635 }
636
637 /// Subtract the given offset from the current Base and Offset
638 /// of the pointer.
639 [[nodiscard]] Pointer atFieldSub(unsigned Off) const {
640 assert(Offset >= Off);
641 unsigned O = Offset - Off;
642 return Pointer(BS.Pointee, O, O);
643 }
644
645 /// Restricts the scope of an array element pointer.
646 [[nodiscard]] Pointer narrow() const {
647 if (!isBlockPointer())
648 return *this;
649 return Pointer(view().narrow());
650 }
651
652 /// Expands a pointer to the containing array, undoing narrowing.
653 [[nodiscard]] Pointer expand() const {
654 if (!isBlockPointer())
655 return *this;
656 return Pointer(view().expand());
657 }
658
659 /// Checks if the pointer is null.
660 bool isZero() const {
661 switch (StorageKind) {
662 case Storage::Int:
663 return Int.isNull();
664 case Storage::Block:
665 return BS.Pointee == nullptr;
666 case Storage::Fn:
667 return !Fn.Func;
668 case Storage::Typeid:
669 case Storage::String:
670 case Storage::Opaque:
671 return false;
672 }
673 llvm_unreachable("Unknown clang::interp::Storage enum");
674 }
675 /// Checks if the pointer is live.
676 bool isLive() const {
677 if (!isBlockPointer())
678 return true;
679 return view().isLive();
680 }
681 /// Checks if the item is a field in an object.
682 bool isField() const {
683 if (!isBlockPointer())
684 return false;
685
686 return view().isField();
687 }
688
689 /// Accessor for information about the declaration site.
690 const Descriptor *getDeclDesc() const {
691 if (!isBlockPointer())
692 return nullptr;
693
694 assert(isBlockPointer());
695 assert(BS.Pointee);
696 return BS.Pointee->Desc;
697 }
698 SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
699
700 /// Returns the expression or declaration the pointer has been created for.
702 if (isBlockPointer())
703 return getDeclDesc()->getSource();
704 if (isFunctionPointer()) {
705 const Function *F = Fn.Func;
706 return F ? F->getDecl() : DeclOrExpr();
707 }
708 llvm_unreachable("Unsupported pointer type in getSource()");
709 return DeclOrExpr();
710 }
711
712 /// Returns a pointer to the object of which this pointer is a field.
713 [[nodiscard]] Pointer getBase() const { return Pointer(view().getBase()); }
714 /// Returns the parent array.
715 [[nodiscard]] Pointer getArray() const { return Pointer(view().getArray()); }
716
717 /// Accessors for information about the innermost field.
718 const Descriptor *getFieldDesc() const {
719 if (!isBlockPointer())
720 return nullptr;
721
722 if (isRoot())
723 return getDeclDesc();
724 return getInlineDesc()->Desc;
725 }
726
727 /// Returns the type of the innermost field.
729 switch (StorageKind) {
730 case Storage::Int:
731 return Int.getPointeeType();
732 case Storage::Block:
733 return view().getType();
734 case Storage::Fn:
735 return Fn.Func->getType();
736 case Storage::Typeid:
737 return QualType(Typeid.TypeInfoType, 0);
738 case Storage::String:
739 if (Str.Decayed)
740 return Str.getLiteral()
741 ->getType()
742 ->getAsArrayTypeUnsafe()
743 ->getElementType();
744 return Str.getLiteral()->getType();
745 case Storage::Opaque:
746 return Opaque.getFieldType();
747 }
748 llvm_unreachable("Unhandled StorageKind");
749 }
750
751 const VarDecl *getRootVarDecl() const;
752 const ValueDecl *getRootValueDecl() const;
753 const Expr *getRootExpr() const;
754
755 [[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
756
757 /// Returns the element size of the innermost field.
758 size_t elemSize() const {
759 if (isIntegralPointer()) {
760 // FIXME: Remove this and handle int ptrs specially?
761 return 1;
762 }
763 if (isStringPointer())
764 return Str.getLiteral()->getCharByteWidth();
765
766 return view().elemSize();
767 }
768 /// Returns the total size of the innermost field.
769 size_t getSize() const {
770 assert(isBlockPointer());
771 return getFieldDesc()->getSize();
772 }
773
774 /// Returns the offset into an array.
775 unsigned getOffset() const {
776 assert(Offset != PtrView::PastEndMark && "invalid offset");
777 return view().getOffset();
778 }
779
780 /// Whether this array refers to an array, but not
781 /// to the first element.
782 bool isArrayRoot() const {
783 switch (StorageKind) {
784 case Storage::Block:
785 return view().isArrayRoot();
786 case Storage::String:
787 return Offset == 0;
788 case Storage::Opaque:
789 return asOpaquePointer().getFieldType()->isArrayType();
790 default:
791 return false;
792 }
793 llvm_unreachable("Unhandled storage kind");
794 }
795
796 /// Checks if the innermost field is an array.
797 bool inArray() const {
798 switch (StorageKind) {
799 case Storage::Block:
800 return view().inArray();
801 case Storage::String:
802 return true;
803 case Storage::Opaque:
804 return asOpaquePointer().isArrayElement();
805 default:
806 return false;
807 }
808
809 llvm_unreachable("Unhandled storage kind");
810 }
811 bool inUnion() const {
812 if (isBlockPointer() && BS.Base != 0)
813 return view().inUnion();
814 return false;
815 };
816
817 /// Checks if the structure is a primitive array.
818 bool inPrimitiveArray() const {
819 if (isBlockPointer())
820 return view().inPrimitiveArray();
821 return false;
822 }
823 /// Checks if the structure is an array of unknown size.
824 bool isUnknownSizeArray() const {
825 if (isBlockPointer())
826 return getFieldDesc()->isUnknownSizeArray();
827 if (isOpaquePointer())
828 return Opaque.isUnknownSizeArray();
829 return false;
830 }
831 /// Checks if the pointer points to an array.
832 bool isArrayElement() const {
833 if (!isBlockPointer())
834 return false;
835
836 return view().isArrayElement();
837 }
838 /// Pointer points directly to a block.
839 bool isRoot() const {
840 if (isZero())
841 return true;
842 if (isBlockPointer())
843 return view().isRoot();
844 if (isOpaquePointer())
845 return Opaque.isRoot();
846 return true;
847 }
848 /// If this pointer has an InlineDescriptor we can use to initialize.
849 bool canBeInitialized() const {
850 if (!isBlockPointer())
851 return false;
852 return view().canBeInitialized();
853 }
854
855 [[nodiscard]] const BlockPointer &asBlockPointer() const {
856 assert(isBlockPointer());
857 return BS;
858 }
859 [[nodiscard]] const IntPointer &asIntPointer() const {
860 assert(isIntegralPointer());
861 return Int;
862 }
863 [[nodiscard]] const FunctionPointer &asFunctionPointer() const {
864 assert(isFunctionPointer());
865 return Fn;
866 }
867 [[nodiscard]] const TypeidPointer &asTypeidPointer() const {
868 assert(isTypeidPointer());
869 return Typeid;
870 }
871 [[nodiscard]] const StringPointer &asStringPointer() const {
872 assert(isStringPointer());
873 return Str;
874 }
875 [[nodiscard]] const OpaquePointer &asOpaquePointer() const {
876 assert(isOpaquePointer());
877 return Opaque;
878 }
879
880 bool isBlockPointer() const { return StorageKind == Storage::Block; }
881 bool isIntegralPointer() const { return StorageKind == Storage::Int; }
882 bool isFunctionPointer() const { return StorageKind == Storage::Fn; }
883 bool isTypeidPointer() const { return StorageKind == Storage::Typeid; }
884 bool isStringPointer() const { return StorageKind == Storage::String; }
885 bool isOpaquePointer() const { return StorageKind == Storage::Opaque; }
886
887 /// Returns the record descriptor of a class.
888 const Record *getRecord() const {
889 if (!isBlockPointer())
890 return nullptr;
891 return view().getRecord();
892 }
893 /// Returns the element record type, if this is a non-primive array.
894 const Record *getElemRecord() const { return view().getElemRecord(); }
895 /// Returns the field information.
896 const FieldDecl *getField() const {
897 if (const Descriptor *FD = getFieldDesc())
898 return FD->asFieldDecl();
899 return nullptr;
900 }
901
902 /// Checks if the storage is extern.
903 bool isExtern() const {
904 if (isBlockPointer())
905 return view().isExtern();
906 return false;
907 }
908 /// Checks if the storage is static.
909 bool isStatic() const {
910 if (!isBlockPointer())
911 return true;
912 assert(BS.Pointee);
913 return BS.Pointee->isGlobal();
914 }
915 /// Checks if the storage is temporary.
916 bool isTemporary() const {
917 if (isBlockPointer()) {
918 assert(BS.Pointee);
919 return BS.Pointee->isTemporary();
920 }
921 return false;
922 }
923 /// Checks if the storage has been dynamically allocated.
924 bool isDynamic() const {
925 if (isBlockPointer()) {
926 assert(BS.Pointee);
927 return BS.Pointee->isDynamic();
928 }
929 return false;
930 }
931 /// Checks if the storage is a static temporary.
932 bool isStaticTemporary() const { return isStatic() && isTemporary(); }
933
934 /// Checks if the field is mutable.
935 bool isMutable() const {
936 if (!isBlockPointer())
937 return false;
938 return view().isMutable();
939 }
940
941 bool isWeak() const {
942 switch (StorageKind) {
943 case Storage::Fn:
944 if (!Fn.Func || !Fn.Func->getDecl())
945 return false;
946 return Fn.Func->getDecl()->isWeak();
947 case Storage::Opaque:
948 if (const VarDecl *BaseDecl = Opaque.getBaseVarDecl())
949 return BaseDecl->isWeak();
950 return false;
951 case Storage::Block:
952 return BS.Pointee->isWeak();
953 default:
954 return false;
955 }
956 llvm_unreachable("Unhandled storage kind");
957 }
958 /// Checks if the object is active.
959 bool isActive() const {
960 if (!isBlockPointer())
961 return true;
962 return view().isActive();
963 }
964 /// Checks if a structure is a base class.
965 bool isBaseClass() const { return view().isBaseClass(); }
966 bool isVirtualBaseClass() const { return view().isVirtualBaseClass(); }
967
968 /// Checks if the pointer points to a dummy value.
969 bool isDummy() const { return isOpaquePointer(); }
970
971 /// Checks if an object or a subfield is mutable.
972 bool isConst() const {
973 if (isIntegralPointer())
974 return true;
975 if (isStringPointer())
976 return true;
977 if (!isBlockPointer())
978 return false;
979 return view().isConst();
980 }
981 bool isConstInMutable() const {
982 if (!isBlockPointer())
983 return false;
984 return isRoot() ? false : getInlineDesc()->IsConstInMutable;
985 }
986
987 /// Checks if an object or a subfield is volatile.
988 bool isVolatile() const {
989 if (!isBlockPointer())
990 return false;
991 return view().isVolatile();
992 }
993
994 /// Returns the declaration ID.
996 if (isBlockPointer()) {
997 assert(BS.Pointee);
998 return BS.Pointee->getDeclID();
999 }
1000 return std::nullopt;
1001 }
1002
1003 /// Returns the byte offset from the start.
1004 uint64_t getByteOffset() const {
1005 if (isBlockPointer())
1006 return isOnePastEnd() ? PtrView::PastEndMark : Offset;
1007 return Offset;
1008 }
1009
1010 /// Returns the number of elements.
1011 unsigned getNumElems() const {
1012 if (isStringPointer())
1013 return Str.getLiteral()->getLength() + 1;
1014 if (isOpaquePointer()) {
1015 const ArrayType *AT =
1016 Opaque.getSurroundingArray()->getAsArrayTypeUnsafe();
1017 if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(AT))
1018 return CAT->getZExtSize();
1019 }
1020 if (!isBlockPointer())
1021 return ~0u;
1022 return view().getNumElems();
1023 }
1024
1025 const Block *block() const {
1026 assert(isBlockPointer());
1027 return BS.Pointee;
1028 }
1029
1030 /// If backed by actual data (i.e. a block or string pointer), return
1031 /// an address to that data.
1032 const std::byte *getRawAddress() const {
1033 if (isStringPointer()) {
1034 const StringLiteral *Lit = Str.getLiteral();
1035 return reinterpret_cast<const std::byte *>(
1036 Lit->getBytes().data() + (Offset * Lit->getCharByteWidth()));
1037 }
1038 assert(isBlockPointer());
1039 return BS.Pointee->data() + Offset;
1040 }
1041
1042 /// Returns the index into an array.
1043 int64_t getIndex() const {
1044 if (isStringPointer())
1045 return Offset;
1046 if (isOpaquePointer()) {
1047 if (Opaque.isArrayElement())
1048 return Opaque.Path[Opaque.PathLength - 1].Index;
1049 return 0;
1050 }
1051 if (!isBlockPointer())
1052 return getIntegerRepresentation();
1053
1054 return view().getIndex();
1055 }
1056
1057 /// Checks if the index is one past end.
1058 bool isOnePastEnd() const {
1059 if (isStringPointer())
1060 return Offset == (Str.getLiteral()->getLength() + 1);
1061 if (isOpaquePointer())
1062 return Opaque.isOnePastEndOrElementPastEnd();
1063
1064 if (!isBlockPointer())
1065 return false;
1066
1067 if (!BS.Pointee)
1068 return false;
1069
1070 return view().isOnePastEnd();
1071 }
1072
1073 /// Checks if the pointer points past the end of the object.
1074 bool isPastEnd() const {
1075 if (isIntegralPointer())
1076 return false;
1077 if (isStringPointer())
1078 return Offset >= (Str.getLiteral()->getLength() + 1);
1079
1080 return !isZero() && Offset > BS.Pointee->getSize();
1081 }
1082
1083 /// Checks if the pointer is an out-of-bounds element pointer.
1084 bool isElementPastEnd() const { return Offset == PtrView::PastEndMark; }
1085
1086 /// Checks if the pointer is pointing to a zero-size array.
1087 bool isZeroSizeArray() const {
1088 if (isFunctionPointer())
1089 return false;
1090 if (isOpaquePointer())
1091 return false; // FIXME: Can actually happen I think?
1092 if (const auto *Desc = getFieldDesc())
1093 return Desc->isZeroSizeArray();
1094 return false;
1095 }
1096
1097 /// Checks whether the pointer can be dereferenced to the given PrimType.
1098 bool canDeref(PrimType T) const {
1099 if (isStringPointer()) {
1100 switch (Str.getLiteral()->getCharByteWidth()) {
1101 case 1:
1102 return T == PT_Sint8 || T == PT_Uint8;
1103 case 2:
1104 return T == PT_Sint16 || T == PT_Uint16;
1105 case 4:
1106 return T == PT_Sint32 || T == PT_Uint32;
1107 }
1108
1109 return false;
1110 }
1111
1112 assert(isBlockPointer());
1113 if (const Descriptor *FieldDesc = getFieldDesc()) {
1114 return (FieldDesc->isPrimitive() || FieldDesc->isPrimitiveArray()) &&
1115 FieldDesc->getPrimType() == T;
1116 }
1117 return false;
1118 }
1119
1120 /// Dereferences the pointer, if it's live.
1121 template <typename T> T &deref() const {
1122 assert(isLive() && "Invalid pointer");
1123 assert(isBlockPointer());
1124 assert(BS.Pointee);
1125 assert(isDereferencable());
1126 assert(Offset + sizeof(T) <= BS.Pointee->getSize());
1127 return view().deref<T>();
1128 }
1129
1130 template <typename T> T load() const {
1131 assert(isLive() && "Invalid pointer");
1132 if (isBlockPointer()) {
1133 assert(BS.Pointee);
1134 assert(isDereferencable());
1135 assert(Offset + sizeof(T) <= BS.Pointee->getSize());
1136 return view().deref<T>();
1137 }
1138
1139 if (isStringPointer()) {
1140 const StringLiteral *Lit = Str.getLiteral();
1141
1142 if constexpr (isFixedSizeIntegralType<T>()) {
1143 // The literal does not include the nul byte.
1144 if (Offset >= Lit->getLength())
1145 return T::from('\0');
1146 return T::from(Lit->getCodeUnit(Offset));
1147 } else if constexpr (std::is_integral_v<T>) {
1148 if (Offset >= Lit->getLength())
1149 return '\0';
1150 return Lit->getCodeUnit(Offset);
1151 }
1152 }
1153
1154 llvm_unreachable("Unexpected pointer type in load()");
1155 }
1156
1157 /// Dereferences the element at index \p I.
1158 /// This is equivalent to atIndex(I).deref<T>().
1159 template <typename T> T &elem(unsigned I) const {
1160 assert(isLive() && "Invalid pointer");
1161 assert(isBlockPointer());
1162 assert(BS.Pointee);
1163 assert(isDereferencable());
1164 assert(getFieldDesc()->isPrimitiveArray());
1165 assert(I < getFieldDesc()->getNumElems());
1166
1167 return view().elem<T>(I);
1168 }
1169
1170 template <typename T> T loadElem(unsigned I) const {
1171 assert(isLive() && "Invalid pointer");
1172 if (isBlockPointer()) {
1173 assert(BS.Pointee);
1174 assert(isDereferencable());
1175 assert(getFieldDesc()->isPrimitiveArray());
1176 assert(I < getFieldDesc()->getNumElems());
1177
1178 return view().elem<T>(I);
1179 }
1180
1181 assert(isStringPointer());
1182 const StringLiteral *Lit = Str.getLiteral();
1183 unsigned Index = Offset + I;
1184 if constexpr (isFixedSizeIntegralType<T>()) {
1185 // The literal does not include the nul byte.
1186 if (Index >= Lit->getLength())
1187 return T::from('\0');
1188 return T::from(Lit->getCodeUnit(Index));
1189 } else if constexpr (std::is_integral_v<T>) {
1190 if (Index >= Lit->getLength())
1191 return '\0';
1192 return Lit->getCodeUnit(Index);
1193 }
1194 llvm_unreachable("Unexpected pointer type in loadElem()");
1195 }
1196
1197 bool isConstexprUnknown() const {
1198 if (isOpaquePointer())
1199 return Opaque.isConstexprUnknown();
1200 if (isBlockPointer())
1201 return getDeclDesc()->IsConstexprUnknown;
1202 return false;
1203 }
1204
1205 /// Whether this block can be read from at all. This is only true for
1206 /// block pointers that point to a valid location inside that block.
1207 bool isDereferencable() const {
1208 if (!isBlockPointer())
1209 return false;
1210 if (isDummy())
1211 return false;
1212 if (isConstexprUnknown())
1213 return false;
1214 if (isPastEnd())
1215 return false;
1216
1217 return true;
1218 }
1219
1221 return StorageKind == Storage::Block || StorageKind == Storage::String;
1222 }
1223
1224 /// Initializes a field.
1225 void initialize() const {
1226 if (!isBlockPointer())
1227 return;
1228 view().initialize();
1229 }
1230 /// Initialized the given element of a primitive array.
1231 void initializeElement(unsigned Index) const {
1232 view().initializeElement(Index);
1233 }
1234 /// Initialize all elements of a primitive array at once. This can be
1235 /// used in situations where we *know* we have initialized *all* elements
1236 /// of a primtive array.
1237 void initializeAllElements() const;
1238 /// Checks if an object was initialized.
1239 bool isInitialized() const {
1240 if (!isBlockPointer())
1241 return true;
1242
1243 return view().isInitialized();
1244 }
1245
1246 /// Like isInitialized(), but for primitive arrays.
1247 bool isElementInitialized(unsigned Index) const {
1248 if (!isBlockPointer())
1249 return true;
1250
1251 return view().isElementInitialized(Index);
1252 }
1254 assert(getFieldDesc()->isPrimitiveArray());
1255 assert(isArrayRoot());
1256 return view().allElementsInitialized();
1257 }
1258 bool allElementsAlive() const;
1259 bool isElementAlive(unsigned Index) const;
1260
1261 /// Activates a field.
1262 void activate() const { view().activate(); }
1263 /// Deactivates an entire strurcutre.
1264 void deactivate() const {
1265 // TODO: this only appears in constructors, so nothing to deactivate.
1266 }
1267
1269 if (!isBlockPointer())
1270 return Lifetime::Started;
1271 return view().getLifetime();
1272 }
1273
1274 /// Start the lifetime of this pointer. This works for pointer with an
1275 /// InlineDescriptor as well as primitive array elements. Pointers are usually
1276 /// alive by default, unless the underlying object has been allocated with
1277 /// std::allocator. This function is used by std::construct_at.
1279 /// Ends the lifetime of the pointer. This works for pointer with an
1280 /// InlineDescriptor as well as primitive array elements. This function is
1281 /// used by std::destroy_at.
1283
1284 void setLifeState(Lifetime L) const {
1285 if (!isBlockPointer())
1286 return;
1287 view().setLifeState(L);
1288 };
1289
1290 /// Strip base casts from this Pointer.
1291 /// The result is either a root pointer or something
1292 /// that isn't a base class anymore.
1293 [[nodiscard]] Pointer stripBaseCasts() const {
1294 return Pointer(view().stripBaseCasts());
1295 }
1296
1297 /// Compare two pointers.
1299 if (!hasSameBase(*this, Other))
1301
1302 if (Offset < Other.Offset)
1304 if (Offset > Other.Offset)
1306
1308 }
1309
1310 /// Checks if two pointers are comparable.
1311 static bool hasSameBase(const Pointer &A, const Pointer &B);
1312 /// Checks if two pointers can be subtracted.
1313 static bool elemsOfSameArray(const Pointer &A, const Pointer &B);
1314 /// Checks if both given pointers point to the same block.
1315 static bool pointToSameBlock(const Pointer &A, const Pointer &B);
1316
1317 static std::optional<std::pair<PtrView, PtrView>>
1318 computeSplitPoint(const Pointer &A, const Pointer &B);
1319
1320 /// Whether this points to a block that's been created for a "literal lvalue",
1321 /// i.e. a non-MaterializeTemporaryExpr Expr.
1322 bool pointsToLiteral() const;
1323 /// Whether this points to a block created for an AddrLabelExpr.
1324 bool pointsToLabel() const;
1325 /// Returns the AddrLabelExpr the Pointer points to, if any.
1327 return dyn_cast_if_present<AddrLabelExpr>(getRootExpr());
1328 }
1329
1330 /// Prints the pointer.
1331 void print(llvm::raw_ostream &OS) const;
1332
1333 /// Compute an integer that can be used to compare this pointer to
1334 /// another one. This is usually NOT the same as the pointer offset
1335 /// regarding the AST record layout.
1336 std::optional<size_t>
1337 computeOffsetForComparison(const ASTContext &ASTCtx) const;
1338 /// Compute the pointer offset as given by the ASTRecordLayout.
1339 /// Returns the result in bytes.
1340 std::optional<size_t> computeLayoutOffset(const ASTContext &ASTCtx) const;
1341
1342private:
1343 friend class Block;
1344 friend class DeadBlock;
1345 friend class MemberPointer;
1346 friend class InterpState;
1347 friend class DynamicAllocator;
1348 friend class Program;
1349
1350 /// Returns the embedded descriptor preceding a field.
1351 InlineDescriptor *getInlineDesc() const {
1352 assert(isBlockPointer());
1353 assert(BS.Base <= BS.Pointee->getSize());
1354 assert(BS.Base != 0);
1355 return getDescriptor(BS.Base);
1356 }
1357
1358 /// Returns a descriptor at a given offset.
1359 InlineDescriptor *getDescriptor(unsigned Offset) const {
1360 assert(Offset != 0 && "Not a nested pointer");
1361 assert(isBlockPointer());
1362 assert(!isZero());
1363 return view().getDescriptor(Offset);
1364 }
1365
1366 /// Returns a reference to the InitMapPtr which stores the initialization map.
1367 InitMapPtr &getInitMap() const {
1368 assert(isBlockPointer());
1369 assert(!isZero());
1370 return view().getInitMap();
1371 }
1372
1373 /// Offset into the storage.
1374 uint64_t Offset = 0;
1375
1376 Storage StorageKind = Storage::Int;
1377 union {
1384 };
1385};
1386
1387inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
1388 P.print(OS);
1389 OS << ' ';
1390 if (P.isZero())
1391 return OS;
1392
1393 if (const Descriptor *D = P.getFieldDesc())
1394 D->dump(OS);
1395 if (P.isArrayElement()) {
1396 if (P.isOnePastEnd())
1397 OS << " one-past-the-end";
1398 else {
1399 OS << ' ';
1400 std::string Indices;
1401 llvm::raw_string_ostream SS(Indices);
1402 Pointer K = P;
1403 while (K.isArrayElement()) {
1404 SS << ']' << K.expand().getIndex() << '[';
1405 K = K.expand().getArray();
1406 }
1407 std::reverse(Indices.begin(), Indices.end());
1408 OS << Indices;
1409 }
1410 } else if (P.isBlockPointer() && P.isArrayRoot())
1411 OS << " arrayroot";
1412
1413 if (P.isDummy())
1414 OS << " dummy";
1415 if (!P.isLive())
1416 OS << " dead";
1417 if (P.isBlockPointer() && P.isBaseClass())
1418 OS << " base-class";
1419 return OS;
1420}
1421
1422} // namespace interp
1423} // namespace clang
1424
1425#endif
#define V(N, I)
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
FormatToken * Next
The next token in the unwrapped line.
static void print(llvm::raw_ostream &OS, const T &V, const Context &Ctx, QualType Ty)
static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R)
Convert a pointer to a composite value to an rvalue.
Definition Pointer.cpp:1112
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:158
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:245
AddrLabelExpr - The GNU address of label extension, representing &&label.
Definition Expr.h:4619
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3820
QualType getElementType() const
Definition TypeBase.h:3832
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
This represents one expression.
Definition Expr.h:114
Represents a member of a struct/union/class.
Definition Decl.h:3311
A (possibly-)qualified type.
Definition TypeBase.h:938
QualType IgnoreParens() const
Returns the specified type after dropping any outer-level parentheses.
Definition TypeBase.h:1331
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8446
Encodes a location in the source.
StringLiteral - This represents a string literal expression, e.g.
Definition Expr.h:1844
unsigned getLength() const
Definition Expr.h:1969
uint32_t getCodeUnit(size_t I) const
Return the code unit at the given position.
Definition Expr.h:1931
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
Definition Expr.h:1920
unsigned getCharByteWidth() const
Definition Expr.h:1971
The base class of the type hierarchy.
Definition TypeBase.h:1879
bool isArrayType() const
Definition TypeBase.h:8782
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9352
bool isPointerOrReferenceType() const
Definition TypeBase.h:8687
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:714
Represents a variable declaration or definition.
Definition Decl.h:934
A memory block, either on the stack or in the heap.
Definition Block.h:44
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:49
Descriptor for a dead block.
Definition Block.h:248
Bytecode function.
Definition Function.h:98
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition Function.h:133
A pointer to a memory block, live or dead.
Definition Pointer.h:548
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition Pointer.cpp:950
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition Pointer.h:646
friend class Program
Definition Pointer.h:1348
OpaquePointer Opaque
Definition Pointer.h:1383
UnsignedOrNone getDeclID() const
Returns the declaration ID.
Definition Pointer.h:995
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
Definition Pointer.h:1293
const Expr * getRootExpr() const
Definition Pointer.cpp:1324
bool isVolatile() const
Checks if an object or a subfield is volatile.
Definition Pointer.h:988
bool isStatic() const
Checks if the storage is static.
Definition Pointer.h:909
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition Pointer.h:924
bool inUnion() const
Definition Pointer.h:811
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:1087
FunctionPointer Fn
Definition Pointer.h:1380
bool allElementsInitialized() const
Definition Pointer.h:1253
T loadElem(unsigned I) const
Definition Pointer.h:1170
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition Pointer.h:617
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:969
const AddrLabelExpr * getPointedToLabel() const
Returns the AddrLabelExpr the Pointer points to, if any.
Definition Pointer.h:1326
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition Pointer.h:639
bool inPrimitiveArray() const
Checks if the structure is a primitive array.
Definition Pointer.h:818
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition Pointer.cpp:466
bool isExtern() const
Checks if the storage is extern.
Definition Pointer.h:903
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:1043
friend class MemberPointer
Definition Pointer.h:1345
bool isOpaquePointer() const
Definition Pointer.h:885
bool isActive() const
Checks if the object is active.
Definition Pointer.h:959
bool isStringPointer() const
Definition Pointer.h:884
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
Definition Pointer.h:1098
bool isConst() const
Checks if an object or a subfield is mutable.
Definition Pointer.h:972
DeclOrExpr getSource() const
Returns the expression or declaration the pointer has been created for.
Definition Pointer.h:701
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition Pointer.h:633
bool isWeak() const
Definition Pointer.h:941
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:1121
Pointer(IntPointer &&IntPtr)
Definition Pointer.h:551
bool isMutable() const
Checks if the field is mutable.
Definition Pointer.h:935
bool isConstInMutable() const
Definition Pointer.h:981
unsigned getNumElems() const
Returns the number of elements.
Definition Pointer.h:1011
Pointer getArray() const
Returns the parent array.
Definition Pointer.h:715
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition Pointer.h:824
const TypeidPointer & asTypeidPointer() const
Definition Pointer.h:867
bool isIntegralPointer() const
Definition Pointer.h:881
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:728
bool isArrayElement() const
Checks if the pointer points to an array.
Definition Pointer.h:832
void initialize() const
Initializes a field.
Definition Pointer.h:1225
Pointer(uint64_t Address, const Type *Ty, uint64_t Offset=0, std::optional< bool > IsNull=std::nullopt)
Definition Pointer.h:557
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition Pointer.h:782
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:676
bool inArray() const
Checks if the innermost field is an array.
Definition Pointer.h:797
const StringPointer & asStringPointer() const
Definition Pointer.h:871
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Definition Pointer.h:932
Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset=0)
Definition Pointer.h:563
T & elem(unsigned I) const
Dereferences the element at index I.
Definition Pointer.h:1159
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:713
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition Pointer.h:1004
bool isTypeidPointer() const
Definition Pointer.h:883
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:660
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition Pointer.h:1298
bool isConstexprUnknown() const
Definition Pointer.h:1197
const IntPointer & asIntPointer() const
Definition Pointer.h:859
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:839
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:690
void activate() const
Activates a field.
Definition Pointer.h:1262
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
Definition Pointer.h:894
const OpaquePointer & asOpaquePointer() const
Definition Pointer.h:875
unsigned getOffset() const
Returns the offset into an array.
Definition Pointer.h:775
friend class DynamicAllocator
Definition Pointer.h:1347
void endLifetime() const
Ends the lifetime of the pointer.
Definition Pointer.h:1282
void setLifeState(Lifetime L) const
Definition Pointer.h:1284
bool isOnePastEnd() const
Checks if the index is one past end.
Definition Pointer.h:1058
friend class InterpState
Definition Pointer.h:1346
uint64_t getIntegerRepresentation() const
Definition Pointer.h:599
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition Pointer.h:1074
Pointer(const Function *F, uint64_t Offset=0)
Definition Pointer.h:561
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:896
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition Pointer.h:653
friend class Block
Definition Pointer.h:1343
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:1084
bool isDereferencable() const
Whether this block can be read from at all.
Definition Pointer.h:1207
void startLifetime() const
Start the lifetime of this pointer.
Definition Pointer.h:1278
Pointer(OpaquePointer OP, uint64_t Offset=0)
Definition Pointer.h:580
bool isBlockPointer() const
Definition Pointer.h:880
bool operator!=(const Pointer &P) const
Definition Pointer.h:591
void deactivate() const
Deactivates an entire strurcutre.
Definition Pointer.h:1264
friend class DeadBlock
Definition Pointer.h:1344
TypeidPointer Typeid
Definition Pointer.h:1381
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.h:1239
size_t getSize() const
Returns the total size of the innermost field.
Definition Pointer.h:769
bool isTemporary() const
Checks if the storage is temporary.
Definition Pointer.h:916
StringPointer Str
Definition Pointer.h:1382
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:863
SourceLocation getDeclLoc() const
Definition Pointer.h:698
const Block * block() const
Definition Pointer.h:1025
void initializeElement(unsigned Index) const
Initialized the given element of a primitive array.
Definition Pointer.h:1231
Pointer(DeclOrExpr DOE, bool ConstexprUnknown=false)
Definition Pointer.h:573
bool isFunctionPointer() const
Definition Pointer.h:882
Pointer getDeclPtr() const
Definition Pointer.h:755
bool isReadablePointerType() const
Definition Pointer.h:1220
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:718
PtrView view() const
Definition Pointer.h:607
bool isVirtualBaseClass() const
Definition Pointer.h:966
Pointer(const Expr *Base, unsigned Id)
Definition Pointer.h:568
bool isBaseClass() const
Checks if a structure is a base class.
Definition Pointer.h:965
size_t elemSize() const
Returns the element size of the innermost field.
Definition Pointer.h:758
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition Pointer.h:849
Lifetime getLifetime() const
Definition Pointer.h:1268
const BlockPointer & asBlockPointer() const
Definition Pointer.h:855
Pointer(StringPointer Str, uint64_t Offset=0)
Definition Pointer.h:570
const std::byte * getRawAddress() const
If backed by actual data (i.e.
Definition Pointer.h:1032
bool isField() const
Checks if the item is a field in an object.
Definition Pointer.h:682
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition Pointer.h:1247
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:888
Structure/Class descriptor.
Definition Record.h:27
@ Address
A pointer to a ValueDecl.
Definition Primitives.h:28
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
Definition Boolean.h:148
static bool isFixedSizeIntegralType(PrimType T)
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:35
Top level wrappers for InstallAPI frontend operations.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
Definition CallGraph.h:218
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
static bool isBlockPointer(Expr *Arg)
@ Off
Never emit colors regardless of the output stream.
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ConceptReference *C)
Insertion operator for diagnostics.
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Other
Other implicit parameter.
Definition Decl.h:1787
#define false
Definition stdbool.h:26
Pointer * Prev
Previous link in the pointer chain.
Definition Pointer.h:357
Pointer * Next
Next link in the pointer chain.
Definition Pointer.h:359
unsigned Base
Start of the current subfield.
Definition Pointer.h:355
Block * Pointee
The block the pointer is pointing to.
Definition Pointer.h:353
QualType getType() const
Definition DeclOrExpr.h:48
Describes a memory block created by an allocation site.
Definition Descriptor.h:121
const bool IsConst
Flag indicating if the block is mutable.
Definition Descriptor.h:153
unsigned getSize() const
Returns the size of the object without metadata.
Definition Descriptor.h:225
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:200
const Descriptor *const ElemDesc
Descriptor of the array element.
Definition Descriptor.h:147
bool isUnknownSizeArray() const
Checks if the descriptor is of an array of unknown size.
Definition Descriptor.h:256
unsigned getElemSize() const
returns the size of an element when the structure is viewed as an array.
Definition Descriptor.h:238
const bool IsArray
Flag indicating if the block is an array.
Definition Descriptor.h:160
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:250
bool isZeroSizeArray() const
Checks if the descriptor is of an array of zero size.
Definition Descriptor.h:254
const FieldDecl * asFieldDecl() const
Definition Descriptor.h:212
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:145
Descriptor used for global variables.
Definition Descriptor.h:48
A pointer-sized struct we use to allocate into data storage.
Definition InitMap.h:79
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:66
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition Descriptor.h:88
unsigned IsBase
Flag indicating if the field is an embedded base class.
Definition Descriptor.h:82
unsigned IsVirtualBase
Flag inidcating if the field is a virtual base class.
Definition Descriptor.h:85
unsigned InUnion
Flag indicating if this field is in a union (even if nested).
Definition Descriptor.h:91
unsigned Offset
Offset inside the structure/array.
Definition Descriptor.h:68
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition Descriptor.h:79
unsigned IsConst
Flag indicating if the storage is constant or not.
Definition Descriptor.h:73
unsigned IsFieldMutable
Flag indicating if the field is mutable (if in a record).
Definition Descriptor.h:94
QualType getPointeeType() const
Definition Pointer.h:372
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
Definition Pointer.cpp:1363
const Type * getType() const
Definition Pointer.h:369
llvm::PointerIntPair< const Type *, 1, bool > TypeAndIsNull
Definition Pointer.h:363
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1334
OpaquePointer withFieldType(const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
Definition Pointer.h:460
llvm::PointerIntPair< const Type *, 2, unsigned > FieldType
Definition Pointer.h:448
OpaquePointer withPastEnd(bool PastEnd) const
Definition Pointer.h:479
QualType getObjectType() const
Definition Pointer.h:487
bool isRoot() const
Check if the pointer has offset 0.
Definition Pointer.cpp:1494
const VarDecl * getBaseVarDecl() const
Definition Pointer.h:455
QualType getSurroundingArray() const
If this is pointing to an array element, return the array.
Definition Pointer.cpp:1463
const Expr * getBaseExpr() const
Definition Pointer.h:456
bool isOnePastEndOrElementPastEnd() const
This is used in Pointer::isOnePastEnd().
Definition Pointer.cpp:1551
const PointerPathEntry * Path
Definition Pointer.h:449
ArrayRef< PointerPathEntry > path() const
Definition Pointer.h:452
const ValueDecl * getBaseDecl() const
Definition Pointer.h:454
bool isArrayElement() const
Definition Pointer.h:500
QualType getFieldType() const
Definition Pointer.h:494
bool isConstexprUnknown() const
Definition Pointer.h:511
OpaquePointer withPath(const PointerPathEntry *Path, unsigned PathLength, const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
Definition Pointer.h:469
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Definition Pointer.cpp:1399
static PointerPathEntry array(int64_t Index)
Definition Pointer.h:423
static PointerPathEntry field(const FieldDecl *FD)
Definition Pointer.h:437
llvm::PointerIntPair< const CXXRecordDecl *, 1, bool > RD
Definition Pointer.h:413
enum clang::interp::PointerPathEntry::@133156275124227243235357227301330162015140142322 Kind
static PointerPathEntry negativeArray(int64_t Index)
Definition Pointer.h:430
static PointerPathEntry base(const CXXRecordDecl *RD, bool Virtual=false)
Definition Pointer.h:416
bool isUnknownSizeArray() const
Definition Pointer.h:170
const Descriptor * getDeclDesc() const
Definition Pointer.h:88
bool allElementsInitialized() const
Definition Pointer.cpp:868
PtrView atField(unsigned Offset) const
Definition Pointer.h:275
bool isField() const
Definition Pointer.h:162
size_t elemSize() const
Definition Pointer.h:90
const Record * getRecord() const
Definition Pointer.h:155
const Descriptor * getFieldDesc() const
Definition Pointer.h:82
const FieldDecl * getField() const
Definition Pointer.h:160
bool isElementInitialized(unsigned Index) const
Definition Pointer.cpp:726
static constexpr unsigned PastEndMark
Definition Pointer.h:37
unsigned getEvalID()
Definition Pointer.h:62
PtrView atIndex(unsigned Idx) const
Definition Pointer.h:211
bool isBaseClass() const
Definition Pointer.h:166
bool inPrimitiveArray() const
Definition Pointer.h:58
void activate() const
Definition Pointer.cpp:893
InlineDescriptor * getDescriptor(unsigned Offset) const
Definition Pointer.h:76
bool inArray() const
Definition Pointer.h:57
void startLifetime() const
Definition Pointer.h:340
PtrView narrow() const
Definition Pointer.h:92
T & elem(unsigned I) const
Definition Pointer.h:257
bool isElementPastEnd() const
Definition Pointer.h:47
const Block * block() const
Definition Pointer.h:60
bool isVolatile() const
Definition Pointer.h:53
bool isInitialized() const
Definition Pointer.h:303
bool isArrayElement() const
Definition Pointer.h:234
bool isPastEnd() const
Definition Pointer.h:174
PtrView getArray() const
Definition Pointer.h:150
bool isZero() const
Definition Pointer.h:43
const Record * getElemRecord() const
Definition Pointer.h:156
unsigned getNumElems() const
Definition Pointer.h:232
InitMapPtr & getInitMap() const
Definition Pointer.h:332
InlineDescriptor * getInlineDesc() const
Definition Pointer.h:70
bool inUnion() const
Definition Pointer.h:56
bool isMutable() const
Definition Pointer.h:49
bool canBeInitialized() const
Definition Pointer.h:59
void endLifetime() const
Definition Pointer.h:341
void initializeElement(unsigned Index) const
Definition Pointer.cpp:844
bool operator==(const PtrView &Other) const
Definition Pointer.h:343
void initialize() const
Definition Pointer.cpp:817
QualType getType() const
Definition Pointer.h:280
bool isOnePastEnd() const
Definition Pointer.h:190
bool isConst() const
Definition Pointer.h:66
bool isRoot() const
Definition Pointer.h:64
void setLifeState(Lifetime L) const
Definition Pointer.cpp:789
Lifetime getLifetime() const
Definition Pointer.cpp:763
PtrView getBase() const
Definition Pointer.h:270
unsigned getOffset() const
Definition Pointer.h:176
bool isActive() const
Definition Pointer.h:45
PtrView expand() const
Definition Pointer.h:116
bool isVirtualBaseClass() const
Definition Pointer.h:167
bool isZeroSizeArray() const
Definition Pointer.h:48
bool isLive() const
Definition Pointer.h:44
bool isArrayRoot() const
Definition Pointer.h:46
T & deref() const
Definition Pointer.h:246
bool operator!=(const PtrView &Other) const
Definition Pointer.h:348
PtrView stripBaseCasts() const
Definition Pointer.h:143
bool isExtern() const
Definition Pointer.h:52
size_t getSize() const
Definition Pointer.h:188
int64_t getIndex() const
Definition Pointer.h:220
const StringLiteral * getLiteral() const
Definition Pointer.h:401
StringPointer decay() const
Definition Pointer.h:400