diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/Interp/Pointer.h')
-rw-r--r-- | contrib/llvm-project/clang/lib/AST/Interp/Pointer.h | 196 |
1 files changed, 163 insertions, 33 deletions
diff --git a/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h b/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h index f2f6e0e76018..8ccaff41ded8 100644 --- a/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h +++ b/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h @@ -26,24 +26,51 @@ namespace clang { namespace interp { class Block; class DeadBlock; -class Context; -class InterpState; class Pointer; -class Function; +class Context; enum PrimType : unsigned; +class Pointer; +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); + /// A pointer to a memory block, live or dead. /// /// This object can be allocated into interpreter stack frames. If pointing to /// a live block, it is a link in the chain of pointers pointing to the block. +/// +/// In the simplest form, a Pointer has a Block* (the pointee) and both Base +/// and Offset are 0, which means it will point to raw data. +/// +/// The Base field is used to access metadata about the data. For primitive +/// arrays, the Base is followed by an InitMap. In a variety of cases, the +/// Base is preceded by an InlineDescriptor, which is used to track the +/// initialization state, among other things. +/// +/// The Offset field is used to access the actual data. In other words, the +/// data the pointer decribes can be found at +/// Pointee->rawData() + Pointer.Offset. +/// +/// +/// Pointee Offset +/// │ │ +/// │ │ +/// ▼ ▼ +/// ┌───────┬────────────┬─────────┬────────────────────────────┐ +/// │ Block │ InlineDesc │ InitMap │ Actual Data │ +/// └───────┴────────────┴─────────┴────────────────────────────┘ +/// ▲ +/// │ +/// │ +/// Base class Pointer { private: - static constexpr unsigned PastEndMark = (unsigned)-1; - static constexpr unsigned RootPtrMark = (unsigned)-1; + static constexpr unsigned PastEndMark = ~0u; + static constexpr unsigned RootPtrMark = ~0u; public: Pointer() {} Pointer(Block *B); + Pointer(Block *B, unsigned BaseAndOffset); Pointer(const Pointer &P); Pointer(Pointer &&P); ~Pointer(); @@ -51,29 +78,56 @@ public: void operator=(const Pointer &P); void operator=(Pointer &&P); + /// Equality operators are just for tests. + bool operator==(const Pointer &P) const { + return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset; + } + + bool operator!=(const Pointer &P) const { + return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset; + } + /// Converts the pointer to an APValue. APValue toAPValue() const; + /// Converts the pointer to a string usable in diagnostics. + std::string toDiagnosticString(const ASTContext &Ctx) const; + + unsigned getIntegerRepresentation() const { + return reinterpret_cast<uintptr_t>(Pointee) + Offset; + } + + /// Converts the pointer to an APValue that is an rvalue. + std::optional<APValue> toRValue(const Context &Ctx) const; + /// Offsets a pointer inside an array. - Pointer atIndex(unsigned Idx) const { + [[nodiscard]] Pointer atIndex(unsigned Idx) const { if (Base == RootPtrMark) return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize()); unsigned Off = Idx * elemSize(); if (getFieldDesc()->ElemDesc) Off += sizeof(InlineDescriptor); else - Off += sizeof(InitMap *); + Off += sizeof(InitMapPtr); return Pointer(Pointee, Base, Base + Off); } /// Creates a pointer to a field. - Pointer atField(unsigned Off) const { + [[nodiscard]] Pointer atField(unsigned Off) const { unsigned Field = Offset + Off; return Pointer(Pointee, Field, Field); } + /// Subtract the given offset from the current Base and Offset + /// of the pointer. + [[nodiscard]] Pointer atFieldSub(unsigned Off) const { + assert(Offset >= Off); + unsigned O = Offset - Off; + return Pointer(Pointee, O, O); + } + /// Restricts the scope of an array element pointer. - Pointer narrow() const { + [[nodiscard]] Pointer narrow() const { // Null pointers cannot be narrowed. if (isZero() || isUnknownSizeArray()) return *this; @@ -93,7 +147,7 @@ public: if (inPrimitiveArray()) { if (Offset != Base) return *this; - return Pointer(Pointee, Base, Offset + sizeof(InitMap *)); + return Pointer(Pointee, Base, Offset + sizeof(InitMapPtr)); } // Pointer is to a field or array element - enter it. @@ -109,12 +163,12 @@ public: } /// Expands a pointer to the containing array, undoing narrowing. - Pointer expand() const { + [[nodiscard]] Pointer expand() const { if (isElementPastEnd()) { // Revert to an outer one-past-end pointer. unsigned Adjust; if (inPrimitiveArray()) - Adjust = sizeof(InitMap *); + Adjust = sizeof(InitMapPtr); else Adjust = sizeof(InlineDescriptor); return Pointer(Pointee, Base, Base + getSize() + Adjust); @@ -130,7 +184,8 @@ public: // Step into the containing array, if inside one. unsigned Next = Base - getInlineDesc()->Offset; - Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; + const Descriptor *Desc = + Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; if (!Desc->IsArray) return *this; return Pointer(Pointee, Next, Offset); @@ -144,11 +199,14 @@ public: bool isField() const { return Base != 0 && Base != RootPtrMark; } /// Accessor for information about the declaration site. - Descriptor *getDeclDesc() const { return Pointee->Desc; } + const Descriptor *getDeclDesc() const { + assert(Pointee); + return Pointee->Desc; + } SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } /// Returns a pointer to the object of which this pointer is a field. - Pointer getBase() const { + [[nodiscard]] Pointer getBase() const { if (Base == RootPtrMark) { assert(Offset == PastEndMark && "cannot get base of a block"); return Pointer(Pointee, Base, 0); @@ -158,7 +216,7 @@ public: return Pointer(Pointee, NewBase, NewBase); } /// Returns the parent array. - Pointer getArray() const { + [[nodiscard]] Pointer getArray() const { if (Base == RootPtrMark) { assert(Offset != 0 && Offset != PastEndMark && "not an array element"); return Pointer(Pointee, Base, 0); @@ -168,14 +226,20 @@ public: } /// Accessors for information about the innermost field. - Descriptor *getFieldDesc() const { + const Descriptor *getFieldDesc() const { if (Base == 0 || Base == RootPtrMark) return getDeclDesc(); return getInlineDesc()->Desc; } /// Returns the type of the innermost field. - QualType getType() const { return getFieldDesc()->getType(); } + QualType getType() const { + if (inPrimitiveArray() && Offset != Base) + return getFieldDesc()->getType()->getAsArrayTypeUnsafe()->getElementType(); + return getFieldDesc()->getType(); + } + + [[nodiscard]] Pointer getDeclPtr() const { return Pointer(Pointee); } /// Returns the element size of the innermost field. size_t elemSize() const { @@ -197,11 +261,15 @@ public: if (getFieldDesc()->ElemDesc) Adjust = sizeof(InlineDescriptor); else - Adjust = sizeof(InitMap *); + Adjust = sizeof(InitMapPtr); } return Offset - Base - Adjust; } + /// Whether this array refers to an array, but not + /// to the first element. + bool isArrayRoot() const { return inArray() && Offset == Base; } + /// Checks if the innermost field is an array. bool inArray() const { return getFieldDesc()->IsArray; } /// Checks if the structure is a primitive array. @@ -211,14 +279,19 @@ public: return getFieldDesc()->isUnknownSizeArray(); } /// Checks if the pointer points to an array. - bool isArrayElement() const { return Base != Offset; } + bool isArrayElement() const { return inArray() && Base != Offset; } /// Pointer points directly to a block. bool isRoot() const { return (Base == 0 || Base == RootPtrMark) && Offset == 0; } /// Returns the record descriptor of a class. - Record *getRecord() const { return getFieldDesc()->ElemRecord; } + const Record *getRecord() const { return getFieldDesc()->ElemRecord; } + /// Returns the element record type, if this is a non-primive array. + const Record *getElemRecord() const { + const Descriptor *ElemDesc = getFieldDesc()->ElemDesc; + return ElemDesc ? ElemDesc->ElemRecord : nullptr; + } /// Returns the field information. const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); } @@ -226,22 +299,32 @@ public: bool isUnion() const; /// Checks if the storage is extern. - bool isExtern() const { return Pointee->isExtern(); } + bool isExtern() const { return Pointee && Pointee->isExtern(); } /// Checks if the storage is static. - bool isStatic() const { return Pointee->isStatic(); } + bool isStatic() const { + assert(Pointee); + return Pointee->isStatic(); + } /// Checks if the storage is temporary. - bool isTemporary() const { return Pointee->isTemporary(); } + bool isTemporary() const { + assert(Pointee); + return Pointee->isTemporary(); + } /// Checks if the storage is a static temporary. bool isStaticTemporary() const { return isStatic() && isTemporary(); } /// Checks if the field is mutable. - bool isMutable() const { return Base != 0 && getInlineDesc()->IsMutable; } + bool isMutable() const { + return Base != 0 && getInlineDesc()->IsFieldMutable; + } /// Checks if an object was initialized. bool isInitialized() const; /// Checks if the object is active. bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; } /// Checks if a structure is a base class. bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } + /// Checks if the pointer pointers to a dummy value. + bool isDummy() const { return getDeclDesc()->isDummy(); } /// Checks if an object or a subfield is mutable. bool isConst() const { @@ -249,7 +332,10 @@ public: } /// Returns the declaration ID. - llvm::Optional<unsigned> getDeclID() const { return Pointee->getDeclID(); } + std::optional<unsigned> getDeclID() const { + assert(Pointee); + return Pointee->getDeclID(); + } /// Returns the byte offset from the start. unsigned getByteOffset() const { @@ -259,10 +345,17 @@ public: /// Returns the number of elements. unsigned getNumElems() const { return getSize() / elemSize(); } + const Block *block() const { return Pointee; } + /// Returns the index into an array. int64_t getIndex() const { if (isElementPastEnd()) return 1; + + // narrow()ed element in a composite array. + if (Base > 0 && Base == Offset) + return 0; + if (auto ElemSize = elemSize()) return getOffset() / ElemSize; return 0; @@ -270,6 +363,8 @@ public: /// Checks if the index is one past end. bool isOnePastEnd() const { + if (!Pointee) + return false; return isElementPastEnd() || getSize() == getOffset(); } @@ -279,12 +374,20 @@ public: /// Dereferences the pointer, if it's live. template <typename T> T &deref() const { assert(isLive() && "Invalid pointer"); - return *reinterpret_cast<T *>(Pointee->data() + Offset); + assert(Pointee); + if (isArrayRoot()) + return *reinterpret_cast<T *>(Pointee->rawData() + Base + + sizeof(InitMapPtr)); + + assert(Offset + sizeof(T) <= Pointee->getDescriptor()->getAllocSize()); + return *reinterpret_cast<T *>(Pointee->rawData() + Offset); } /// Dereferences a primitive element. template <typename T> T &elem(unsigned I) const { - return reinterpret_cast<T *>(Pointee->data())[I]; + assert(I < getNumElems()); + assert(Pointee); + return reinterpret_cast<T *>(Pointee->data() + sizeof(InitMapPtr))[I]; } /// Initializes a field. @@ -294,6 +397,19 @@ public: /// Deactivates an entire strurcutre. void deactivate() const; + /// Compare two pointers. + ComparisonCategoryResult compare(const Pointer &Other) const { + if (!hasSameBase(*this, Other)) + return ComparisonCategoryResult::Unordered; + + if (Offset < Other.Offset) + return ComparisonCategoryResult::Less; + else if (Offset > Other.Offset) + return ComparisonCategoryResult::Greater; + + return ComparisonCategoryResult::Equal; + } + /// Checks if two pointers are comparable. static bool hasSameBase(const Pointer &A, const Pointer &B); /// Checks if two pointers can be subtracted. @@ -301,7 +417,17 @@ public: /// Prints the pointer. void print(llvm::raw_ostream &OS) const { - OS << "{" << Base << ", " << Offset << ", "; + OS << Pointee << " {"; + if (Base == RootPtrMark) + OS << "rootptr, "; + else + OS << Base << ", "; + + if (Offset == PastEndMark) + OS << "pastend, "; + else + OS << Offset << ", "; + if (Pointee) OS << Pointee->getSize(); else @@ -312,6 +438,7 @@ public: private: friend class Block; friend class DeadBlock; + friend struct InitMap; Pointer(Block *Pointee, unsigned Base, unsigned Offset); @@ -321,12 +448,15 @@ private: /// Returns a descriptor at a given offset. InlineDescriptor *getDescriptor(unsigned Offset) const { assert(Offset != 0 && "Not a nested pointer"); - return reinterpret_cast<InlineDescriptor *>(Pointee->data() + Offset) - 1; + assert(Pointee); + return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) - + 1; } - /// Returns a reference to the pointer which stores the initialization map. - InitMap *&getInitMap() const { - return *reinterpret_cast<InitMap **>(Pointee->data() + Base); + /// Returns a reference to the InitMapPtr which stores the initialization map. + InitMapPtr &getInitMap() const { + assert(Pointee); + return *reinterpret_cast<InitMapPtr *>(Pointee->rawData() + Base); } /// The block the pointer is pointing to. |