13#ifndef LLVM_CLANG_AST_INTERP_POINTER_H
14#define LLVM_CLANG_AST_INTERP_POINTER_H
24#include "llvm/Support/raw_ostream.h"
77 assert(
Offset != 0 &&
"Not a nested pointer");
84 return Pointee->getDescriptor();
145 while (
V.isBaseClass())
151 assert(
Offset !=
Base &&
"not an array element");
158 return ElemDesc ? ElemDesc->
ElemRecord :
nullptr;
247 assert(
isLive() &&
"Invalid pointer");
257 template <
typename T>
T &
elem(
unsigned I)
const {
258 assert(
isLive() &&
"Invalid pointer");
265 assert(ReadOffset +
sizeof(
T) <=
Pointee->getSize());
267 return *
reinterpret_cast<T *
>(
Pointee->data() + ReadOffset);
276 unsigned F = this->Offset +
Offset;
286 return VD->getType();
293 return AT->getElementType();
295 return CT->getElementType();
297 return CT->getElementType();
319 assert(
Pointee &&
"Cannot check if null pointer was initialized");
366 std::optional<IntPointer>
atOffset(
const Context &Ctx,
unsigned Offset)
const;
402 if (
const auto *PE = dyn_cast<PredefinedExpr>(
Base))
403 return PE->getFunctionName();
413 llvm::PointerIntPair<const CXXRecordDecl *, 1, bool>
RD = {};
448 llvm::PointerIntPair<const Type *, 2, unsigned>
FieldType = {};
461 std::optional<bool> PastEnd = std::nullopt)
const {
462 unsigned NewBitFieldValue =
FieldType.getInt();
471 std::optional<bool> PastEnd = std::nullopt)
const {
472 unsigned NewBitFieldValue =
FieldType.getInt();
482 FieldType.getInt() |
static_cast<unsigned>(PastEnd)},
489 if (
T->isPointerOrReferenceType())
490 return T->getPointeeType();
495 if (
FieldType.getPointer()->isPointerOrReferenceType() &&
Base.isDecl())
496 return FieldType.getPointer()->getPointeeType();
558 std::optional<bool>
IsNull = std::nullopt)
562 : Offset(Offset), StorageKind(
Storage::
Fn),
Fn{F} {}
566 Typeid.TypeInfoType = TypeInfoType;
597 std::string toDiagnosticString(
const ASTContext &Ctx)
const;
603 return reinterpret_cast<uint64_t
>(
Fn.Func) + Offset;
604 return reinterpret_cast<uint64_t
>(
BS.Pointee) + Offset;
618 switch (StorageKind) {
628 llvm_unreachable(
"Unexpected pointer type in atIndex()");
640 assert(Offset >=
Off);
641 unsigned O = Offset -
Off;
661 switch (StorageKind) {
665 return BS.Pointee ==
nullptr;
673 llvm_unreachable(
"Unknown clang::interp::Storage enum");
679 return view().isLive();
686 return view().isField();
696 return BS.Pointee->Desc;
708 llvm_unreachable(
"Unsupported pointer type in getSource()");
724 return getInlineDesc()->Desc;
729 switch (StorageKind) {
731 return Int.getPointeeType();
733 return view().getType();
735 return Fn.Func->getType();
740 return Str.getLiteral()
742 ->getAsArrayTypeUnsafe()
744 return Str.getLiteral()->getType();
746 return Opaque.getFieldType();
748 llvm_unreachable(
"Unhandled StorageKind");
751 const VarDecl *getRootVarDecl()
const;
752 const ValueDecl *getRootValueDecl()
const;
753 const Expr *getRootExpr()
const;
764 return Str.getLiteral()->getCharByteWidth();
766 return view().elemSize();
777 return view().getOffset();
783 switch (StorageKind) {
785 return view().isArrayRoot();
793 llvm_unreachable(
"Unhandled storage kind");
798 switch (StorageKind) {
800 return view().inArray();
809 llvm_unreachable(
"Unhandled storage kind");
813 return view().inUnion();
820 return view().inPrimitiveArray();
828 return Opaque.isUnknownSizeArray();
836 return view().isArrayElement();
843 return view().isRoot();
852 return view().canBeInitialized();
891 return view().getRecord();
898 return FD->asFieldDecl();
905 return view().isExtern();
913 return BS.Pointee->isGlobal();
919 return BS.Pointee->isTemporary();
927 return BS.Pointee->isDynamic();
938 return view().isMutable();
942 switch (StorageKind) {
944 if (!
Fn.Func || !
Fn.Func->getDecl())
946 return Fn.Func->getDecl()->isWeak();
949 return BaseDecl->isWeak();
952 return BS.Pointee->isWeak();
956 llvm_unreachable(
"Unhandled storage kind");
962 return view().isActive();
979 return view().isConst();
984 return isRoot() ?
false : getInlineDesc()->IsConstInMutable;
991 return view().isVolatile();
998 return BS.Pointee->getDeclID();
1000 return std::nullopt;
1013 return Str.getLiteral()->getLength() + 1;
1016 Opaque.getSurroundingArray()->getAsArrayTypeUnsafe();
1017 if (
const auto *CAT = dyn_cast_if_present<ConstantArrayType>(AT))
1018 return CAT->getZExtSize();
1022 return view().getNumElems();
1035 return reinterpret_cast<const std::byte *
>(
1039 return BS.Pointee->data() + Offset;
1047 if (
Opaque.isArrayElement())
1054 return view().getIndex();
1060 return Offset == (
Str.getLiteral()->getLength() + 1);
1062 return Opaque.isOnePastEndOrElementPastEnd();
1070 return view().isOnePastEnd();
1078 return Offset >= (
Str.getLiteral()->getLength() + 1);
1080 return !
isZero() && Offset >
BS.Pointee->getSize();
1093 return Desc->isZeroSizeArray();
1100 switch (
Str.getLiteral()->getCharByteWidth()) {
1114 return (FieldDesc->isPrimitive() || FieldDesc->isPrimitiveArray()) &&
1115 FieldDesc->getPrimType() ==
T;
1122 assert(
isLive() &&
"Invalid pointer");
1126 assert(Offset +
sizeof(
T) <=
BS.Pointee->getSize());
1127 return view().deref<
T>();
1131 assert(
isLive() &&
"Invalid pointer");
1135 assert(Offset +
sizeof(
T) <=
BS.Pointee->getSize());
1136 return view().deref<
T>();
1145 return T::from(
'\0');
1147 }
else if constexpr (std::is_integral_v<T>) {
1154 llvm_unreachable(
"Unexpected pointer type in load()");
1159 template <
typename T>
T &
elem(
unsigned I)
const {
1160 assert(
isLive() &&
"Invalid pointer");
1167 return view().elem<
T>(I);
1171 assert(
isLive() &&
"Invalid pointer");
1178 return view().elem<
T>(I);
1183 unsigned Index = Offset + I;
1187 return T::from(
'\0');
1189 }
else if constexpr (std::is_integral_v<T>) {
1194 llvm_unreachable(
"Unexpected pointer type in loadElem()");
1199 return Opaque.isConstexprUnknown();
1228 view().initialize();
1232 view().initializeElement(Index);
1237 void initializeAllElements()
const;
1243 return view().isInitialized();
1251 return view().isElementInitialized(Index);
1256 return view().allElementsInitialized();
1258 bool allElementsAlive()
const;
1259 bool isElementAlive(
unsigned Index)
const;
1271 return view().getLifetime();
1287 view().setLifeState(L);
1302 if (Offset <
Other.Offset)
1304 if (Offset >
Other.Offset)
1313 static bool elemsOfSameArray(
const Pointer &A,
const Pointer &B);
1315 static bool pointToSameBlock(
const Pointer &A,
const Pointer &B);
1317 static std::optional<std::pair<PtrView, PtrView>>
1322 bool pointsToLiteral()
const;
1324 bool pointsToLabel()
const;
1327 return dyn_cast_if_present<AddrLabelExpr>(
getRootExpr());
1331 void print(llvm::raw_ostream &OS)
const;
1336 std::optional<size_t>
1337 computeOffsetForComparison(
const ASTContext &ASTCtx)
const;
1340 std::optional<size_t> computeLayoutOffset(
const ASTContext &ASTCtx)
const;
1353 assert(
BS.Base <=
BS.Pointee->getSize());
1354 assert(
BS.Base != 0);
1355 return getDescriptor(
BS.Base);
1360 assert(Offset != 0 &&
"Not a nested pointer");
1363 return view().getDescriptor(Offset);
1367 InitMapPtr &getInitMap()
const {
1370 return view().getInitMap();
1374 uint64_t Offset = 0;
1376 Storage StorageKind = Storage::Int;
1397 OS <<
" one-past-the-end";
1400 std::string Indices;
1401 llvm::raw_string_ostream SS(Indices);
1407 std::reverse(Indices.begin(), Indices.end());
1418 OS <<
" base-class";
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
static void print(llvm::raw_ostream &OS, const T &V, const Context &Ctx, QualType Ty)
static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R)
Convert a pointer to a composite value to an rvalue.
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AddrLabelExpr - The GNU address of label extension, representing &&label.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
QualType getElementType() const
Represents a C++ struct/union/class.
This represents one expression.
Represents a member of a struct/union/class.
A (possibly-)qualified type.
QualType IgnoreParens() const
Returns the specified type after dropping any outer-level parentheses.
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Encodes a location in the source.
StringLiteral - This represents a string literal expression, e.g.
unsigned getLength() const
uint32_t getCodeUnit(size_t I) const
Return the code unit at the given position.
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
unsigned getCharByteWidth() const
The base class of the type hierarchy.
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
bool isPointerOrReferenceType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
A memory block, either on the stack or in the heap.
Holds all information required to evaluate constexpr code in a module.
Descriptor for a dead block.
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
A pointer to a memory block, live or dead.
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Pointer narrow() const
Restricts the scope of an array element pointer.
UnsignedOrNone getDeclID() const
Returns the declaration ID.
Pointer stripBaseCasts() const
Strip base casts from this Pointer.
const Expr * getRootExpr() const
bool isVolatile() const
Checks if an object or a subfield is volatile.
bool isStatic() const
Checks if the storage is static.
bool isDynamic() const
Checks if the storage has been dynamically allocated.
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
bool allElementsInitialized() const
T loadElem(unsigned I) const
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
bool isDummy() const
Checks if the pointer points to a dummy value.
const AddrLabelExpr * getPointedToLabel() const
Returns the AddrLabelExpr the Pointer points to, if any.
Pointer atFieldSub(unsigned Off) const
Subtract the given offset from the current Base and Offset of the pointer.
bool inPrimitiveArray() const
Checks if the structure is a primitive array.
void print(llvm::raw_ostream &OS) const
Prints the pointer.
bool isExtern() const
Checks if the storage is extern.
int64_t getIndex() const
Returns the index into an array.
friend class MemberPointer
bool isOpaquePointer() const
bool isActive() const
Checks if the object is active.
bool isStringPointer() const
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
bool isConst() const
Checks if an object or a subfield is mutable.
DeclOrExpr getSource() const
Returns the expression or declaration the pointer has been created for.
Pointer atField(unsigned Off) const
Creates a pointer to a field.
T & deref() const
Dereferences the pointer, if it's live.
Pointer(IntPointer &&IntPtr)
bool isMutable() const
Checks if the field is mutable.
bool isConstInMutable() const
unsigned getNumElems() const
Returns the number of elements.
Pointer getArray() const
Returns the parent array.
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
const TypeidPointer & asTypeidPointer() const
bool isIntegralPointer() const
QualType getType() const
Returns the type of the innermost field.
bool isArrayElement() const
Checks if the pointer points to an array.
void initialize() const
Initializes a field.
Pointer(uint64_t Address, const Type *Ty, uint64_t Offset=0, std::optional< bool > IsNull=std::nullopt)
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
bool isLive() const
Checks if the pointer is live.
bool inArray() const
Checks if the innermost field is an array.
const StringPointer & asStringPointer() const
bool isStaticTemporary() const
Checks if the storage is a static temporary.
Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset=0)
T & elem(unsigned I) const
Dereferences the element at index I.
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
uint64_t getByteOffset() const
Returns the byte offset from the start.
bool isTypeidPointer() const
bool isZero() const
Checks if the pointer is null.
ComparisonCategoryResult compare(const Pointer &Other) const
Compare two pointers.
bool isConstexprUnknown() const
const IntPointer & asIntPointer() const
bool isRoot() const
Pointer points directly to a block.
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
void activate() const
Activates a field.
const Record * getElemRecord() const
Returns the element record type, if this is a non-primive array.
const OpaquePointer & asOpaquePointer() const
unsigned getOffset() const
Returns the offset into an array.
friend class DynamicAllocator
void endLifetime() const
Ends the lifetime of the pointer.
void setLifeState(Lifetime L) const
bool isOnePastEnd() const
Checks if the index is one past end.
uint64_t getIntegerRepresentation() const
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Pointer(const Function *F, uint64_t Offset=0)
const FieldDecl * getField() const
Returns the field information.
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
bool isDereferencable() const
Whether this block can be read from at all.
void startLifetime() const
Start the lifetime of this pointer.
Pointer(OpaquePointer OP, uint64_t Offset=0)
bool isBlockPointer() const
bool operator!=(const Pointer &P) const
void deactivate() const
Deactivates an entire strurcutre.
bool isInitialized() const
Checks if an object was initialized.
size_t getSize() const
Returns the total size of the innermost field.
bool isTemporary() const
Checks if the storage is temporary.
const FunctionPointer & asFunctionPointer() const
SourceLocation getDeclLoc() const
const Block * block() const
void initializeElement(unsigned Index) const
Initialized the given element of a primitive array.
Pointer(DeclOrExpr DOE, bool ConstexprUnknown=false)
bool isFunctionPointer() const
Pointer getDeclPtr() const
bool isReadablePointerType() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
bool isVirtualBaseClass() const
Pointer(const Expr *Base, unsigned Id)
bool isBaseClass() const
Checks if a structure is a base class.
size_t elemSize() const
Returns the element size of the innermost field.
bool canBeInitialized() const
If this pointer has an InlineDescriptor we can use to initialize.
Lifetime getLifetime() const
const BlockPointer & asBlockPointer() const
Pointer(StringPointer Str, uint64_t Offset=0)
const std::byte * getRawAddress() const
If backed by actual data (i.e.
bool isField() const
Checks if the item is a field in an object.
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
const Record * getRecord() const
Returns the record descriptor of a class.
Structure/Class descriptor.
@ Address
A pointer to a ValueDecl.
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const Boolean &B)
static bool isFixedSizeIntegralType(PrimType T)
PrimType
Enumeration of the primitive types of the VM.
Top level wrappers for InstallAPI frontend operations.
bool operator==(const CallGraphNode::CallRecord &LHS, const CallGraphNode::CallRecord &RHS)
ComparisonCategoryResult
An enumeration representing the possible results of a three-way comparison.
OptionalUnsigned< unsigned > UnsignedOrNone
const FunctionProtoType * T
static bool isBlockPointer(Expr *Arg)
@ Off
Never emit colors regardless of the output stream.
const StreamingDiagnostic & operator<<(const StreamingDiagnostic &DB, const ConceptReference *C)
Insertion operator for diagnostics.
U cast(CodeGen::Address addr)
@ Other
Other implicit parameter.
Pointer * Prev
Previous link in the pointer chain.
Pointer * Next
Next link in the pointer chain.
unsigned Base
Start of the current subfield.
Block * Pointee
The block the pointer is pointing to.
Describes a memory block created by an allocation site.
const bool IsConst
Flag indicating if the block is mutable.
unsigned getSize() const
Returns the size of the object without metadata.
const Decl * asDecl() const
const Descriptor *const ElemDesc
Descriptor of the array element.
bool isUnknownSizeArray() const
Checks if the descriptor is of an array of unknown size.
unsigned getElemSize() const
returns the size of an element when the structure is viewed as an array.
const bool IsArray
Flag indicating if the block is an array.
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
bool isZeroSizeArray() const
Checks if the descriptor is of an array of zero size.
const FieldDecl * asFieldDecl() const
const Record *const ElemRecord
Pointer to the record, if block contains records.
Descriptor used for global variables.
GlobalInitState InitState
A pointer-sized struct we use to allocate into data storage.
Inline descriptor embedded in structures and arrays.
unsigned IsActive
Flag indicating if the field is the active member of a union.
unsigned IsBase
Flag indicating if the field is an embedded base class.
unsigned IsVirtualBase
Flag inidcating if the field is a virtual base class.
unsigned InUnion
Flag indicating if this field is in a union (even if nested).
unsigned Offset
Offset inside the structure/array.
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
unsigned IsConst
Flag indicating if the storage is constant or not.
unsigned IsFieldMutable
Flag indicating if the field is mutable (if in a record).
QualType getPointeeType() const
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
const Type * getType() const
llvm::PointerIntPair< const Type *, 1, bool > TypeAndIsNull
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
OpaquePointer withFieldType(const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
llvm::PointerIntPair< const Type *, 2, unsigned > FieldType
OpaquePointer withPastEnd(bool PastEnd) const
QualType getObjectType() const
bool isRoot() const
Check if the pointer has offset 0.
const VarDecl * getBaseVarDecl() const
bool hasValidBase() const
QualType getSurroundingArray() const
If this is pointing to an array element, return the array.
const Expr * getBaseExpr() const
bool isOnePastEndOrElementPastEnd() const
This is used in Pointer::isOnePastEnd().
const PointerPathEntry * Path
ArrayRef< PointerPathEntry > path() const
const ValueDecl * getBaseDecl() const
bool isArrayElement() const
QualType getFieldType() const
bool isOnePastEnd() const
bool isConstexprUnknown() const
bool isUnknownSizeArray() const
OpaquePointer withPath(const PointerPathEntry *Path, unsigned PathLength, const Type *FieldTy, std::optional< bool > PastEnd=std::nullopt) const
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
static PointerPathEntry array(int64_t Index)
static PointerPathEntry field(const FieldDecl *FD)
llvm::PointerIntPair< const CXXRecordDecl *, 1, bool > RD
enum clang::interp::PointerPathEntry::@133156275124227243235357227301330162015140142322 Kind
static PointerPathEntry negativeArray(int64_t Index)
static PointerPathEntry base(const CXXRecordDecl *RD, bool Virtual=false)
bool isUnknownSizeArray() const
const Descriptor * getDeclDesc() const
bool allElementsInitialized() const
PtrView atField(unsigned Offset) const
const Record * getRecord() const
const Descriptor * getFieldDesc() const
const FieldDecl * getField() const
bool isElementInitialized(unsigned Index) const
static constexpr unsigned PastEndMark
PtrView atIndex(unsigned Idx) const
bool inPrimitiveArray() const
InlineDescriptor * getDescriptor(unsigned Offset) const
void startLifetime() const
T & elem(unsigned I) const
bool isElementPastEnd() const
const Block * block() const
bool isInitialized() const
bool isArrayElement() const
const Record * getElemRecord() const
unsigned getNumElems() const
InitMapPtr & getInitMap() const
InlineDescriptor * getInlineDesc() const
bool canBeInitialized() const
void initializeElement(unsigned Index) const
bool operator==(const PtrView &Other) const
bool isOnePastEnd() const
void setLifeState(Lifetime L) const
Lifetime getLifetime() const
unsigned getOffset() const
bool isVirtualBaseClass() const
bool isZeroSizeArray() const
bool operator!=(const PtrView &Other) const
PtrView stripBaseCasts() const
const StringLiteral * getLiteral() const
StringPointer decay() const
const Type * TypeInfoType