aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/AST/Interp/Pointer.h')
-rw-r--r--contrib/llvm-project/clang/lib/AST/Interp/Pointer.h196
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.