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 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
307 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
309 }
310
311 assert(Pointee && "Cannot check if null pointer was initialized");
312 const Descriptor *Desc = getFieldDesc();
313 assert(Desc);
314 if (Desc->isPrimitiveArray())
316
317 if (Base == 0)
318 return true;
319 // Field has its bit in an inline descriptor.
321 }
322
323 void initializeElement(unsigned Index) const;
324 bool allElementsInitialized() const;
325 bool isElementInitialized(unsigned Index) const;
327 return *reinterpret_cast<InitMapPtr *>(Pointee->rawData() + Base);
328 }
329 void initialize() const;
330 void activate() const;
331
332 void setLifeState(Lifetime L) const;
333 Lifetime getLifetime() const;
336
337 bool operator==(const PtrView &Other) const {
338 return Other.Pointee == Pointee && Base == Other.Base &&
339 Offset == Other.Offset;
340 }
341
342 bool operator!=(const PtrView &Other) const { return !(Other == *this); }
343};
344
346 /// The block the pointer is pointing to.
348 /// Start of the current subfield.
349 unsigned Base;
350 /// Previous link in the pointer chain.
352 /// Next link in the pointer chain.
354};
355
357 llvm::PointerIntPair<const Type *, 1, bool> TypeAndIsNull;
358 uint64_t Value;
359
360 std::optional<IntPointer> atOffset(const Context &Ctx, unsigned Offset) const;
361 IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const;
362
363 const Type *getType() const { return TypeAndIsNull.getPointer(); }
364 bool isNull() const { return TypeAndIsNull.getInt(); }
365
367 if (!getType())
368 return QualType();
369
370 QualType QT(getType(), 0);
371 if (QT->isPointerOrReferenceType())
372 QT = QT->getPointeeType();
373 else if (QT->isArrayType())
375
376 return QT.IgnoreParens();
377 }
378};
379
382};
383
385 const Type *TypePtr;
387};
388
390 const Expr *Base = nullptr;
391 unsigned ID = 0;
392 bool Decayed = false;
393
394 StringPointer decay() const { return StringPointer{Base, ID, true}; }
395 const StringLiteral *getLiteral() const {
396 if (const auto *PE = dyn_cast<PredefinedExpr>(Base))
397 return PE->getFunctionName();
399 }
400};
401
403 enum { Base, Field, Array, NegativeArray } Kind;
404 union {
405 uint64_t Index;
406 const FieldDecl *FD;
407 llvm::PointerIntPair<const CXXRecordDecl *, 1, bool> RD = {};
408 };
409
410 static PointerPathEntry base(const CXXRecordDecl *RD, bool Virtual = false) {
412 E.Kind = Base;
413 E.RD = {RD, Virtual};
414 return E;
415 }
416
417 static PointerPathEntry array(int64_t Index) {
419 E.Kind = Array;
420 E.Index = Index;
421 return E;
422 }
423
427 E.Index = Index;
428 return E;
429 }
430
433 E.Kind = Field;
434 E.FD = FD;
435 return E;
436 }
437};
438
441 // FieldType and IsOnePastEnd/IsConstexprUnknown bits.
442 llvm::PointerIntPair<const Type *, 2, unsigned> FieldType = {};
443 const PointerPathEntry *Path = nullptr;
444 unsigned PathLength = 0;
445
447 bool hasDeclBase() const { return Base.isDecl(); }
448 const VarDecl *getBaseDecl() const { return Base.asVarDecl(); }
449 const Expr *getBaseExpr() const { return Base.asExpr(); }
450
452 withFieldType(const Type *FieldTy,
453 std::optional<bool> PastEnd = std::nullopt) const {
454 unsigned NewBitFieldValue = FieldType.getInt();
455 if (PastEnd)
456 NewBitFieldValue =
457 (isConstexprUnknown() ? 2u : 0u) + static_cast<unsigned>(*PastEnd);
458 return OpaquePointer{Base, {FieldTy, NewBitFieldValue}, Path, PathLength};
459 }
460
462 const Type *FieldTy,
463 std::optional<bool> PastEnd = std::nullopt) const {
464 unsigned NewBitFieldValue = FieldType.getInt();
465 if (PastEnd)
466 NewBitFieldValue =
467 (isConstexprUnknown() ? 2u : 0u) + static_cast<unsigned>(*PastEnd);
468 return OpaquePointer{Base, {FieldTy, NewBitFieldValue}, Path, PathLength};
469 }
470
471 OpaquePointer withPastEnd(bool PastEnd) const {
472 return OpaquePointer{Base,
473 {FieldType.getPointer(),
474 FieldType.getInt() | static_cast<unsigned>(PastEnd)},
475 Path,
476 PathLength};
477 }
478
480 QualType T = Base.getType();
481 if (T->isPointerOrReferenceType())
482 return T->getPointeeType();
483 return T;
484 }
485
487 if (FieldType.getPointer()->isPointerOrReferenceType() && Base.isDecl())
488 return FieldType.getPointer()->getPointeeType();
489 return QualType(FieldType.getPointer(), 0);
490 }
491
492 bool isArrayElement() const {
493 return PathLength != 0 &&
495 }
496
497 std::optional<size_t> computeLayoutOffset(const ASTContext &ASTCtx) const;
498 /// If this is pointing to an array element, return the array.
500
501 bool isOnePastEnd() const { return FieldType.getInt() & 1u; }
502 bool isOnePastEndOrElementPastEnd() const;
503 bool isConstexprUnknown() const { return FieldType.getInt() & 2u; }
504 bool isUnknownSizeArray() const;
505 bool isRoot() const;
506};
507
508enum class Storage { Int, Block, Fn, Typeid, String, Opaque };
509
510/// A pointer to a memory block, live or dead.
511///
512/// This object can be allocated into interpreter stack frames. If pointing to
513/// a live block, it is a link in the chain of pointers pointing to the block.
514///
515/// In the simplest form, a Pointer has a Block* (the pointee) and both Base
516/// and Offset are 0, which means it will point to raw data.
517///
518/// The Base field is used to access metadata about the data. For primitive
519/// arrays, the Base is followed by an InitMap. In a variety of cases, the
520/// Base is preceded by an InlineDescriptor, which is used to track the
521/// initialization state, among other things.
522///
523/// The Offset field is used to access the actual data. In other words, the
524/// data the pointer decribes can be found at
525/// Pointee->rawData() + Pointer.Offset.
526///
527/// \verbatim
528/// Pointee Offset
529/// │ │
530/// │ │
531/// ▼ ▼
532/// ┌───────┬────────────┬─────────┬────────────────────────────┐
533/// │ Block │ InlineDesc │ InitMap │ Actual Data │
534/// └───────┴────────────┴─────────┴────────────────────────────┘
535/// ▲
536/// │
537/// │
538/// Base
539/// \endverbatim
540class Pointer {
541public:
542 Pointer() : StorageKind(Storage::Int), Int{{nullptr, true}, 0} {}
544 : StorageKind(Storage::Int), Int(std::move(IntPtr)) {}
545 Pointer(Block *B);
546 Pointer(Block *B, uint64_t BaseAndOffset);
547 Pointer(const Pointer &P);
548 Pointer(Pointer &&P);
549 Pointer(uint64_t Address, const Type *Ty, uint64_t Offset = 0,
550 std::optional<bool> IsNull = std::nullopt)
551 : Offset(Offset), StorageKind(Storage::Int),
552 Int{{Ty, IsNull.value_or(Address == 0)}, Address} {}
553 Pointer(const Function *F, uint64_t Offset = 0)
554 : Offset(Offset), StorageKind(Storage::Fn), Fn{F} {}
555 Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
556 : Offset(Offset), StorageKind(Storage::Typeid) {
557 Typeid.TypePtr = TypePtr;
558 Typeid.TypeInfoType = TypeInfoType;
559 }
560 Pointer(const Expr *Base, unsigned Id)
561 : Offset(0), StorageKind(Storage::String), Str{Base, Id} {}
562 Pointer(StringPointer Str, uint64_t Offset = 0)
563 : Offset(Offset), StorageKind(Storage::String), Str(Str) {}
564
565 Pointer(DeclOrExpr DOE, bool ConstexprUnknown = false)
566 : Offset(0), StorageKind(Storage::Opaque) {
567 Opaque.Base = DOE;
568 Opaque.FieldType = {DOE.getType().getTypePtr(), ConstexprUnknown ? 2u : 0u};
569 Opaque.Path = nullptr;
570 Opaque.PathLength = 0;
571 }
572 Pointer(OpaquePointer OP, uint64_t Offset = 0)
573 : Offset(Offset), StorageKind(Storage::Opaque), Opaque(OP) {}
574
575 Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
576 explicit Pointer(PtrView V) : Pointer(V.Pointee, V.Base, V.Offset) {}
577 ~Pointer();
578
579 Pointer &operator=(const Pointer &P);
580 Pointer &operator=(Pointer &&P);
581
582 bool operator==(const Pointer &P) const;
583 bool operator!=(const Pointer &P) const { return !(P == *this); }
584
585 /// Converts the pointer to an APValue.
586 APValue toAPValue(const ASTContext &ASTCtx) const;
587
588 /// Converts the pointer to a string usable in diagnostics.
589 std::string toDiagnosticString(const ASTContext &Ctx) const;
590
591 uint64_t getIntegerRepresentation() const {
592 if (isIntegralPointer())
593 return Int.Value + (Offset * elemSize());
594 if (isFunctionPointer())
595 return reinterpret_cast<uint64_t>(Fn.Func) + Offset;
596 return reinterpret_cast<uint64_t>(BS.Pointee) + Offset;
597 }
598
599 PtrView view() const {
600 assert(isBlockPointer());
601 return PtrView{BS.Pointee, BS.Base, Offset};
602 }
603
604 /// Converts the pointer to an APValue that is an rvalue.
605 std::optional<APValue> toRValue(const Context &Ctx,
606 QualType ResultType) const;
607
608 /// Offsets a pointer inside an array.
609 [[nodiscard]] Pointer atIndex(uint64_t Idx) const {
610 switch (StorageKind) {
611 case Storage::Int:
612 return Pointer(Int.Value, Int.getType(), Idx);
613 case Storage::Block:
614 return Pointer(view().atIndex(Idx));
615 case Storage::Fn:
616 return Pointer(Fn.Func, Idx);
617 case Storage::String:
618 return Pointer(Str, Idx);
619 default:
620 llvm_unreachable("Unexpected pointer type in atIndex()");
621 }
622 }
623
624 /// Creates a pointer to a field.
625 [[nodiscard]] Pointer atField(unsigned Off) const {
626 return Pointer(view().atField(Off));
627 }
628
629 /// Subtract the given offset from the current Base and Offset
630 /// of the pointer.
631 [[nodiscard]] Pointer atFieldSub(unsigned Off) const {
632 assert(Offset >= Off);
633 unsigned O = Offset - Off;
634 return Pointer(BS.Pointee, O, O);
635 }
636
637 /// Restricts the scope of an array element pointer.
638 [[nodiscard]] Pointer narrow() const {
639 if (!isBlockPointer())
640 return *this;
641 return Pointer(view().narrow());
642 }
643
644 /// Expands a pointer to the containing array, undoing narrowing.
645 [[nodiscard]] Pointer expand() const {
646 if (!isBlockPointer())
647 return *this;
648 return Pointer(view().expand());
649 }
650
651 /// Checks if the pointer is null.
652 bool isZero() const {
653 switch (StorageKind) {
654 case Storage::Int:
655 return Int.isNull();
656 case Storage::Block:
657 return BS.Pointee == nullptr;
658 case Storage::Fn:
659 return !Fn.Func;
660 case Storage::Typeid:
661 case Storage::String:
662 case Storage::Opaque:
663 return false;
664 }
665 llvm_unreachable("Unknown clang::interp::Storage enum");
666 }
667 /// Checks if the pointer is live.
668 bool isLive() const {
669 if (!isBlockPointer())
670 return true;
671 return view().isLive();
672 }
673 /// Checks if the item is a field in an object.
674 bool isField() const {
675 if (!isBlockPointer())
676 return false;
677
678 return view().isField();
679 }
680
681 /// Accessor for information about the declaration site.
682 const Descriptor *getDeclDesc() const {
683 if (!isBlockPointer())
684 return nullptr;
685
686 assert(isBlockPointer());
687 assert(BS.Pointee);
688 return BS.Pointee->Desc;
689 }
690 SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
691
692 /// Returns the expression or declaration the pointer has been created for.
694 if (isBlockPointer())
695 return getDeclDesc()->getSource();
696 if (isFunctionPointer()) {
697 const Function *F = Fn.Func;
698 return F ? F->getDecl() : DeclOrExpr();
699 }
700 llvm_unreachable("Unsupported pointer type in getSource()");
701 return DeclOrExpr();
702 }
703
704 /// Returns a pointer to the object of which this pointer is a field.
705 [[nodiscard]] Pointer getBase() const { return Pointer(view().getBase()); }
706 /// Returns the parent array.
707 [[nodiscard]] Pointer getArray() const { return Pointer(view().getArray()); }
708
709 /// Accessors for information about the innermost field.
710 const Descriptor *getFieldDesc() const {
711 if (!isBlockPointer())
712 return nullptr;
713
714 if (isRoot())
715 return getDeclDesc();
716 return getInlineDesc()->Desc;
717 }
718
719 /// Returns the type of the innermost field.
721 switch (StorageKind) {
722 case Storage::Int:
723 return Int.getPointeeType();
724 case Storage::Block:
725 return view().getType();
726 case Storage::Fn:
727 return Fn.Func->getDecl()->getType();
728 case Storage::Typeid:
729 return QualType(Typeid.TypeInfoType, 0);
730 case Storage::String:
731 if (Str.Decayed)
732 return Str.getLiteral()
733 ->getType()
734 ->getAsArrayTypeUnsafe()
735 ->getElementType();
736 return Str.getLiteral()->getType();
737 case Storage::Opaque:
738 return Opaque.getFieldType();
739 }
740 llvm_unreachable("Unhandled StorageKind");
741 }
742
743 const VarDecl *getRootVarDecl() const;
744 const Expr *getRootExpr() const;
745
746 [[nodiscard]] Pointer getDeclPtr() const { return Pointer(BS.Pointee); }
747
748 /// Returns the element size of the innermost field.
749 size_t elemSize() const {
750 if (isIntegralPointer()) {
751 // FIXME: Remove this and handle int ptrs specially?
752 return 1;
753 }
754 if (isStringPointer())
755 return Str.getLiteral()->getCharByteWidth();
756
757 return view().elemSize();
758 }
759 /// Returns the total size of the innermost field.
760 size_t getSize() const {
761 assert(isBlockPointer());
762 return getFieldDesc()->getSize();
763 }
764
765 /// Returns the offset into an array.
766 unsigned getOffset() const {
767 assert(Offset != PtrView::PastEndMark && "invalid offset");
768 return view().getOffset();
769 }
770
771 /// Whether this array refers to an array, but not
772 /// to the first element.
773 bool isArrayRoot() const { return view().isArrayRoot(); }
774
775 /// Checks if the innermost field is an array.
776 bool inArray() const {
777 if (isBlockPointer())
778 return view().inArray();
779 if (isStringPointer())
780 return true;
781 return false;
782 }
783 bool inUnion() const {
784 if (isBlockPointer() && BS.Base >= sizeof(InlineDescriptor))
785 return view().inUnion();
786 return false;
787 };
788
789 /// Checks if the structure is a primitive array.
790 bool inPrimitiveArray() const {
791 if (isBlockPointer())
792 return view().inPrimitiveArray();
793 return false;
794 }
795 /// Checks if the structure is an array of unknown size.
796 bool isUnknownSizeArray() const {
797 if (isBlockPointer())
798 return getFieldDesc()->isUnknownSizeArray();
799 if (isOpaquePointer())
800 return Opaque.isUnknownSizeArray();
801 return false;
802 }
803 /// Checks if the pointer points to an array.
804 bool isArrayElement() const {
805 if (!isBlockPointer())
806 return false;
807
808 return view().isArrayElement();
809 }
810 /// Pointer points directly to a block.
811 bool isRoot() const {
812 if (isZero())
813 return true;
814 if (isBlockPointer())
815 return view().isRoot();
816 if (isOpaquePointer())
817 return Opaque.isRoot();
818 return true;
819 }
820 /// If this pointer has an InlineDescriptor we can use to initialize.
821 bool canBeInitialized() const {
822 if (!isBlockPointer())
823 return false;
824
825 return BS.Pointee && BS.Base > 0;
826 }
827
828 [[nodiscard]] const BlockPointer &asBlockPointer() const {
829 assert(isBlockPointer());
830 return BS;
831 }
832 [[nodiscard]] const IntPointer &asIntPointer() const {
833 assert(isIntegralPointer());
834 return Int;
835 }
836 [[nodiscard]] const FunctionPointer &asFunctionPointer() const {
837 assert(isFunctionPointer());
838 return Fn;
839 }
840 [[nodiscard]] const TypeidPointer &asTypeidPointer() const {
841 assert(isTypeidPointer());
842 return Typeid;
843 }
844 [[nodiscard]] const StringPointer &asStringPointer() const {
845 assert(isStringPointer());
846 return Str;
847 }
848 [[nodiscard]] const OpaquePointer &asOpaquePointer() const {
849 assert(isOpaquePointer());
850 return Opaque;
851 }
852
853 bool isBlockPointer() const { return StorageKind == Storage::Block; }
854 bool isIntegralPointer() const { return StorageKind == Storage::Int; }
855 bool isFunctionPointer() const { return StorageKind == Storage::Fn; }
856 bool isTypeidPointer() const { return StorageKind == Storage::Typeid; }
857 bool isStringPointer() const { return StorageKind == Storage::String; }
858 bool isOpaquePointer() const { return StorageKind == Storage::Opaque; }
859
860 /// Returns the record descriptor of a class.
861 const Record *getRecord() const {
862 if (!isBlockPointer())
863 return nullptr;
864 return view().getRecord();
865 }
866 /// Returns the element record type, if this is a non-primive array.
867 const Record *getElemRecord() const { return view().getElemRecord(); }
868 /// Returns the field information.
869 const FieldDecl *getField() const {
870 if (const Descriptor *FD = getFieldDesc())
871 return FD->asFieldDecl();
872 return nullptr;
873 }
874
875 /// Checks if the storage is extern.
876 bool isExtern() const {
877 if (isBlockPointer())
878 return view().isExtern();
879 return false;
880 }
881 /// Checks if the storage is static.
882 bool isStatic() const {
883 if (!isBlockPointer())
884 return true;
885 assert(BS.Pointee);
886 return BS.Pointee->isStatic();
887 }
888 /// Checks if the storage is temporary.
889 bool isTemporary() const {
890 if (isBlockPointer()) {
891 assert(BS.Pointee);
892 return BS.Pointee->isTemporary();
893 }
894 return false;
895 }
896 /// Checks if the storage has been dynamically allocated.
897 bool isDynamic() const {
898 if (isBlockPointer()) {
899 assert(BS.Pointee);
900 return BS.Pointee->isDynamic();
901 }
902 return false;
903 }
904 /// Checks if the storage is a static temporary.
905 bool isStaticTemporary() const { return isStatic() && isTemporary(); }
906
907 /// Checks if the field is mutable.
908 bool isMutable() const {
909 if (!isBlockPointer())
910 return false;
911 return view().isMutable();
912 }
913
914 bool isWeak() const {
915 if (isFunctionPointer()) {
916 if (!Fn.Func || !Fn.Func->getDecl())
917 return false;
918
919 return Fn.Func->getDecl()->isWeak();
920 }
921
922 if (isOpaquePointer()) {
923 if (const VarDecl *BaseDecl = Opaque.getBaseDecl())
924 return BaseDecl->isWeak();
925 return false;
926 }
927 if (!isBlockPointer())
928 return false;
929
930 assert(isBlockPointer());
931 return BS.Pointee->isWeak();
932 }
933 /// Checks if the object is active.
934 bool isActive() const {
935 if (!isBlockPointer())
936 return true;
937 return view().isActive();
938 }
939 /// Checks if a structure is a base class.
940 bool isBaseClass() const { return view().isBaseClass(); }
941 bool isVirtualBaseClass() const { return view().isVirtualBaseClass(); }
942
943 /// Checks if the pointer points to a dummy value.
944 bool isDummy() const { return isOpaquePointer(); }
945
946 /// Checks if an object or a subfield is mutable.
947 bool isConst() const {
948 if (isIntegralPointer())
949 return true;
950 if (isStringPointer())
951 return true;
952 if (!isBlockPointer())
953 return false;
954 return view().isConst();
955 }
956 bool isConstInMutable() const {
957 if (!isBlockPointer())
958 return false;
959 return isRoot() ? false : getInlineDesc()->IsConstInMutable;
960 }
961
962 /// Checks if an object or a subfield is volatile.
963 bool isVolatile() const {
964 if (!isBlockPointer())
965 return false;
966 return view().isVolatile();
967 }
968
969 /// Returns the declaration ID.
971 if (isBlockPointer()) {
972 assert(BS.Pointee);
973 return BS.Pointee->getDeclID();
974 }
975 return std::nullopt;
976 }
977
978 /// Returns the byte offset from the start.
979 uint64_t getByteOffset() const {
980 if (isBlockPointer())
981 return isOnePastEnd() ? PtrView::PastEndMark : Offset;
982 return Offset;
983 }
984
985 /// Returns the number of elements.
986 unsigned getNumElems() const {
987 if (isStringPointer())
988 return Str.getLiteral()->getLength() + 1;
989 if (isOpaquePointer()) {
990 const ArrayType *AT =
991 Opaque.getSurroundingArray()->getAsArrayTypeUnsafe();
992 if (const auto *CAT = dyn_cast_if_present<ConstantArrayType>(AT))
993 return CAT->getZExtSize();
994 }
995 if (!isBlockPointer())
996 return ~0u;
997 return view().getNumElems();
998 }
999
1000 const Block *block() const { return BS.Pointee; }
1001
1002 /// If backed by actual data (i.e. a block or string pointer), return
1003 /// an address to that data.
1004 const std::byte *getRawAddress() const {
1005 if (isStringPointer()) {
1006 const StringLiteral *Lit = Str.getLiteral();
1007 return reinterpret_cast<const std::byte *>(
1008 Lit->getBytes().data() + (Offset * Lit->getCharByteWidth()));
1009 }
1010 assert(isBlockPointer());
1011 return BS.Pointee->rawData() + Offset;
1012 }
1013
1014 /// Returns the index into an array.
1015 int64_t getIndex() const {
1016 if (isStringPointer())
1017 return Offset;
1018 if (isOpaquePointer()) {
1019 if (Opaque.isArrayElement())
1020 return Opaque.Path[Opaque.PathLength - 1].Index;
1021 return 0;
1022 }
1023 if (!isBlockPointer())
1024 return getIntegerRepresentation();
1025
1026 return view().getIndex();
1027 }
1028
1029 /// Checks if the index is one past end.
1030 bool isOnePastEnd() const {
1031 if (isStringPointer())
1032 return Offset == (Str.getLiteral()->getLength() + 1);
1033 if (isOpaquePointer())
1034 return Opaque.isOnePastEndOrElementPastEnd();
1035
1036 if (!isBlockPointer())
1037 return false;
1038
1039 if (!BS.Pointee)
1040 return false;
1041
1042 return view().isOnePastEnd();
1043 }
1044
1045 /// Checks if the pointer points past the end of the object.
1046 bool isPastEnd() const {
1047 if (isIntegralPointer())
1048 return false;
1049 if (isStringPointer())
1050 return Offset >= (Str.getLiteral()->getLength() + 1);
1051
1052 return !isZero() && Offset > BS.Pointee->getSize();
1053 }
1054
1055 /// Checks if the pointer is an out-of-bounds element pointer.
1056 bool isElementPastEnd() const { return Offset == PtrView::PastEndMark; }
1057
1058 /// Checks if the pointer is pointing to a zero-size array.
1059 bool isZeroSizeArray() const {
1060 if (isFunctionPointer())
1061 return false;
1062 if (isOpaquePointer())
1063 return false; // FIXME: Can actually happen I think?
1064 if (const auto *Desc = getFieldDesc())
1065 return Desc->isZeroSizeArray();
1066 return false;
1067 }
1068
1069 /// Checks whether the pointer can be dereferenced to the given PrimType.
1070 bool canDeref(PrimType T) const {
1071 if (isStringPointer()) {
1072 switch (Str.getLiteral()->getCharByteWidth()) {
1073 case 1:
1074 return T == PT_Sint8 || T == PT_Uint8;
1075 case 2:
1076 return T == PT_Sint16 || T == PT_Uint16;
1077 case 4:
1078 return T == PT_Sint32 || T == PT_Uint32;
1079 }
1080
1081 return false;
1082 }
1083
1084 assert(isBlockPointer());
1085 if (const Descriptor *FieldDesc = getFieldDesc()) {
1086 return (FieldDesc->isPrimitive() || FieldDesc->isPrimitiveArray()) &&
1087 FieldDesc->getPrimType() == T;
1088 }
1089 return false;
1090 }
1091
1092 /// Dereferences the pointer, if it's live.
1093 template <typename T> T &deref() const {
1094 assert(isLive() && "Invalid pointer");
1095 assert(isBlockPointer());
1096 assert(BS.Pointee);
1097 assert(isDereferencable());
1098 assert(Offset + sizeof(T) <= BS.Pointee->getSize());
1099 return view().deref<T>();
1100 }
1101
1102 template <typename T> T load() const {
1103 assert(isLive() && "Invalid pointer");
1104 if (isBlockPointer()) {
1105 assert(BS.Pointee);
1106 assert(isDereferencable());
1107 assert(Offset + sizeof(T) <= BS.Pointee->getSize());
1108 return view().deref<T>();
1109 }
1110
1111 if (isStringPointer()) {
1112 const StringLiteral *Lit = Str.getLiteral();
1113
1114 if constexpr (isFixedSizeIntegralType<T>()) {
1115 // The literal does not include the nul byte.
1116 if (Offset >= Lit->getLength())
1117 return T::from('\0');
1118 return T::from(Lit->getCodeUnit(Offset));
1119 } else if constexpr (std::is_integral_v<T>) {
1120 if (Offset >= Lit->getLength())
1121 return '\0';
1122 return Lit->getCodeUnit(Offset);
1123 }
1124 }
1125
1126 llvm_unreachable("Unexpected pointer type in load()");
1127 }
1128
1129 /// Dereferences the element at index \p I.
1130 /// This is equivalent to atIndex(I).deref<T>().
1131 template <typename T> T &elem(unsigned I) const {
1132 assert(isLive() && "Invalid pointer");
1133 assert(isBlockPointer());
1134 assert(BS.Pointee);
1135 assert(isDereferencable());
1136 assert(getFieldDesc()->isPrimitiveArray());
1137 assert(I < getFieldDesc()->getNumElems());
1138
1139 return view().elem<T>(I);
1140 }
1141
1142 template <typename T> T loadElem(unsigned I) const {
1143 assert(isLive() && "Invalid pointer");
1144 if (isBlockPointer()) {
1145 assert(BS.Pointee);
1146 assert(isDereferencable());
1147 assert(getFieldDesc()->isPrimitiveArray());
1148 assert(I < getFieldDesc()->getNumElems());
1149
1150 return view().elem<T>(I);
1151 }
1152
1153 assert(isStringPointer());
1154 const StringLiteral *Lit = Str.getLiteral();
1155 unsigned Index = Offset + I;
1156 if constexpr (isFixedSizeIntegralType<T>()) {
1157 // The literal does not include the nul byte.
1158 if (Index >= Lit->getLength())
1159 return T::from('\0');
1160 return T::from(Lit->getCodeUnit(Index));
1161 } else if constexpr (std::is_integral_v<T>) {
1162 if (Index >= Lit->getLength())
1163 return '\0';
1164 return Lit->getCodeUnit(Index);
1165 }
1166 llvm_unreachable("Unexpected pointer type in loadElem()");
1167 }
1168
1169 bool isConstexprUnknown() const {
1170 if (isOpaquePointer())
1171 return Opaque.isConstexprUnknown();
1172 if (isBlockPointer())
1173 return getDeclDesc()->IsConstexprUnknown;
1174 return false;
1175 }
1176
1177 /// Whether this block can be read from at all. This is only true for
1178 /// block pointers that point to a valid location inside that block.
1179 bool isDereferencable() const {
1180 if (!isBlockPointer())
1181 return false;
1182 if (isDummy())
1183 return false;
1184 if (isConstexprUnknown())
1185 return false;
1186 if (isPastEnd())
1187 return false;
1188
1189 return true;
1190 }
1191
1193 return StorageKind == Storage::Block || StorageKind == Storage::String;
1194 }
1195
1196 /// Initializes a field.
1197 void initialize() const {
1198 if (!isBlockPointer())
1199 return;
1200 view().initialize();
1201 }
1202 /// Initialized the given element of a primitive array.
1203 void initializeElement(unsigned Index) const {
1204 view().initializeElement(Index);
1205 }
1206 /// Initialize all elements of a primitive array at once. This can be
1207 /// used in situations where we *know* we have initialized *all* elements
1208 /// of a primtive array.
1209 void initializeAllElements() const;
1210 /// Checks if an object was initialized.
1211 bool isInitialized() const;
1212 /// Like isInitialized(), but for primitive arrays.
1213 bool isElementInitialized(unsigned Index) const {
1214 if (!isBlockPointer())
1215 return true;
1216
1217 return view().isElementInitialized(Index);
1218 }
1220 assert(getFieldDesc()->isPrimitiveArray());
1221 assert(isArrayRoot());
1222 return view().allElementsInitialized();
1223 }
1224 bool allElementsAlive() const;
1225 bool isElementAlive(unsigned Index) const;
1226
1227 /// Activates a field.
1228 void activate() const { view().activate(); }
1229 /// Deactivates an entire strurcutre.
1230 void deactivate() const {
1231 // TODO: this only appears in constructors, so nothing to deactivate.
1232 }
1233
1235 if (!isBlockPointer())
1236 return Lifetime::Started;
1237 return view().getLifetime();
1238 }
1239
1240 /// Start the lifetime of this pointer. This works for pointer with an
1241 /// InlineDescriptor as well as primitive array elements. Pointers are usually
1242 /// alive by default, unless the underlying object has been allocated with
1243 /// std::allocator. This function is used by std::construct_at.
1245 /// Ends the lifetime of the pointer. This works for pointer with an
1246 /// InlineDescriptor as well as primitive array elements. This function is
1247 /// used by std::destroy_at.
1249
1250 void setLifeState(Lifetime L) const {
1251 if (!isBlockPointer())
1252 return;
1253 view().setLifeState(L);
1254 };
1255
1256 /// Strip base casts from this Pointer.
1257 /// The result is either a root pointer or something
1258 /// that isn't a base class anymore.
1259 [[nodiscard]] Pointer stripBaseCasts() const {
1260 return Pointer(view().stripBaseCasts());
1261 }
1262
1263 /// Compare two pointers.
1265 if (!hasSameBase(*this, Other))
1267
1268 if (Offset < Other.Offset)
1270 if (Offset > Other.Offset)
1272
1274 }
1275
1276 /// Checks if two pointers are comparable.
1277 static bool hasSameBase(const Pointer &A, const Pointer &B);
1278 /// Checks if two pointers can be subtracted.
1279 static bool elemsOfSameArray(const Pointer &A, const Pointer &B);
1280 /// Checks if both given pointers point to the same block.
1281 static bool pointToSameBlock(const Pointer &A, const Pointer &B);
1282
1283 static std::optional<std::pair<PtrView, PtrView>>
1284 computeSplitPoint(const Pointer &A, const Pointer &B);
1285
1286 /// Whether this points to a block that's been created for a "literal lvalue",
1287 /// i.e. a non-MaterializeTemporaryExpr Expr.
1288 bool pointsToLiteral() const;
1289 /// Whether this points to a block created for an AddrLabelExpr.
1290 bool pointsToLabel() const;
1291 /// Returns the AddrLabelExpr the Pointer points to, if any.
1293 return dyn_cast_if_present<AddrLabelExpr>(getRootExpr());
1294 }
1295
1296 /// Prints the pointer.
1297 void print(llvm::raw_ostream &OS) const;
1298
1299 /// Compute an integer that can be used to compare this pointer to
1300 /// another one. This is usually NOT the same as the pointer offset
1301 /// regarding the AST record layout.
1302 std::optional<size_t>
1303 computeOffsetForComparison(const ASTContext &ASTCtx) const;
1304 /// Compute the pointer offset as given by the ASTRecordLayout.
1305 /// Returns the result in bytes.
1306 std::optional<size_t> computeLayoutOffset(const ASTContext &ASTCtx) const;
1307
1308private:
1309 friend class Block;
1310 friend class DeadBlock;
1311 friend class MemberPointer;
1312 friend class InterpState;
1313 friend class DynamicAllocator;
1314 friend class Program;
1315
1316 /// Returns the embedded descriptor preceding a field.
1317 InlineDescriptor *getInlineDesc() const {
1318 assert(isBlockPointer());
1319 assert(BS.Base != sizeof(GlobalInlineDescriptor));
1320 assert(BS.Base <= BS.Pointee->getSize());
1321 assert(BS.Base >= sizeof(InlineDescriptor));
1322 return getDescriptor(BS.Base);
1323 }
1324
1325 /// Returns a descriptor at a given offset.
1326 InlineDescriptor *getDescriptor(unsigned Offset) const {
1327 assert(Offset != 0 && "Not a nested pointer");
1328 assert(isBlockPointer());
1329 assert(!isZero());
1330 return view().getDescriptor(Offset);
1331 }
1332
1333 /// Returns a reference to the InitMapPtr which stores the initialization map.
1334 InitMapPtr &getInitMap() const {
1335 assert(isBlockPointer());
1336 assert(!isZero());
1337 return view().getInitMap();
1338 }
1339
1340 /// Offset into the storage.
1341 uint64_t Offset = 0;
1342
1343 Storage StorageKind = Storage::Int;
1344 union {
1351 };
1352};
1353
1354inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
1355 P.print(OS);
1356 OS << ' ';
1357 if (P.isZero())
1358 return OS;
1359
1360 if (const Descriptor *D = P.getFieldDesc())
1361 D->dump(OS);
1362 if (P.isArrayElement()) {
1363 if (P.isOnePastEnd())
1364 OS << " one-past-the-end";
1365 else {
1366 OS << ' ';
1367 std::string Indices;
1368 llvm::raw_string_ostream SS(Indices);
1369 Pointer K = P;
1370 while (K.isArrayElement()) {
1371 SS << ']' << K.expand().getIndex() << '[';
1372 K = K.expand().getArray();
1373 }
1374 std::reverse(Indices.begin(), Indices.end());
1375 OS << Indices;
1376 }
1377 } else if (P.isBlockPointer() && P.isArrayRoot())
1378 OS << " arrayroot";
1379
1380 if (P.isDummy())
1381 OS << " dummy";
1382 if (!P.isLive())
1383 OS << " dead";
1384 if (P.isBlockPointer() && P.isBaseClass())
1385 OS << " base-class";
1386 return OS;
1387}
1388
1389} // namespace interp
1390} // namespace clang
1391
1392#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:1123
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
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:8428
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:8764
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:881
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9317
bool isPointerOrReferenceType() const
Definition TypeBase.h:8669
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:48
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:540
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition Pointer.cpp:961
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition Pointer.h:638
friend class Program
Definition Pointer.h:1314
OpaquePointer Opaque
Definition Pointer.h:1350
UnsignedOrNone getDeclID() const
Returns the declaration ID.
Definition Pointer.h:970
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
Definition Pointer.h:1259
const Expr * getRootExpr() const
Definition Pointer.cpp:1331
bool isVolatile() const
Checks if an object or a subfield is volatile.
Definition Pointer.h:963
bool isStatic() const
Checks if the storage is static.
Definition Pointer.h:882
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition Pointer.h:897
bool inUnion() const
Definition Pointer.h:783
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:1059
FunctionPointer Fn
Definition Pointer.h:1347
bool allElementsInitialized() const
Definition Pointer.h:1219
T loadElem(unsigned I) const
Definition Pointer.h:1142
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition Pointer.h:609
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:944
const AddrLabelExpr * getPointedToLabel() const
Returns the AddrLabelExpr the Pointer points to, if any.
Definition Pointer.h:1292
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
Definition Pointer.h:631
bool inPrimitiveArray() const
Checks if the structure is a primitive array.
Definition Pointer.h:790
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition Pointer.cpp:458
bool isExtern() const
Checks if the storage is extern.
Definition Pointer.h:876
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:1015
friend class MemberPointer
Definition Pointer.h:1311
bool isOpaquePointer() const
Definition Pointer.h:858
bool isActive() const
Checks if the object is active.
Definition Pointer.h:934
bool isStringPointer() const
Definition Pointer.h:857
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
Definition Pointer.h:1070
bool isConst() const
Checks if an object or a subfield is mutable.
Definition Pointer.h:947
DeclOrExpr getSource() const
Returns the expression or declaration the pointer has been created for.
Definition Pointer.h:693
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition Pointer.h:625
bool isWeak() const
Definition Pointer.h:914
T & deref() const
Dereferences the pointer, if it's live.
Definition Pointer.h:1093
Pointer(IntPointer &&IntPtr)
Definition Pointer.h:543
bool isMutable() const
Checks if the field is mutable.
Definition Pointer.h:908
bool isConstInMutable() const
Definition Pointer.h:956
unsigned getNumElems() const
Returns the number of elements.
Definition Pointer.h:986
Pointer getArray() const
Returns the parent array.
Definition Pointer.h:707
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition Pointer.h:796
const TypeidPointer & asTypeidPointer() const
Definition Pointer.h:840
bool isIntegralPointer() const
Definition Pointer.h:854
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:720
bool isArrayElement() const
Checks if the pointer points to an array.
Definition Pointer.h:804
void initialize() const
Initializes a field.
Definition Pointer.h:1197
Pointer(uint64_t Address, const Type *Ty, uint64_t Offset=0, std::optional< bool > IsNull=std::nullopt)
Definition Pointer.h:549
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition Pointer.h:773
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:668
bool inArray() const
Checks if the innermost field is an array.
Definition Pointer.h:776
const StringPointer & asStringPointer() const
Definition Pointer.h:844
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Definition Pointer.h:905
Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset=0)
Definition Pointer.h:555
T & elem(unsigned I) const
Dereferences the element at index I.
Definition Pointer.h:1131
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:705
uint64_t getByteOffset() const
Returns the byte offset from the start.
Definition Pointer.h:979
bool isTypeidPointer() const
Definition Pointer.h:856
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:652
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
Definition Pointer.h:1264
bool isConstexprUnknown() const
Definition Pointer.h:1169
const IntPointer & asIntPointer() const
Definition Pointer.h:832
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:811
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:682
void activate() const
Activates a field.
Definition Pointer.h:1228
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
Definition Pointer.h:867
const OpaquePointer & asOpaquePointer() const
Definition Pointer.h:848
unsigned getOffset() const
Returns the offset into an array.
Definition Pointer.h:766
friend class DynamicAllocator
Definition Pointer.h:1313
void endLifetime() const
Ends the lifetime of the pointer.
Definition Pointer.h:1248
void setLifeState(Lifetime L) const
Definition Pointer.h:1250
bool isOnePastEnd() const
Checks if the index is one past end.
Definition Pointer.h:1030
friend class InterpState
Definition Pointer.h:1312
uint64_t getIntegerRepresentation() const
Definition Pointer.h:591
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition Pointer.h:1046
Pointer(const Function *F, uint64_t Offset=0)
Definition Pointer.h:553
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:869
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition Pointer.h:645
friend class Block
Definition Pointer.h:1309
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:1056
bool isDereferencable() const
Whether this block can be read from at all.
Definition Pointer.h:1179
void startLifetime() const
Start the lifetime of this pointer.
Definition Pointer.h:1244
Pointer(OpaquePointer OP, uint64_t Offset=0)
Definition Pointer.h:572
bool isBlockPointer() const
Definition Pointer.h:853
bool operator!=(const Pointer &P) const
Definition Pointer.h:583
void deactivate() const
Deactivates an entire strurcutre.
Definition Pointer.h:1230
friend class DeadBlock
Definition Pointer.h:1310
TypeidPointer Typeid
Definition Pointer.h:1348
size_t getSize() const
Returns the total size of the innermost field.
Definition Pointer.h:760
bool isTemporary() const
Checks if the storage is temporary.
Definition Pointer.h:889
StringPointer Str
Definition Pointer.h:1349
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:836
SourceLocation getDeclLoc() const
Definition Pointer.h:690
const Block * block() const
Definition Pointer.h:1000
void initializeElement(unsigned Index) const
Initialized the given element of a primitive array.
Definition Pointer.h:1203
Pointer(DeclOrExpr DOE, bool ConstexprUnknown=false)
Definition Pointer.h:565
bool isFunctionPointer() const
Definition Pointer.h:855
Pointer getDeclPtr() const
Definition Pointer.h:746
bool isReadablePointerType() const
Definition Pointer.h:1192
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:710
PtrView view() const
Definition Pointer.h:599
bool isVirtualBaseClass() const
Definition Pointer.h:941
Pointer(const Expr *Base, unsigned Id)
Definition Pointer.h:560
bool isBaseClass() const
Checks if a structure is a base class.
Definition Pointer.h:940
size_t elemSize() const
Returns the element size of the innermost field.
Definition Pointer.h:749
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Definition Pointer.h:821
Lifetime getLifetime() const
Definition Pointer.h:1234
const BlockPointer & asBlockPointer() const
Definition Pointer.h:828
Pointer(StringPointer Str, uint64_t Offset=0)
Definition Pointer.h:562
const std::byte * getRawAddress() const
If backed by actual data (i.e.
Definition Pointer.h:1004
bool isField() const
Checks if the item is a field in an object.
Definition Pointer.h:674
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition Pointer.h:1213
const Record * getRecord() const
Returns the record descriptor of a class.
Definition Pointer.h:861
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:351
Pointer * Next
Next link in the pointer chain.
Definition Pointer.h:353
unsigned Base
Start of the current subfield.
Definition Pointer.h:349
Block * Pointee
The block the pointer is pointing to.
Definition Pointer.h:347
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:366
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
Definition Pointer.cpp:1370
const Type * getType() const
Definition Pointer.h:363
llvm::PointerIntPair< const Type *, 1, bool > TypeAndIsNull
Definition Pointer.h:357
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1341
OpaquePointer withFieldType(const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
Definition Pointer.h:452
llvm::PointerIntPair< const Type *, 2, unsigned > FieldType
Definition Pointer.h:442
OpaquePointer withPastEnd(bool PastEnd) const
Definition Pointer.h:471
QualType getObjectType() const
Definition Pointer.h:479
bool isRoot() const
Check if the pointer has offset 0.
Definition Pointer.cpp:1499
QualType getSurroundingArray() const
If this is pointing to an array element, return the array.
Definition Pointer.cpp:1468
const VarDecl * getBaseDecl() const
Definition Pointer.h:448
const Expr * getBaseExpr() const
Definition Pointer.h:449
bool isOnePastEndOrElementPastEnd() const
This is used in Pointer::isOnePastEnd().
Definition Pointer.cpp:1556
const PointerPathEntry * Path
Definition Pointer.h:443
ArrayRef< PointerPathEntry > path() const
Definition Pointer.h:446
bool isArrayElement() const
Definition Pointer.h:492
QualType getFieldType() const
Definition Pointer.h:486
bool isConstexprUnknown() const
Definition Pointer.h:503
OpaquePointer withPath(const PointerPathEntry *Path, unsigned PathLength, const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
Definition Pointer.h:461
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Definition Pointer.cpp:1406
static PointerPathEntry array(int64_t Index)
Definition Pointer.h:417
static PointerPathEntry field(const FieldDecl *FD)
Definition Pointer.h:431
llvm::PointerIntPair< const CXXRecordDecl *, 1, bool > RD
Definition Pointer.h:407
enum clang::interp::PointerPathEntry::@133156275124227243235357227301330162015140142322 Kind
static PointerPathEntry negativeArray(int64_t Index)
Definition Pointer.h:424
static PointerPathEntry base(const CXXRecordDecl *RD, bool Virtual=false)
Definition Pointer.h:410
bool isUnknownSizeArray() const
Definition Pointer.h:172
const Descriptor * getDeclDesc() const
Definition Pointer.h:89
bool allElementsInitialized() const
Definition Pointer.cpp:868
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:740
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:901
InlineDescriptor * getDescriptor(unsigned Offset) const
Definition Pointer.h:77
bool inArray() const
Definition Pointer.h:57
void startLifetime() const
Definition Pointer.h:334
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:326
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:335
void initializeElement(unsigned Index) const
Definition Pointer.cpp:840
bool operator==(const PtrView &Other) const
Definition Pointer.h:337
void initialize() const
Definition Pointer.cpp:819
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:797
Lifetime getLifetime() const
Definition Pointer.cpp:778
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:342
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:395
StringPointer decay() const
Definition Pointer.h:394