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