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