1a07aba5dSTimm Baeder //===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===// 2a07aba5dSTimm Baeder // 3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a07aba5dSTimm Baeder // 7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 8a07aba5dSTimm Baeder // 9a07aba5dSTimm Baeder // Defines the classes responsible for pointer tracking. 10a07aba5dSTimm Baeder // 11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 12a07aba5dSTimm Baeder 13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_POINTER_H 14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_POINTER_H 15a07aba5dSTimm Baeder 16a07aba5dSTimm Baeder #include "Descriptor.h" 17a07aba5dSTimm Baeder #include "FunctionPointer.h" 18a07aba5dSTimm Baeder #include "InterpBlock.h" 19a07aba5dSTimm Baeder #include "clang/AST/ComparisonCategories.h" 20a07aba5dSTimm Baeder #include "clang/AST/Decl.h" 21a07aba5dSTimm Baeder #include "clang/AST/DeclCXX.h" 22a07aba5dSTimm Baeder #include "clang/AST/Expr.h" 23a07aba5dSTimm Baeder #include "llvm/Support/raw_ostream.h" 24a07aba5dSTimm Baeder 25a07aba5dSTimm Baeder namespace clang { 26a07aba5dSTimm Baeder namespace interp { 27a07aba5dSTimm Baeder class Block; 28a07aba5dSTimm Baeder class DeadBlock; 29a07aba5dSTimm Baeder class Pointer; 30a07aba5dSTimm Baeder class Context; 31a07aba5dSTimm Baeder template <unsigned A, bool B> class Integral; 32a07aba5dSTimm Baeder enum PrimType : unsigned; 33a07aba5dSTimm Baeder 34a07aba5dSTimm Baeder class Pointer; 35a07aba5dSTimm Baeder inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); 36a07aba5dSTimm Baeder 37a07aba5dSTimm Baeder struct BlockPointer { 38a07aba5dSTimm Baeder /// The block the pointer is pointing to. 39a07aba5dSTimm Baeder Block *Pointee; 40a07aba5dSTimm Baeder /// Start of the current subfield. 41a07aba5dSTimm Baeder unsigned Base; 42a07aba5dSTimm Baeder }; 43a07aba5dSTimm Baeder 44a07aba5dSTimm Baeder struct IntPointer { 45a07aba5dSTimm Baeder const Descriptor *Desc; 46a07aba5dSTimm Baeder uint64_t Value; 47a07aba5dSTimm Baeder 48a07aba5dSTimm Baeder IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const; 4943fd2c40STimm Baeder IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const; 50a07aba5dSTimm Baeder }; 51a07aba5dSTimm Baeder 52e86b68ffSTimm Baeder struct TypeidPointer { 53e86b68ffSTimm Baeder const Type *TypePtr; 54e86b68ffSTimm Baeder const Type *TypeInfoType; 55e86b68ffSTimm Baeder }; 56e86b68ffSTimm Baeder 57e86b68ffSTimm Baeder enum class Storage { Block, Int, Fn, Typeid }; 58a07aba5dSTimm Baeder 59a07aba5dSTimm Baeder /// A pointer to a memory block, live or dead. 60a07aba5dSTimm Baeder /// 61a07aba5dSTimm Baeder /// This object can be allocated into interpreter stack frames. If pointing to 62a07aba5dSTimm Baeder /// a live block, it is a link in the chain of pointers pointing to the block. 63a07aba5dSTimm Baeder /// 64a07aba5dSTimm Baeder /// In the simplest form, a Pointer has a Block* (the pointee) and both Base 65a07aba5dSTimm Baeder /// and Offset are 0, which means it will point to raw data. 66a07aba5dSTimm Baeder /// 67a07aba5dSTimm Baeder /// The Base field is used to access metadata about the data. For primitive 68a07aba5dSTimm Baeder /// arrays, the Base is followed by an InitMap. In a variety of cases, the 69a07aba5dSTimm Baeder /// Base is preceded by an InlineDescriptor, which is used to track the 70a07aba5dSTimm Baeder /// initialization state, among other things. 71a07aba5dSTimm Baeder /// 72a07aba5dSTimm Baeder /// The Offset field is used to access the actual data. In other words, the 73a07aba5dSTimm Baeder /// data the pointer decribes can be found at 74a07aba5dSTimm Baeder /// Pointee->rawData() + Pointer.Offset. 75a07aba5dSTimm Baeder /// 76a07aba5dSTimm Baeder /// 77a07aba5dSTimm Baeder /// Pointee Offset 78a07aba5dSTimm Baeder /// │ │ 79a07aba5dSTimm Baeder /// │ │ 80a07aba5dSTimm Baeder /// ▼ ▼ 81a07aba5dSTimm Baeder /// ┌───────┬────────────┬─────────┬────────────────────────────┐ 82a07aba5dSTimm Baeder /// │ Block │ InlineDesc │ InitMap │ Actual Data │ 83a07aba5dSTimm Baeder /// └───────┴────────────┴─────────┴────────────────────────────┘ 84a07aba5dSTimm Baeder /// ▲ 85a07aba5dSTimm Baeder /// │ 86a07aba5dSTimm Baeder /// │ 87a07aba5dSTimm Baeder /// Base 88a07aba5dSTimm Baeder class Pointer { 89a07aba5dSTimm Baeder private: 90a07aba5dSTimm Baeder static constexpr unsigned PastEndMark = ~0u; 91a07aba5dSTimm Baeder static constexpr unsigned RootPtrMark = ~0u; 92a07aba5dSTimm Baeder 93a07aba5dSTimm Baeder public: 94a07aba5dSTimm Baeder Pointer() { 95a07aba5dSTimm Baeder StorageKind = Storage::Int; 96a07aba5dSTimm Baeder PointeeStorage.Int.Value = 0; 97a07aba5dSTimm Baeder PointeeStorage.Int.Desc = nullptr; 98a07aba5dSTimm Baeder } 99a07aba5dSTimm Baeder Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) { 100a07aba5dSTimm Baeder PointeeStorage.Int = std::move(IntPtr); 101a07aba5dSTimm Baeder } 102a07aba5dSTimm Baeder Pointer(Block *B); 103a07aba5dSTimm Baeder Pointer(Block *B, uint64_t BaseAndOffset); 104a07aba5dSTimm Baeder Pointer(const Pointer &P); 105a07aba5dSTimm Baeder Pointer(Pointer &&P); 106a07aba5dSTimm Baeder Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0) 107a07aba5dSTimm Baeder : Offset(Offset), StorageKind(Storage::Int) { 108a07aba5dSTimm Baeder PointeeStorage.Int.Value = Address; 109a07aba5dSTimm Baeder PointeeStorage.Int.Desc = Desc; 110a07aba5dSTimm Baeder } 111a07aba5dSTimm Baeder Pointer(const Function *F, uint64_t Offset = 0) 112a07aba5dSTimm Baeder : Offset(Offset), StorageKind(Storage::Fn) { 113a07aba5dSTimm Baeder PointeeStorage.Fn = FunctionPointer(F); 114a07aba5dSTimm Baeder } 115e86b68ffSTimm Baeder Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0) 116e86b68ffSTimm Baeder : Offset(Offset), StorageKind(Storage::Typeid) { 117e86b68ffSTimm Baeder PointeeStorage.Typeid.TypePtr = TypePtr; 118e86b68ffSTimm Baeder PointeeStorage.Typeid.TypeInfoType = TypeInfoType; 119e86b68ffSTimm Baeder } 1201f2d9345STimm Baeder Pointer(Block *Pointee, unsigned Base, uint64_t Offset); 121a07aba5dSTimm Baeder ~Pointer(); 122a07aba5dSTimm Baeder 123a07aba5dSTimm Baeder void operator=(const Pointer &P); 124a07aba5dSTimm Baeder void operator=(Pointer &&P); 125a07aba5dSTimm Baeder 126a07aba5dSTimm Baeder /// Equality operators are just for tests. 127a07aba5dSTimm Baeder bool operator==(const Pointer &P) const { 128a07aba5dSTimm Baeder if (P.StorageKind != StorageKind) 129a07aba5dSTimm Baeder return false; 130a07aba5dSTimm Baeder if (isIntegralPointer()) 131a07aba5dSTimm Baeder return P.asIntPointer().Value == asIntPointer().Value && 132a07aba5dSTimm Baeder Offset == P.Offset; 133a07aba5dSTimm Baeder 134a07aba5dSTimm Baeder assert(isBlockPointer()); 135a07aba5dSTimm Baeder return P.asBlockPointer().Pointee == asBlockPointer().Pointee && 136a07aba5dSTimm Baeder P.asBlockPointer().Base == asBlockPointer().Base && 137a07aba5dSTimm Baeder Offset == P.Offset; 138a07aba5dSTimm Baeder } 139a07aba5dSTimm Baeder 140a07aba5dSTimm Baeder bool operator!=(const Pointer &P) const { return !(P == *this); } 141a07aba5dSTimm Baeder 142a07aba5dSTimm Baeder /// Converts the pointer to an APValue. 143a07aba5dSTimm Baeder APValue toAPValue(const ASTContext &ASTCtx) const; 144a07aba5dSTimm Baeder 145a07aba5dSTimm Baeder /// Converts the pointer to a string usable in diagnostics. 146a07aba5dSTimm Baeder std::string toDiagnosticString(const ASTContext &Ctx) const; 147a07aba5dSTimm Baeder 148a07aba5dSTimm Baeder uint64_t getIntegerRepresentation() const { 149a07aba5dSTimm Baeder if (isIntegralPointer()) 150a07aba5dSTimm Baeder return asIntPointer().Value + (Offset * elemSize()); 151a07aba5dSTimm Baeder if (isFunctionPointer()) 152db94852bSTimm Baeder return asFunctionPointer().getIntegerRepresentation() + Offset; 153a07aba5dSTimm Baeder return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset; 154a07aba5dSTimm Baeder } 155a07aba5dSTimm Baeder 156a07aba5dSTimm Baeder /// Converts the pointer to an APValue that is an rvalue. 157a07aba5dSTimm Baeder std::optional<APValue> toRValue(const Context &Ctx, 158a07aba5dSTimm Baeder QualType ResultType) const; 159a07aba5dSTimm Baeder 160a07aba5dSTimm Baeder /// Offsets a pointer inside an array. 161a07aba5dSTimm Baeder [[nodiscard]] Pointer atIndex(uint64_t Idx) const { 162a07aba5dSTimm Baeder if (isIntegralPointer()) 163a07aba5dSTimm Baeder return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx); 164a07aba5dSTimm Baeder if (isFunctionPointer()) 165a07aba5dSTimm Baeder return Pointer(asFunctionPointer().getFunction(), Idx); 166a07aba5dSTimm Baeder 167a07aba5dSTimm Baeder if (asBlockPointer().Base == RootPtrMark) 168a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, RootPtrMark, 169a07aba5dSTimm Baeder getDeclDesc()->getSize()); 170a07aba5dSTimm Baeder uint64_t Off = Idx * elemSize(); 171a07aba5dSTimm Baeder if (getFieldDesc()->ElemDesc) 172a07aba5dSTimm Baeder Off += sizeof(InlineDescriptor); 173a07aba5dSTimm Baeder else 174a07aba5dSTimm Baeder Off += sizeof(InitMapPtr); 175a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 176a07aba5dSTimm Baeder asBlockPointer().Base + Off); 177a07aba5dSTimm Baeder } 178a07aba5dSTimm Baeder 179a07aba5dSTimm Baeder /// Creates a pointer to a field. 180a07aba5dSTimm Baeder [[nodiscard]] Pointer atField(unsigned Off) const { 181a07aba5dSTimm Baeder assert(isBlockPointer()); 182a07aba5dSTimm Baeder unsigned Field = Offset + Off; 183a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, Field, Field); 184a07aba5dSTimm Baeder } 185a07aba5dSTimm Baeder 186a07aba5dSTimm Baeder /// Subtract the given offset from the current Base and Offset 187a07aba5dSTimm Baeder /// of the pointer. 188a07aba5dSTimm Baeder [[nodiscard]] Pointer atFieldSub(unsigned Off) const { 189a07aba5dSTimm Baeder assert(Offset >= Off); 190a07aba5dSTimm Baeder unsigned O = Offset - Off; 191a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, O, O); 192a07aba5dSTimm Baeder } 193a07aba5dSTimm Baeder 194a07aba5dSTimm Baeder /// Restricts the scope of an array element pointer. 195a07aba5dSTimm Baeder [[nodiscard]] Pointer narrow() const { 196a07aba5dSTimm Baeder if (!isBlockPointer()) 197a07aba5dSTimm Baeder return *this; 198a07aba5dSTimm Baeder assert(isBlockPointer()); 199a07aba5dSTimm Baeder // Null pointers cannot be narrowed. 200a07aba5dSTimm Baeder if (isZero() || isUnknownSizeArray()) 201a07aba5dSTimm Baeder return *this; 202a07aba5dSTimm Baeder 203a07aba5dSTimm Baeder // Pointer to an array of base types - enter block. 204a07aba5dSTimm Baeder if (asBlockPointer().Base == RootPtrMark) 205a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor), 206a07aba5dSTimm Baeder Offset == 0 ? Offset : PastEndMark); 207a07aba5dSTimm Baeder 208a07aba5dSTimm Baeder // Pointer is one past end - magic offset marks that. 209a07aba5dSTimm Baeder if (isOnePastEnd()) 210a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 211a07aba5dSTimm Baeder PastEndMark); 212a07aba5dSTimm Baeder 213a07aba5dSTimm Baeder // Primitive arrays are a bit special since they do not have inline 214a07aba5dSTimm Baeder // descriptors. If Offset != Base, then the pointer already points to 215a07aba5dSTimm Baeder // an element and there is nothing to do. Otherwise, the pointer is 216a07aba5dSTimm Baeder // adjusted to the first element of the array. 217a07aba5dSTimm Baeder if (inPrimitiveArray()) { 218a07aba5dSTimm Baeder if (Offset != asBlockPointer().Base) 219a07aba5dSTimm Baeder return *this; 220a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 221a07aba5dSTimm Baeder Offset + sizeof(InitMapPtr)); 222a07aba5dSTimm Baeder } 223a07aba5dSTimm Baeder 224a07aba5dSTimm Baeder // Pointer is to a field or array element - enter it. 225a07aba5dSTimm Baeder if (Offset != asBlockPointer().Base) 226a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, Offset, Offset); 227a07aba5dSTimm Baeder 228a07aba5dSTimm Baeder // Enter the first element of an array. 229a07aba5dSTimm Baeder if (!getFieldDesc()->isArray()) 230a07aba5dSTimm Baeder return *this; 231a07aba5dSTimm Baeder 232a07aba5dSTimm Baeder const unsigned NewBase = asBlockPointer().Base + sizeof(InlineDescriptor); 233a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, NewBase, NewBase); 234a07aba5dSTimm Baeder } 235a07aba5dSTimm Baeder 236a07aba5dSTimm Baeder /// Expands a pointer to the containing array, undoing narrowing. 237a07aba5dSTimm Baeder [[nodiscard]] Pointer expand() const { 238a07aba5dSTimm Baeder assert(isBlockPointer()); 239a07aba5dSTimm Baeder Block *Pointee = asBlockPointer().Pointee; 240a07aba5dSTimm Baeder 241a07aba5dSTimm Baeder if (isElementPastEnd()) { 242a07aba5dSTimm Baeder // Revert to an outer one-past-end pointer. 243a07aba5dSTimm Baeder unsigned Adjust; 244a07aba5dSTimm Baeder if (inPrimitiveArray()) 245a07aba5dSTimm Baeder Adjust = sizeof(InitMapPtr); 246a07aba5dSTimm Baeder else 247a07aba5dSTimm Baeder Adjust = sizeof(InlineDescriptor); 248a07aba5dSTimm Baeder return Pointer(Pointee, asBlockPointer().Base, 249a07aba5dSTimm Baeder asBlockPointer().Base + getSize() + Adjust); 250a07aba5dSTimm Baeder } 251a07aba5dSTimm Baeder 252a07aba5dSTimm Baeder // Do not step out of array elements. 253a07aba5dSTimm Baeder if (asBlockPointer().Base != Offset) 254a07aba5dSTimm Baeder return *this; 255a07aba5dSTimm Baeder 256a07aba5dSTimm Baeder if (isRoot()) 257d6d60707STimm Baeder return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base); 258a07aba5dSTimm Baeder 259a07aba5dSTimm Baeder // Step into the containing array, if inside one. 260a07aba5dSTimm Baeder unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; 261a07aba5dSTimm Baeder const Descriptor *Desc = 262a07aba5dSTimm Baeder (Next == Pointee->getDescriptor()->getMetadataSize()) 263a07aba5dSTimm Baeder ? getDeclDesc() 264a07aba5dSTimm Baeder : getDescriptor(Next)->Desc; 265a07aba5dSTimm Baeder if (!Desc->IsArray) 266a07aba5dSTimm Baeder return *this; 267a07aba5dSTimm Baeder return Pointer(Pointee, Next, Offset); 268a07aba5dSTimm Baeder } 269a07aba5dSTimm Baeder 270a07aba5dSTimm Baeder /// Checks if the pointer is null. 271a07aba5dSTimm Baeder bool isZero() const { 272a07aba5dSTimm Baeder if (isBlockPointer()) 273a07aba5dSTimm Baeder return asBlockPointer().Pointee == nullptr; 274a07aba5dSTimm Baeder if (isFunctionPointer()) 275a07aba5dSTimm Baeder return asFunctionPointer().isZero(); 276e86b68ffSTimm Baeder if (isTypeidPointer()) 277e86b68ffSTimm Baeder return false; 278a07aba5dSTimm Baeder assert(isIntegralPointer()); 279a07aba5dSTimm Baeder return asIntPointer().Value == 0 && Offset == 0; 280a07aba5dSTimm Baeder } 281a07aba5dSTimm Baeder /// Checks if the pointer is live. 282a07aba5dSTimm Baeder bool isLive() const { 283a07aba5dSTimm Baeder if (!isBlockPointer()) 284a07aba5dSTimm Baeder return true; 285a07aba5dSTimm Baeder return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead; 286a07aba5dSTimm Baeder } 287a07aba5dSTimm Baeder /// Checks if the item is a field in an object. 288a07aba5dSTimm Baeder bool isField() const { 289a07aba5dSTimm Baeder if (!isBlockPointer()) 290a07aba5dSTimm Baeder return false; 291a07aba5dSTimm Baeder 292a07aba5dSTimm Baeder return !isRoot() && getFieldDesc()->asDecl(); 293a07aba5dSTimm Baeder } 294a07aba5dSTimm Baeder 295a07aba5dSTimm Baeder /// Accessor for information about the declaration site. 296a07aba5dSTimm Baeder const Descriptor *getDeclDesc() const { 297a07aba5dSTimm Baeder if (isIntegralPointer()) 298a07aba5dSTimm Baeder return asIntPointer().Desc; 299e86b68ffSTimm Baeder if (isFunctionPointer() || isTypeidPointer()) 300a07aba5dSTimm Baeder return nullptr; 301a07aba5dSTimm Baeder 302a07aba5dSTimm Baeder assert(isBlockPointer()); 303a07aba5dSTimm Baeder assert(asBlockPointer().Pointee); 304a07aba5dSTimm Baeder return asBlockPointer().Pointee->Desc; 305a07aba5dSTimm Baeder } 306a07aba5dSTimm Baeder SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } 307a07aba5dSTimm Baeder 308a07aba5dSTimm Baeder /// Returns the expression or declaration the pointer has been created for. 309a07aba5dSTimm Baeder DeclTy getSource() const { 310a07aba5dSTimm Baeder if (isBlockPointer()) 311a07aba5dSTimm Baeder return getDeclDesc()->getSource(); 312a07aba5dSTimm Baeder if (isFunctionPointer()) { 313a07aba5dSTimm Baeder const Function *F = asFunctionPointer().getFunction(); 314a07aba5dSTimm Baeder return F ? F->getDecl() : DeclTy(); 315a07aba5dSTimm Baeder } 316a07aba5dSTimm Baeder assert(isIntegralPointer()); 317a07aba5dSTimm Baeder return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy(); 318a07aba5dSTimm Baeder } 319a07aba5dSTimm Baeder 320a07aba5dSTimm Baeder /// Returns a pointer to the object of which this pointer is a field. 321a07aba5dSTimm Baeder [[nodiscard]] Pointer getBase() const { 322a07aba5dSTimm Baeder if (asBlockPointer().Base == RootPtrMark) { 323a07aba5dSTimm Baeder assert(Offset == PastEndMark && "cannot get base of a block"); 324a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); 325a07aba5dSTimm Baeder } 326a07aba5dSTimm Baeder unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset; 327a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, NewBase, NewBase); 328a07aba5dSTimm Baeder } 329a07aba5dSTimm Baeder /// Returns the parent array. 330a07aba5dSTimm Baeder [[nodiscard]] Pointer getArray() const { 331a07aba5dSTimm Baeder if (asBlockPointer().Base == RootPtrMark) { 332a07aba5dSTimm Baeder assert(Offset != 0 && Offset != PastEndMark && "not an array element"); 333a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); 334a07aba5dSTimm Baeder } 335a07aba5dSTimm Baeder assert(Offset != asBlockPointer().Base && "not an array element"); 336a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 337a07aba5dSTimm Baeder asBlockPointer().Base); 338a07aba5dSTimm Baeder } 339a07aba5dSTimm Baeder 340a07aba5dSTimm Baeder /// Accessors for information about the innermost field. 341a07aba5dSTimm Baeder const Descriptor *getFieldDesc() const { 342a07aba5dSTimm Baeder if (isIntegralPointer()) 343a07aba5dSTimm Baeder return asIntPointer().Desc; 344a07aba5dSTimm Baeder 345a07aba5dSTimm Baeder if (isRoot()) 346a07aba5dSTimm Baeder return getDeclDesc(); 347a07aba5dSTimm Baeder return getInlineDesc()->Desc; 348a07aba5dSTimm Baeder } 349a07aba5dSTimm Baeder 350a07aba5dSTimm Baeder /// Returns the type of the innermost field. 351a07aba5dSTimm Baeder QualType getType() const { 352e86b68ffSTimm Baeder if (isTypeidPointer()) 353e86b68ffSTimm Baeder return QualType(PointeeStorage.Typeid.TypeInfoType, 0); 354e86b68ffSTimm Baeder 355a07aba5dSTimm Baeder if (inPrimitiveArray() && Offset != asBlockPointer().Base) { 356a07aba5dSTimm Baeder // Unfortunately, complex and vector types are not array types in clang, 357a07aba5dSTimm Baeder // but they are for us. 358a07aba5dSTimm Baeder if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) 359a07aba5dSTimm Baeder return AT->getElementType(); 360a07aba5dSTimm Baeder if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>()) 361a07aba5dSTimm Baeder return CT->getElementType(); 362a07aba5dSTimm Baeder if (const auto *CT = getFieldDesc()->getType()->getAs<VectorType>()) 363a07aba5dSTimm Baeder return CT->getElementType(); 364a07aba5dSTimm Baeder } 365a07aba5dSTimm Baeder return getFieldDesc()->getType(); 366a07aba5dSTimm Baeder } 367a07aba5dSTimm Baeder 368a07aba5dSTimm Baeder [[nodiscard]] Pointer getDeclPtr() const { 369a07aba5dSTimm Baeder return Pointer(asBlockPointer().Pointee); 370a07aba5dSTimm Baeder } 371a07aba5dSTimm Baeder 372a07aba5dSTimm Baeder /// Returns the element size of the innermost field. 373a07aba5dSTimm Baeder size_t elemSize() const { 374a07aba5dSTimm Baeder if (isIntegralPointer()) { 375a07aba5dSTimm Baeder if (!asIntPointer().Desc) 376a07aba5dSTimm Baeder return 1; 377a07aba5dSTimm Baeder return asIntPointer().Desc->getElemSize(); 378a07aba5dSTimm Baeder } 379a07aba5dSTimm Baeder 380a07aba5dSTimm Baeder if (asBlockPointer().Base == RootPtrMark) 381a07aba5dSTimm Baeder return getDeclDesc()->getSize(); 382a07aba5dSTimm Baeder return getFieldDesc()->getElemSize(); 383a07aba5dSTimm Baeder } 384a07aba5dSTimm Baeder /// Returns the total size of the innermost field. 385a07aba5dSTimm Baeder size_t getSize() const { 386a07aba5dSTimm Baeder assert(isBlockPointer()); 387a07aba5dSTimm Baeder return getFieldDesc()->getSize(); 388a07aba5dSTimm Baeder } 389a07aba5dSTimm Baeder 390a07aba5dSTimm Baeder /// Returns the offset into an array. 391a07aba5dSTimm Baeder unsigned getOffset() const { 392a07aba5dSTimm Baeder assert(Offset != PastEndMark && "invalid offset"); 393a07aba5dSTimm Baeder assert(isBlockPointer()); 394a07aba5dSTimm Baeder if (asBlockPointer().Base == RootPtrMark) 395a07aba5dSTimm Baeder return Offset; 396a07aba5dSTimm Baeder 397a07aba5dSTimm Baeder unsigned Adjust = 0; 398a07aba5dSTimm Baeder if (Offset != asBlockPointer().Base) { 399a07aba5dSTimm Baeder if (getFieldDesc()->ElemDesc) 400a07aba5dSTimm Baeder Adjust = sizeof(InlineDescriptor); 401a07aba5dSTimm Baeder else 402a07aba5dSTimm Baeder Adjust = sizeof(InitMapPtr); 403a07aba5dSTimm Baeder } 404a07aba5dSTimm Baeder return Offset - asBlockPointer().Base - Adjust; 405a07aba5dSTimm Baeder } 406a07aba5dSTimm Baeder 407a07aba5dSTimm Baeder /// Whether this array refers to an array, but not 408a07aba5dSTimm Baeder /// to the first element. 409a07aba5dSTimm Baeder bool isArrayRoot() const { 410a07aba5dSTimm Baeder return inArray() && Offset == asBlockPointer().Base; 411a07aba5dSTimm Baeder } 412a07aba5dSTimm Baeder 413a07aba5dSTimm Baeder /// Checks if the innermost field is an array. 414a07aba5dSTimm Baeder bool inArray() const { 415a07aba5dSTimm Baeder if (isBlockPointer()) 416a07aba5dSTimm Baeder return getFieldDesc()->IsArray; 417a07aba5dSTimm Baeder return false; 418a07aba5dSTimm Baeder } 419a07aba5dSTimm Baeder bool inUnion() const { 420a07aba5dSTimm Baeder if (isBlockPointer()) 421a07aba5dSTimm Baeder return getInlineDesc()->InUnion; 422a07aba5dSTimm Baeder return false; 423a07aba5dSTimm Baeder }; 424a07aba5dSTimm Baeder 425a07aba5dSTimm Baeder /// Checks if the structure is a primitive array. 426a07aba5dSTimm Baeder bool inPrimitiveArray() const { 427a07aba5dSTimm Baeder if (isBlockPointer()) 428a07aba5dSTimm Baeder return getFieldDesc()->isPrimitiveArray(); 429a07aba5dSTimm Baeder return false; 430a07aba5dSTimm Baeder } 431a07aba5dSTimm Baeder /// Checks if the structure is an array of unknown size. 432a07aba5dSTimm Baeder bool isUnknownSizeArray() const { 433a07aba5dSTimm Baeder if (!isBlockPointer()) 434a07aba5dSTimm Baeder return false; 435a07aba5dSTimm Baeder return getFieldDesc()->isUnknownSizeArray(); 436a07aba5dSTimm Baeder } 437a07aba5dSTimm Baeder /// Checks if the pointer points to an array. 438a07aba5dSTimm Baeder bool isArrayElement() const { 439800b0739STimm Baeder if (!isBlockPointer()) 440800b0739STimm Baeder return false; 441800b0739STimm Baeder 442800b0739STimm Baeder const BlockPointer &BP = asBlockPointer(); 443800b0739STimm Baeder if (inArray() && BP.Base != Offset) 444800b0739STimm Baeder return true; 445800b0739STimm Baeder 446800b0739STimm Baeder // Might be a narrow()'ed element in a composite array. 447800b0739STimm Baeder // Check the inline descriptor. 448800b0739STimm Baeder if (BP.Base >= sizeof(InlineDescriptor) && getInlineDesc()->IsArrayElement) 449800b0739STimm Baeder return true; 450800b0739STimm Baeder 451a07aba5dSTimm Baeder return false; 452a07aba5dSTimm Baeder } 453a07aba5dSTimm Baeder /// Pointer points directly to a block. 454a07aba5dSTimm Baeder bool isRoot() const { 455e86b68ffSTimm Baeder if (isZero() || !isBlockPointer()) 456a07aba5dSTimm Baeder return true; 457a07aba5dSTimm Baeder return (asBlockPointer().Base == 458a07aba5dSTimm Baeder asBlockPointer().Pointee->getDescriptor()->getMetadataSize() || 459a07aba5dSTimm Baeder asBlockPointer().Base == 0); 460a07aba5dSTimm Baeder } 461a07aba5dSTimm Baeder /// If this pointer has an InlineDescriptor we can use to initialize. 462a07aba5dSTimm Baeder bool canBeInitialized() const { 463a07aba5dSTimm Baeder if (!isBlockPointer()) 464a07aba5dSTimm Baeder return false; 465a07aba5dSTimm Baeder 466a07aba5dSTimm Baeder return asBlockPointer().Pointee && asBlockPointer().Base > 0; 467a07aba5dSTimm Baeder } 468a07aba5dSTimm Baeder 469a07aba5dSTimm Baeder [[nodiscard]] const BlockPointer &asBlockPointer() const { 470a07aba5dSTimm Baeder assert(isBlockPointer()); 471a07aba5dSTimm Baeder return PointeeStorage.BS; 472a07aba5dSTimm Baeder } 473a07aba5dSTimm Baeder [[nodiscard]] const IntPointer &asIntPointer() const { 474a07aba5dSTimm Baeder assert(isIntegralPointer()); 475a07aba5dSTimm Baeder return PointeeStorage.Int; 476a07aba5dSTimm Baeder } 477a07aba5dSTimm Baeder [[nodiscard]] const FunctionPointer &asFunctionPointer() const { 478a07aba5dSTimm Baeder assert(isFunctionPointer()); 479a07aba5dSTimm Baeder return PointeeStorage.Fn; 480a07aba5dSTimm Baeder } 481a07aba5dSTimm Baeder 482a07aba5dSTimm Baeder bool isBlockPointer() const { return StorageKind == Storage::Block; } 483a07aba5dSTimm Baeder bool isIntegralPointer() const { return StorageKind == Storage::Int; } 484a07aba5dSTimm Baeder bool isFunctionPointer() const { return StorageKind == Storage::Fn; } 485e86b68ffSTimm Baeder bool isTypeidPointer() const { return StorageKind == Storage::Typeid; } 486a07aba5dSTimm Baeder 487a07aba5dSTimm Baeder /// Returns the record descriptor of a class. 488a07aba5dSTimm Baeder const Record *getRecord() const { return getFieldDesc()->ElemRecord; } 489a07aba5dSTimm Baeder /// Returns the element record type, if this is a non-primive array. 490a07aba5dSTimm Baeder const Record *getElemRecord() const { 491a07aba5dSTimm Baeder const Descriptor *ElemDesc = getFieldDesc()->ElemDesc; 492a07aba5dSTimm Baeder return ElemDesc ? ElemDesc->ElemRecord : nullptr; 493a07aba5dSTimm Baeder } 494a07aba5dSTimm Baeder /// Returns the field information. 495a07aba5dSTimm Baeder const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); } 496a07aba5dSTimm Baeder 497a07aba5dSTimm Baeder /// Checks if the object is a union. 498a07aba5dSTimm Baeder bool isUnion() const; 499a07aba5dSTimm Baeder 500a07aba5dSTimm Baeder /// Checks if the storage is extern. 501a07aba5dSTimm Baeder bool isExtern() const { 502a07aba5dSTimm Baeder if (isBlockPointer()) 503a07aba5dSTimm Baeder return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern(); 504a07aba5dSTimm Baeder return false; 505a07aba5dSTimm Baeder } 506a07aba5dSTimm Baeder /// Checks if the storage is static. 507a07aba5dSTimm Baeder bool isStatic() const { 508a07aba5dSTimm Baeder if (!isBlockPointer()) 509a07aba5dSTimm Baeder return true; 510a07aba5dSTimm Baeder assert(asBlockPointer().Pointee); 511a07aba5dSTimm Baeder return asBlockPointer().Pointee->isStatic(); 512a07aba5dSTimm Baeder } 513a07aba5dSTimm Baeder /// Checks if the storage is temporary. 514a07aba5dSTimm Baeder bool isTemporary() const { 515a07aba5dSTimm Baeder if (isBlockPointer()) { 516a07aba5dSTimm Baeder assert(asBlockPointer().Pointee); 517a07aba5dSTimm Baeder return asBlockPointer().Pointee->isTemporary(); 518a07aba5dSTimm Baeder } 519a07aba5dSTimm Baeder return false; 520a07aba5dSTimm Baeder } 521df11ee21STimm Baeder /// Checks if the storage has been dynamically allocated. 522df11ee21STimm Baeder bool isDynamic() const { 523df11ee21STimm Baeder if (isBlockPointer()) { 524df11ee21STimm Baeder assert(asBlockPointer().Pointee); 525df11ee21STimm Baeder return asBlockPointer().Pointee->isDynamic(); 526df11ee21STimm Baeder } 527df11ee21STimm Baeder return false; 528df11ee21STimm Baeder } 529a07aba5dSTimm Baeder /// Checks if the storage is a static temporary. 530a07aba5dSTimm Baeder bool isStaticTemporary() const { return isStatic() && isTemporary(); } 531a07aba5dSTimm Baeder 532a07aba5dSTimm Baeder /// Checks if the field is mutable. 533a07aba5dSTimm Baeder bool isMutable() const { 534a07aba5dSTimm Baeder if (!isBlockPointer()) 535a07aba5dSTimm Baeder return false; 536a07aba5dSTimm Baeder return !isRoot() && getInlineDesc()->IsFieldMutable; 537a07aba5dSTimm Baeder } 538a07aba5dSTimm Baeder 539a07aba5dSTimm Baeder bool isWeak() const { 540a07aba5dSTimm Baeder if (!isBlockPointer()) 541a07aba5dSTimm Baeder return false; 542a07aba5dSTimm Baeder 543a07aba5dSTimm Baeder assert(isBlockPointer()); 5444e5f8a8fSTimm Baeder return asBlockPointer().Pointee->isWeak(); 545a07aba5dSTimm Baeder } 546a07aba5dSTimm Baeder /// Checks if an object was initialized. 547a07aba5dSTimm Baeder bool isInitialized() const; 548a07aba5dSTimm Baeder /// Checks if the object is active. 549a07aba5dSTimm Baeder bool isActive() const { 550a07aba5dSTimm Baeder if (!isBlockPointer()) 551a07aba5dSTimm Baeder return true; 552a07aba5dSTimm Baeder return isRoot() || getInlineDesc()->IsActive; 553a07aba5dSTimm Baeder } 554a07aba5dSTimm Baeder /// Checks if a structure is a base class. 555a07aba5dSTimm Baeder bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } 556a07aba5dSTimm Baeder bool isVirtualBaseClass() const { 557a07aba5dSTimm Baeder return isField() && getInlineDesc()->IsVirtualBase; 558a07aba5dSTimm Baeder } 559a07aba5dSTimm Baeder /// Checks if the pointer points to a dummy value. 560a07aba5dSTimm Baeder bool isDummy() const { 561a07aba5dSTimm Baeder if (!isBlockPointer()) 562a07aba5dSTimm Baeder return false; 563a07aba5dSTimm Baeder 564a07aba5dSTimm Baeder if (!asBlockPointer().Pointee) 565a07aba5dSTimm Baeder return false; 566a07aba5dSTimm Baeder 567a07aba5dSTimm Baeder return getDeclDesc()->isDummy(); 568a07aba5dSTimm Baeder } 569a07aba5dSTimm Baeder 570a07aba5dSTimm Baeder /// Checks if an object or a subfield is mutable. 571a07aba5dSTimm Baeder bool isConst() const { 572a07aba5dSTimm Baeder if (isIntegralPointer()) 573a07aba5dSTimm Baeder return true; 574a07aba5dSTimm Baeder return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; 575a07aba5dSTimm Baeder } 576a07aba5dSTimm Baeder 577a07aba5dSTimm Baeder /// Returns the declaration ID. 578a07aba5dSTimm Baeder std::optional<unsigned> getDeclID() const { 579a07aba5dSTimm Baeder if (isBlockPointer()) { 580a07aba5dSTimm Baeder assert(asBlockPointer().Pointee); 581a07aba5dSTimm Baeder return asBlockPointer().Pointee->getDeclID(); 582a07aba5dSTimm Baeder } 583a07aba5dSTimm Baeder return std::nullopt; 584a07aba5dSTimm Baeder } 585a07aba5dSTimm Baeder 586a07aba5dSTimm Baeder /// Returns the byte offset from the start. 587db94852bSTimm Baeder uint64_t getByteOffset() const { 588a07aba5dSTimm Baeder if (isIntegralPointer()) 589a07aba5dSTimm Baeder return asIntPointer().Value + Offset; 590a07aba5dSTimm Baeder if (isOnePastEnd()) 591a07aba5dSTimm Baeder return PastEndMark; 592a07aba5dSTimm Baeder return Offset; 593a07aba5dSTimm Baeder } 594a07aba5dSTimm Baeder 595a07aba5dSTimm Baeder /// Returns the number of elements. 596a07aba5dSTimm Baeder unsigned getNumElems() const { 597a07aba5dSTimm Baeder if (!isBlockPointer()) 598a07aba5dSTimm Baeder return ~0u; 599a07aba5dSTimm Baeder return getSize() / elemSize(); 600a07aba5dSTimm Baeder } 601a07aba5dSTimm Baeder 602a07aba5dSTimm Baeder const Block *block() const { return asBlockPointer().Pointee; } 603a07aba5dSTimm Baeder 604a07aba5dSTimm Baeder /// Returns the index into an array. 605a07aba5dSTimm Baeder int64_t getIndex() const { 606a07aba5dSTimm Baeder if (!isBlockPointer()) 607dac18299STimm Baeder return getIntegerRepresentation(); 608a07aba5dSTimm Baeder 609a07aba5dSTimm Baeder if (isZero()) 610a07aba5dSTimm Baeder return 0; 611a07aba5dSTimm Baeder 612a07aba5dSTimm Baeder // narrow()ed element in a composite array. 613a07aba5dSTimm Baeder if (asBlockPointer().Base > sizeof(InlineDescriptor) && 614a07aba5dSTimm Baeder asBlockPointer().Base == Offset) 615a07aba5dSTimm Baeder return 0; 616a07aba5dSTimm Baeder 617a07aba5dSTimm Baeder if (auto ElemSize = elemSize()) 618a07aba5dSTimm Baeder return getOffset() / ElemSize; 619a07aba5dSTimm Baeder return 0; 620a07aba5dSTimm Baeder } 621a07aba5dSTimm Baeder 622a07aba5dSTimm Baeder /// Checks if the index is one past end. 623a07aba5dSTimm Baeder bool isOnePastEnd() const { 624e86b68ffSTimm Baeder if (!isBlockPointer()) 625a07aba5dSTimm Baeder return false; 626a07aba5dSTimm Baeder 627a07aba5dSTimm Baeder if (!asBlockPointer().Pointee) 628a07aba5dSTimm Baeder return false; 629a07aba5dSTimm Baeder 630a07aba5dSTimm Baeder if (isUnknownSizeArray()) 631a07aba5dSTimm Baeder return false; 632a07aba5dSTimm Baeder 633*51c7338cSTimm Baeder return isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray()); 634a07aba5dSTimm Baeder } 635a07aba5dSTimm Baeder 636a07aba5dSTimm Baeder /// Checks if the pointer points past the end of the object. 637a07aba5dSTimm Baeder bool isPastEnd() const { 638a07aba5dSTimm Baeder if (isIntegralPointer()) 639a07aba5dSTimm Baeder return false; 640a07aba5dSTimm Baeder 641a07aba5dSTimm Baeder return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize(); 642a07aba5dSTimm Baeder } 643a07aba5dSTimm Baeder 644a07aba5dSTimm Baeder /// Checks if the pointer is an out-of-bounds element pointer. 645a07aba5dSTimm Baeder bool isElementPastEnd() const { return Offset == PastEndMark; } 646a07aba5dSTimm Baeder 647a07aba5dSTimm Baeder /// Checks if the pointer is pointing to a zero-size array. 648a07aba5dSTimm Baeder bool isZeroSizeArray() const { 649db94852bSTimm Baeder if (isFunctionPointer()) 650db94852bSTimm Baeder return false; 651a07aba5dSTimm Baeder if (const auto *Desc = getFieldDesc()) 652a07aba5dSTimm Baeder return Desc->isZeroSizeArray(); 653a07aba5dSTimm Baeder return false; 654a07aba5dSTimm Baeder } 655a07aba5dSTimm Baeder 656a07aba5dSTimm Baeder /// Dereferences the pointer, if it's live. 657a07aba5dSTimm Baeder template <typename T> T &deref() const { 658a07aba5dSTimm Baeder assert(isLive() && "Invalid pointer"); 659a07aba5dSTimm Baeder assert(isBlockPointer()); 660a07aba5dSTimm Baeder assert(asBlockPointer().Pointee); 661a07aba5dSTimm Baeder assert(isDereferencable()); 662a07aba5dSTimm Baeder assert(Offset + sizeof(T) <= 663a07aba5dSTimm Baeder asBlockPointer().Pointee->getDescriptor()->getAllocSize()); 664a07aba5dSTimm Baeder 665a07aba5dSTimm Baeder if (isArrayRoot()) 666a07aba5dSTimm Baeder return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + 667a07aba5dSTimm Baeder asBlockPointer().Base + sizeof(InitMapPtr)); 668a07aba5dSTimm Baeder 669a07aba5dSTimm Baeder return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset); 670a07aba5dSTimm Baeder } 671a07aba5dSTimm Baeder 672a07aba5dSTimm Baeder /// Whether this block can be read from at all. This is only true for 673a07aba5dSTimm Baeder /// block pointers that point to a valid location inside that block. 674a07aba5dSTimm Baeder bool isDereferencable() const { 675a07aba5dSTimm Baeder if (!isBlockPointer()) 676a07aba5dSTimm Baeder return false; 677a07aba5dSTimm Baeder if (isPastEnd()) 678a07aba5dSTimm Baeder return false; 679a07aba5dSTimm Baeder 680a07aba5dSTimm Baeder return true; 681a07aba5dSTimm Baeder } 682a07aba5dSTimm Baeder 683a07aba5dSTimm Baeder /// Initializes a field. 684a07aba5dSTimm Baeder void initialize() const; 685a07aba5dSTimm Baeder /// Activats a field. 686a07aba5dSTimm Baeder void activate() const; 687a07aba5dSTimm Baeder /// Deactivates an entire strurcutre. 688a07aba5dSTimm Baeder void deactivate() const; 689a07aba5dSTimm Baeder 690a07aba5dSTimm Baeder /// Compare two pointers. 691a07aba5dSTimm Baeder ComparisonCategoryResult compare(const Pointer &Other) const { 692a07aba5dSTimm Baeder if (!hasSameBase(*this, Other)) 693a07aba5dSTimm Baeder return ComparisonCategoryResult::Unordered; 694a07aba5dSTimm Baeder 695a07aba5dSTimm Baeder if (Offset < Other.Offset) 696a07aba5dSTimm Baeder return ComparisonCategoryResult::Less; 697a07aba5dSTimm Baeder else if (Offset > Other.Offset) 698a07aba5dSTimm Baeder return ComparisonCategoryResult::Greater; 699a07aba5dSTimm Baeder 700a07aba5dSTimm Baeder return ComparisonCategoryResult::Equal; 701a07aba5dSTimm Baeder } 702a07aba5dSTimm Baeder 703a07aba5dSTimm Baeder /// Checks if two pointers are comparable. 704a07aba5dSTimm Baeder static bool hasSameBase(const Pointer &A, const Pointer &B); 705a07aba5dSTimm Baeder /// Checks if two pointers can be subtracted. 706a07aba5dSTimm Baeder static bool hasSameArray(const Pointer &A, const Pointer &B); 707a07aba5dSTimm Baeder /// Checks if both given pointers point to the same block. 708a07aba5dSTimm Baeder static bool pointToSameBlock(const Pointer &A, const Pointer &B); 709a07aba5dSTimm Baeder 710360e4abfSTimm Baeder /// Whether this points to a block that's been created for a "literal lvalue", 711360e4abfSTimm Baeder /// i.e. a non-MaterializeTemporaryExpr Expr. 712360e4abfSTimm Baeder bool pointsToLiteral() const; 713360e4abfSTimm Baeder 714a07aba5dSTimm Baeder /// Prints the pointer. 715a07aba5dSTimm Baeder void print(llvm::raw_ostream &OS) const; 716a07aba5dSTimm Baeder 717a07aba5dSTimm Baeder private: 718a07aba5dSTimm Baeder friend class Block; 719a07aba5dSTimm Baeder friend class DeadBlock; 720a07aba5dSTimm Baeder friend class MemberPointer; 721a07aba5dSTimm Baeder friend class InterpState; 722a07aba5dSTimm Baeder friend struct InitMap; 723a07aba5dSTimm Baeder friend class DynamicAllocator; 724a07aba5dSTimm Baeder 725a07aba5dSTimm Baeder /// Returns the embedded descriptor preceding a field. 726a07aba5dSTimm Baeder InlineDescriptor *getInlineDesc() const { 727d6d60707STimm Baeder assert(isBlockPointer()); 728a07aba5dSTimm Baeder assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor)); 729a07aba5dSTimm Baeder assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize()); 730d6d60707STimm Baeder assert(asBlockPointer().Base >= sizeof(InlineDescriptor)); 731a07aba5dSTimm Baeder return getDescriptor(asBlockPointer().Base); 732a07aba5dSTimm Baeder } 733a07aba5dSTimm Baeder 734a07aba5dSTimm Baeder /// Returns a descriptor at a given offset. 735a07aba5dSTimm Baeder InlineDescriptor *getDescriptor(unsigned Offset) const { 736a07aba5dSTimm Baeder assert(Offset != 0 && "Not a nested pointer"); 737a07aba5dSTimm Baeder assert(isBlockPointer()); 738a07aba5dSTimm Baeder assert(!isZero()); 739a07aba5dSTimm Baeder return reinterpret_cast<InlineDescriptor *>( 740a07aba5dSTimm Baeder asBlockPointer().Pointee->rawData() + Offset) - 741a07aba5dSTimm Baeder 1; 742a07aba5dSTimm Baeder } 743a07aba5dSTimm Baeder 744a07aba5dSTimm Baeder /// Returns a reference to the InitMapPtr which stores the initialization map. 745a07aba5dSTimm Baeder InitMapPtr &getInitMap() const { 746a07aba5dSTimm Baeder assert(isBlockPointer()); 747a07aba5dSTimm Baeder assert(!isZero()); 748a07aba5dSTimm Baeder return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() + 749a07aba5dSTimm Baeder asBlockPointer().Base); 750a07aba5dSTimm Baeder } 751a07aba5dSTimm Baeder 752a07aba5dSTimm Baeder /// Offset into the storage. 753a07aba5dSTimm Baeder uint64_t Offset = 0; 754a07aba5dSTimm Baeder 755a07aba5dSTimm Baeder /// Previous link in the pointer chain. 756a07aba5dSTimm Baeder Pointer *Prev = nullptr; 757a07aba5dSTimm Baeder /// Next link in the pointer chain. 758a07aba5dSTimm Baeder Pointer *Next = nullptr; 759a07aba5dSTimm Baeder 760a07aba5dSTimm Baeder union { 761a07aba5dSTimm Baeder BlockPointer BS; 762a07aba5dSTimm Baeder IntPointer Int; 763a07aba5dSTimm Baeder FunctionPointer Fn; 764e86b68ffSTimm Baeder TypeidPointer Typeid; 765a07aba5dSTimm Baeder } PointeeStorage; 766a07aba5dSTimm Baeder Storage StorageKind = Storage::Int; 767a07aba5dSTimm Baeder }; 768a07aba5dSTimm Baeder 769a07aba5dSTimm Baeder inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { 770a07aba5dSTimm Baeder P.print(OS); 771a07aba5dSTimm Baeder return OS; 772a07aba5dSTimm Baeder } 773a07aba5dSTimm Baeder 774a07aba5dSTimm Baeder } // namespace interp 775a07aba5dSTimm Baeder } // namespace clang 776a07aba5dSTimm Baeder 777a07aba5dSTimm Baeder #endif 778