1a7dea167SDimitry Andric //===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric // 9a7dea167SDimitry Andric // Defines the classes responsible for pointer tracking. 10a7dea167SDimitry Andric // 11a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 12a7dea167SDimitry Andric 13a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_POINTER_H 14a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_POINTER_H 15a7dea167SDimitry Andric 16a7dea167SDimitry Andric #include "Descriptor.h" 175ffd83dbSDimitry Andric #include "InterpBlock.h" 185ffd83dbSDimitry Andric #include "clang/AST/ComparisonCategories.h" 19a7dea167SDimitry Andric #include "clang/AST/Decl.h" 20a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h" 21a7dea167SDimitry Andric #include "clang/AST/Expr.h" 22a7dea167SDimitry Andric #include "llvm/ADT/PointerUnion.h" 23a7dea167SDimitry Andric #include "llvm/Support/raw_ostream.h" 24a7dea167SDimitry Andric 25a7dea167SDimitry Andric namespace clang { 26a7dea167SDimitry Andric namespace interp { 27a7dea167SDimitry Andric class Block; 28a7dea167SDimitry Andric class DeadBlock; 29a7dea167SDimitry Andric class Pointer; 30*5f757f3fSDimitry Andric class Context; 31a7dea167SDimitry Andric enum PrimType : unsigned; 32a7dea167SDimitry Andric 33*5f757f3fSDimitry Andric class Pointer; 34*5f757f3fSDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); 35*5f757f3fSDimitry Andric 36a7dea167SDimitry Andric /// A pointer to a memory block, live or dead. 37a7dea167SDimitry Andric /// 38a7dea167SDimitry Andric /// This object can be allocated into interpreter stack frames. If pointing to 39a7dea167SDimitry Andric /// a live block, it is a link in the chain of pointers pointing to the block. 40bdd1243dSDimitry Andric /// 41bdd1243dSDimitry Andric /// In the simplest form, a Pointer has a Block* (the pointee) and both Base 42bdd1243dSDimitry Andric /// and Offset are 0, which means it will point to raw data. 43bdd1243dSDimitry Andric /// 44bdd1243dSDimitry Andric /// The Base field is used to access metadata about the data. For primitive 45bdd1243dSDimitry Andric /// arrays, the Base is followed by an InitMap. In a variety of cases, the 46bdd1243dSDimitry Andric /// Base is preceded by an InlineDescriptor, which is used to track the 47bdd1243dSDimitry Andric /// initialization state, among other things. 48bdd1243dSDimitry Andric /// 49bdd1243dSDimitry Andric /// The Offset field is used to access the actual data. In other words, the 50bdd1243dSDimitry Andric /// data the pointer decribes can be found at 51bdd1243dSDimitry Andric /// Pointee->rawData() + Pointer.Offset. 52bdd1243dSDimitry Andric /// 53bdd1243dSDimitry Andric /// 54bdd1243dSDimitry Andric /// Pointee Offset 55bdd1243dSDimitry Andric /// │ │ 56bdd1243dSDimitry Andric /// │ │ 57bdd1243dSDimitry Andric /// ▼ ▼ 58bdd1243dSDimitry Andric /// ┌───────┬────────────┬─────────┬────────────────────────────┐ 59bdd1243dSDimitry Andric /// │ Block │ InlineDesc │ InitMap │ Actual Data │ 60bdd1243dSDimitry Andric /// └───────┴────────────┴─────────┴────────────────────────────┘ 61bdd1243dSDimitry Andric /// ▲ 62bdd1243dSDimitry Andric /// │ 63bdd1243dSDimitry Andric /// │ 64bdd1243dSDimitry Andric /// Base 65a7dea167SDimitry Andric class Pointer { 66a7dea167SDimitry Andric private: 67bdd1243dSDimitry Andric static constexpr unsigned PastEndMark = ~0u; 68bdd1243dSDimitry Andric static constexpr unsigned RootPtrMark = ~0u; 69a7dea167SDimitry Andric 70a7dea167SDimitry Andric public: 71a7dea167SDimitry Andric Pointer() {} 72a7dea167SDimitry Andric Pointer(Block *B); 73bdd1243dSDimitry Andric Pointer(Block *B, unsigned BaseAndOffset); 74a7dea167SDimitry Andric Pointer(const Pointer &P); 75a7dea167SDimitry Andric Pointer(Pointer &&P); 76a7dea167SDimitry Andric ~Pointer(); 77a7dea167SDimitry Andric 78a7dea167SDimitry Andric void operator=(const Pointer &P); 79a7dea167SDimitry Andric void operator=(Pointer &&P); 80a7dea167SDimitry Andric 81*5f757f3fSDimitry Andric /// Equality operators are just for tests. 82*5f757f3fSDimitry Andric bool operator==(const Pointer &P) const { 83*5f757f3fSDimitry Andric return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset; 84*5f757f3fSDimitry Andric } 85*5f757f3fSDimitry Andric 86*5f757f3fSDimitry Andric bool operator!=(const Pointer &P) const { 87*5f757f3fSDimitry Andric return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset; 88*5f757f3fSDimitry Andric } 89*5f757f3fSDimitry Andric 90a7dea167SDimitry Andric /// Converts the pointer to an APValue. 91a7dea167SDimitry Andric APValue toAPValue() const; 92a7dea167SDimitry Andric 93*5f757f3fSDimitry Andric /// Converts the pointer to a string usable in diagnostics. 94*5f757f3fSDimitry Andric std::string toDiagnosticString(const ASTContext &Ctx) const; 95*5f757f3fSDimitry Andric 96*5f757f3fSDimitry Andric unsigned getIntegerRepresentation() const { 97*5f757f3fSDimitry Andric return reinterpret_cast<uintptr_t>(Pointee) + Offset; 98*5f757f3fSDimitry Andric } 99*5f757f3fSDimitry Andric 100*5f757f3fSDimitry Andric /// Converts the pointer to an APValue that is an rvalue. 101*5f757f3fSDimitry Andric APValue toRValue(const Context &Ctx) const; 102*5f757f3fSDimitry Andric 103a7dea167SDimitry Andric /// Offsets a pointer inside an array. 104*5f757f3fSDimitry Andric [[nodiscard]] Pointer atIndex(unsigned Idx) const { 105a7dea167SDimitry Andric if (Base == RootPtrMark) 106a7dea167SDimitry Andric return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize()); 107a7dea167SDimitry Andric unsigned Off = Idx * elemSize(); 108a7dea167SDimitry Andric if (getFieldDesc()->ElemDesc) 109a7dea167SDimitry Andric Off += sizeof(InlineDescriptor); 110a7dea167SDimitry Andric else 111*5f757f3fSDimitry Andric Off += sizeof(InitMapPtr); 112a7dea167SDimitry Andric return Pointer(Pointee, Base, Base + Off); 113a7dea167SDimitry Andric } 114a7dea167SDimitry Andric 115a7dea167SDimitry Andric /// Creates a pointer to a field. 116*5f757f3fSDimitry Andric [[nodiscard]] Pointer atField(unsigned Off) const { 117a7dea167SDimitry Andric unsigned Field = Offset + Off; 118a7dea167SDimitry Andric return Pointer(Pointee, Field, Field); 119a7dea167SDimitry Andric } 120a7dea167SDimitry Andric 121*5f757f3fSDimitry Andric /// Subtract the given offset from the current Base and Offset 122*5f757f3fSDimitry Andric /// of the pointer. 123*5f757f3fSDimitry Andric [[nodiscard]] Pointer atFieldSub(unsigned Off) const { 124*5f757f3fSDimitry Andric assert(Offset >= Off); 125*5f757f3fSDimitry Andric unsigned O = Offset - Off; 126*5f757f3fSDimitry Andric return Pointer(Pointee, O, O); 127*5f757f3fSDimitry Andric } 128*5f757f3fSDimitry Andric 129a7dea167SDimitry Andric /// Restricts the scope of an array element pointer. 130*5f757f3fSDimitry Andric [[nodiscard]] Pointer narrow() const { 131a7dea167SDimitry Andric // Null pointers cannot be narrowed. 132a7dea167SDimitry Andric if (isZero() || isUnknownSizeArray()) 133a7dea167SDimitry Andric return *this; 134a7dea167SDimitry Andric 135a7dea167SDimitry Andric // Pointer to an array of base types - enter block. 136a7dea167SDimitry Andric if (Base == RootPtrMark) 137a7dea167SDimitry Andric return Pointer(Pointee, 0, Offset == 0 ? Offset : PastEndMark); 138a7dea167SDimitry Andric 139a7dea167SDimitry Andric // Pointer is one past end - magic offset marks that. 140a7dea167SDimitry Andric if (isOnePastEnd()) 141a7dea167SDimitry Andric return Pointer(Pointee, Base, PastEndMark); 142a7dea167SDimitry Andric 143a7dea167SDimitry Andric // Primitive arrays are a bit special since they do not have inline 144a7dea167SDimitry Andric // descriptors. If Offset != Base, then the pointer already points to 145a7dea167SDimitry Andric // an element and there is nothing to do. Otherwise, the pointer is 146a7dea167SDimitry Andric // adjusted to the first element of the array. 147a7dea167SDimitry Andric if (inPrimitiveArray()) { 148a7dea167SDimitry Andric if (Offset != Base) 149a7dea167SDimitry Andric return *this; 150*5f757f3fSDimitry Andric return Pointer(Pointee, Base, Offset + sizeof(InitMapPtr)); 151a7dea167SDimitry Andric } 152a7dea167SDimitry Andric 153a7dea167SDimitry Andric // Pointer is to a field or array element - enter it. 154a7dea167SDimitry Andric if (Offset != Base) 155a7dea167SDimitry Andric return Pointer(Pointee, Offset, Offset); 156a7dea167SDimitry Andric 157a7dea167SDimitry Andric // Enter the first element of an array. 158a7dea167SDimitry Andric if (!getFieldDesc()->isArray()) 159a7dea167SDimitry Andric return *this; 160a7dea167SDimitry Andric 161a7dea167SDimitry Andric const unsigned NewBase = Base + sizeof(InlineDescriptor); 162a7dea167SDimitry Andric return Pointer(Pointee, NewBase, NewBase); 163a7dea167SDimitry Andric } 164a7dea167SDimitry Andric 165a7dea167SDimitry Andric /// Expands a pointer to the containing array, undoing narrowing. 166*5f757f3fSDimitry Andric [[nodiscard]] Pointer expand() const { 167a7dea167SDimitry Andric if (isElementPastEnd()) { 168a7dea167SDimitry Andric // Revert to an outer one-past-end pointer. 169a7dea167SDimitry Andric unsigned Adjust; 170a7dea167SDimitry Andric if (inPrimitiveArray()) 171*5f757f3fSDimitry Andric Adjust = sizeof(InitMapPtr); 172a7dea167SDimitry Andric else 173a7dea167SDimitry Andric Adjust = sizeof(InlineDescriptor); 174a7dea167SDimitry Andric return Pointer(Pointee, Base, Base + getSize() + Adjust); 175a7dea167SDimitry Andric } 176a7dea167SDimitry Andric 177a7dea167SDimitry Andric // Do not step out of array elements. 178a7dea167SDimitry Andric if (Base != Offset) 179a7dea167SDimitry Andric return *this; 180a7dea167SDimitry Andric 181a7dea167SDimitry Andric // If at base, point to an array of base types. 182a7dea167SDimitry Andric if (Base == 0) 183a7dea167SDimitry Andric return Pointer(Pointee, RootPtrMark, 0); 184a7dea167SDimitry Andric 185a7dea167SDimitry Andric // Step into the containing array, if inside one. 186a7dea167SDimitry Andric unsigned Next = Base - getInlineDesc()->Offset; 187*5f757f3fSDimitry Andric const Descriptor *Desc = 188*5f757f3fSDimitry Andric Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; 189a7dea167SDimitry Andric if (!Desc->IsArray) 190a7dea167SDimitry Andric return *this; 191a7dea167SDimitry Andric return Pointer(Pointee, Next, Offset); 192a7dea167SDimitry Andric } 193a7dea167SDimitry Andric 194a7dea167SDimitry Andric /// Checks if the pointer is null. 195a7dea167SDimitry Andric bool isZero() const { return Pointee == nullptr; } 196a7dea167SDimitry Andric /// Checks if the pointer is live. 197a7dea167SDimitry Andric bool isLive() const { return Pointee && !Pointee->IsDead; } 198a7dea167SDimitry Andric /// Checks if the item is a field in an object. 199a7dea167SDimitry Andric bool isField() const { return Base != 0 && Base != RootPtrMark; } 200a7dea167SDimitry Andric 201a7dea167SDimitry Andric /// Accessor for information about the declaration site. 202*5f757f3fSDimitry Andric const Descriptor *getDeclDesc() const { 203*5f757f3fSDimitry Andric assert(Pointee); 204*5f757f3fSDimitry Andric return Pointee->Desc; 205*5f757f3fSDimitry Andric } 206a7dea167SDimitry Andric SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } 207a7dea167SDimitry Andric 208a7dea167SDimitry Andric /// Returns a pointer to the object of which this pointer is a field. 209*5f757f3fSDimitry Andric [[nodiscard]] Pointer getBase() const { 210a7dea167SDimitry Andric if (Base == RootPtrMark) { 211a7dea167SDimitry Andric assert(Offset == PastEndMark && "cannot get base of a block"); 212a7dea167SDimitry Andric return Pointer(Pointee, Base, 0); 213a7dea167SDimitry Andric } 214a7dea167SDimitry Andric assert(Offset == Base && "not an inner field"); 215a7dea167SDimitry Andric unsigned NewBase = Base - getInlineDesc()->Offset; 216a7dea167SDimitry Andric return Pointer(Pointee, NewBase, NewBase); 217a7dea167SDimitry Andric } 218a7dea167SDimitry Andric /// Returns the parent array. 219*5f757f3fSDimitry Andric [[nodiscard]] Pointer getArray() const { 220a7dea167SDimitry Andric if (Base == RootPtrMark) { 221a7dea167SDimitry Andric assert(Offset != 0 && Offset != PastEndMark && "not an array element"); 222a7dea167SDimitry Andric return Pointer(Pointee, Base, 0); 223a7dea167SDimitry Andric } 224a7dea167SDimitry Andric assert(Offset != Base && "not an array element"); 225a7dea167SDimitry Andric return Pointer(Pointee, Base, Base); 226a7dea167SDimitry Andric } 227a7dea167SDimitry Andric 228a7dea167SDimitry Andric /// Accessors for information about the innermost field. 229*5f757f3fSDimitry Andric const Descriptor *getFieldDesc() const { 230a7dea167SDimitry Andric if (Base == 0 || Base == RootPtrMark) 231a7dea167SDimitry Andric return getDeclDesc(); 232a7dea167SDimitry Andric return getInlineDesc()->Desc; 233a7dea167SDimitry Andric } 234a7dea167SDimitry Andric 235a7dea167SDimitry Andric /// Returns the type of the innermost field. 236*5f757f3fSDimitry Andric QualType getType() const { 237*5f757f3fSDimitry Andric if (inPrimitiveArray() && Offset != Base) 238*5f757f3fSDimitry Andric return getFieldDesc()->getType()->getAsArrayTypeUnsafe()->getElementType(); 239*5f757f3fSDimitry Andric return getFieldDesc()->getType(); 240*5f757f3fSDimitry Andric } 241a7dea167SDimitry Andric 242*5f757f3fSDimitry Andric [[nodiscard]] Pointer getDeclPtr() const { return Pointer(Pointee); } 24306c3fb27SDimitry Andric 244a7dea167SDimitry Andric /// Returns the element size of the innermost field. 245a7dea167SDimitry Andric size_t elemSize() const { 246a7dea167SDimitry Andric if (Base == RootPtrMark) 247a7dea167SDimitry Andric return getDeclDesc()->getSize(); 248a7dea167SDimitry Andric return getFieldDesc()->getElemSize(); 249a7dea167SDimitry Andric } 250a7dea167SDimitry Andric /// Returns the total size of the innermost field. 251a7dea167SDimitry Andric size_t getSize() const { return getFieldDesc()->getSize(); } 252a7dea167SDimitry Andric 253a7dea167SDimitry Andric /// Returns the offset into an array. 254a7dea167SDimitry Andric unsigned getOffset() const { 255a7dea167SDimitry Andric assert(Offset != PastEndMark && "invalid offset"); 256a7dea167SDimitry Andric if (Base == RootPtrMark) 257a7dea167SDimitry Andric return Offset; 258a7dea167SDimitry Andric 259a7dea167SDimitry Andric unsigned Adjust = 0; 260a7dea167SDimitry Andric if (Offset != Base) { 261a7dea167SDimitry Andric if (getFieldDesc()->ElemDesc) 262a7dea167SDimitry Andric Adjust = sizeof(InlineDescriptor); 263a7dea167SDimitry Andric else 264*5f757f3fSDimitry Andric Adjust = sizeof(InitMapPtr); 265a7dea167SDimitry Andric } 266a7dea167SDimitry Andric return Offset - Base - Adjust; 267a7dea167SDimitry Andric } 268a7dea167SDimitry Andric 26906c3fb27SDimitry Andric /// Whether this array refers to an array, but not 27006c3fb27SDimitry Andric /// to the first element. 27106c3fb27SDimitry Andric bool isArrayRoot() const { return inArray() && Offset == Base; } 27206c3fb27SDimitry Andric 273a7dea167SDimitry Andric /// Checks if the innermost field is an array. 274a7dea167SDimitry Andric bool inArray() const { return getFieldDesc()->IsArray; } 275a7dea167SDimitry Andric /// Checks if the structure is a primitive array. 276a7dea167SDimitry Andric bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); } 277a7dea167SDimitry Andric /// Checks if the structure is an array of unknown size. 278a7dea167SDimitry Andric bool isUnknownSizeArray() const { 279a7dea167SDimitry Andric return getFieldDesc()->isUnknownSizeArray(); 280a7dea167SDimitry Andric } 281a7dea167SDimitry Andric /// Checks if the pointer points to an array. 282*5f757f3fSDimitry Andric bool isArrayElement() const { return inArray() && Base != Offset; } 283a7dea167SDimitry Andric /// Pointer points directly to a block. 284a7dea167SDimitry Andric bool isRoot() const { 285a7dea167SDimitry Andric return (Base == 0 || Base == RootPtrMark) && Offset == 0; 286a7dea167SDimitry Andric } 287a7dea167SDimitry Andric 288a7dea167SDimitry Andric /// Returns the record descriptor of a class. 28906c3fb27SDimitry Andric const Record *getRecord() const { return getFieldDesc()->ElemRecord; } 29006c3fb27SDimitry Andric /// Returns the element record type, if this is a non-primive array. 29106c3fb27SDimitry Andric const Record *getElemRecord() const { 292*5f757f3fSDimitry Andric const Descriptor *ElemDesc = getFieldDesc()->ElemDesc; 293*5f757f3fSDimitry Andric return ElemDesc ? ElemDesc->ElemRecord : nullptr; 29406c3fb27SDimitry Andric } 295a7dea167SDimitry Andric /// Returns the field information. 296a7dea167SDimitry Andric const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); } 297a7dea167SDimitry Andric 298a7dea167SDimitry Andric /// Checks if the object is a union. 299a7dea167SDimitry Andric bool isUnion() const; 300a7dea167SDimitry Andric 301a7dea167SDimitry Andric /// Checks if the storage is extern. 302*5f757f3fSDimitry Andric bool isExtern() const { return Pointee && Pointee->isExtern(); } 303a7dea167SDimitry Andric /// Checks if the storage is static. 304*5f757f3fSDimitry Andric bool isStatic() const { 305*5f757f3fSDimitry Andric assert(Pointee); 306*5f757f3fSDimitry Andric return Pointee->isStatic(); 307*5f757f3fSDimitry Andric } 308a7dea167SDimitry Andric /// Checks if the storage is temporary. 309*5f757f3fSDimitry Andric bool isTemporary() const { 310*5f757f3fSDimitry Andric assert(Pointee); 311*5f757f3fSDimitry Andric return Pointee->isTemporary(); 312*5f757f3fSDimitry Andric } 313a7dea167SDimitry Andric /// Checks if the storage is a static temporary. 314a7dea167SDimitry Andric bool isStaticTemporary() const { return isStatic() && isTemporary(); } 315a7dea167SDimitry Andric 316a7dea167SDimitry Andric /// Checks if the field is mutable. 317bdd1243dSDimitry Andric bool isMutable() const { 318bdd1243dSDimitry Andric return Base != 0 && getInlineDesc()->IsFieldMutable; 319bdd1243dSDimitry Andric } 320a7dea167SDimitry Andric /// Checks if an object was initialized. 321a7dea167SDimitry Andric bool isInitialized() const; 322a7dea167SDimitry Andric /// Checks if the object is active. 323a7dea167SDimitry Andric bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; } 324a7dea167SDimitry Andric /// Checks if a structure is a base class. 325a7dea167SDimitry Andric bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } 326*5f757f3fSDimitry Andric /// Checks if the pointer pointers to a dummy value. 327*5f757f3fSDimitry Andric bool isDummy() const { return getDeclDesc()->isDummy(); } 328a7dea167SDimitry Andric 329a7dea167SDimitry Andric /// Checks if an object or a subfield is mutable. 330a7dea167SDimitry Andric bool isConst() const { 331a7dea167SDimitry Andric return Base == 0 ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; 332a7dea167SDimitry Andric } 333a7dea167SDimitry Andric 334a7dea167SDimitry Andric /// Returns the declaration ID. 335*5f757f3fSDimitry Andric std::optional<unsigned> getDeclID() const { 336*5f757f3fSDimitry Andric assert(Pointee); 337*5f757f3fSDimitry Andric return Pointee->getDeclID(); 338*5f757f3fSDimitry Andric } 339a7dea167SDimitry Andric 340a7dea167SDimitry Andric /// Returns the byte offset from the start. 341a7dea167SDimitry Andric unsigned getByteOffset() const { 342a7dea167SDimitry Andric return Offset; 343a7dea167SDimitry Andric } 344a7dea167SDimitry Andric 345a7dea167SDimitry Andric /// Returns the number of elements. 346a7dea167SDimitry Andric unsigned getNumElems() const { return getSize() / elemSize(); } 347a7dea167SDimitry Andric 34806c3fb27SDimitry Andric const Block *block() const { return Pointee; } 34906c3fb27SDimitry Andric 350a7dea167SDimitry Andric /// Returns the index into an array. 351a7dea167SDimitry Andric int64_t getIndex() const { 352a7dea167SDimitry Andric if (isElementPastEnd()) 353a7dea167SDimitry Andric return 1; 354*5f757f3fSDimitry Andric 355*5f757f3fSDimitry Andric // narrow()ed element in a composite array. 356*5f757f3fSDimitry Andric if (Base > 0 && Base == Offset) 357*5f757f3fSDimitry Andric return 0; 358*5f757f3fSDimitry Andric 359a7dea167SDimitry Andric if (auto ElemSize = elemSize()) 360a7dea167SDimitry Andric return getOffset() / ElemSize; 361a7dea167SDimitry Andric return 0; 362a7dea167SDimitry Andric } 363a7dea167SDimitry Andric 364a7dea167SDimitry Andric /// Checks if the index is one past end. 365a7dea167SDimitry Andric bool isOnePastEnd() const { 366*5f757f3fSDimitry Andric if (!Pointee) 367*5f757f3fSDimitry Andric return false; 368a7dea167SDimitry Andric return isElementPastEnd() || getSize() == getOffset(); 369a7dea167SDimitry Andric } 370a7dea167SDimitry Andric 371a7dea167SDimitry Andric /// Checks if the pointer is an out-of-bounds element pointer. 372a7dea167SDimitry Andric bool isElementPastEnd() const { return Offset == PastEndMark; } 373a7dea167SDimitry Andric 374a7dea167SDimitry Andric /// Dereferences the pointer, if it's live. 375a7dea167SDimitry Andric template <typename T> T &deref() const { 376a7dea167SDimitry Andric assert(isLive() && "Invalid pointer"); 377*5f757f3fSDimitry Andric assert(Pointee); 37806c3fb27SDimitry Andric if (isArrayRoot()) 37906c3fb27SDimitry Andric return *reinterpret_cast<T *>(Pointee->rawData() + Base + 380*5f757f3fSDimitry Andric sizeof(InitMapPtr)); 38106c3fb27SDimitry Andric 382bdd1243dSDimitry Andric return *reinterpret_cast<T *>(Pointee->rawData() + Offset); 383a7dea167SDimitry Andric } 384a7dea167SDimitry Andric 385a7dea167SDimitry Andric /// Dereferences a primitive element. 386a7dea167SDimitry Andric template <typename T> T &elem(unsigned I) const { 38706c3fb27SDimitry Andric assert(I < getNumElems()); 388*5f757f3fSDimitry Andric assert(Pointee); 389*5f757f3fSDimitry Andric return reinterpret_cast<T *>(Pointee->data() + sizeof(InitMapPtr))[I]; 390a7dea167SDimitry Andric } 391a7dea167SDimitry Andric 392a7dea167SDimitry Andric /// Initializes a field. 393a7dea167SDimitry Andric void initialize() const; 394a7dea167SDimitry Andric /// Activats a field. 395a7dea167SDimitry Andric void activate() const; 396a7dea167SDimitry Andric /// Deactivates an entire strurcutre. 397a7dea167SDimitry Andric void deactivate() const; 398a7dea167SDimitry Andric 399*5f757f3fSDimitry Andric /// Compare two pointers. 400*5f757f3fSDimitry Andric ComparisonCategoryResult compare(const Pointer &Other) const { 401*5f757f3fSDimitry Andric if (!hasSameBase(*this, Other)) 402*5f757f3fSDimitry Andric return ComparisonCategoryResult::Unordered; 403*5f757f3fSDimitry Andric 404*5f757f3fSDimitry Andric if (Offset < Other.Offset) 405*5f757f3fSDimitry Andric return ComparisonCategoryResult::Less; 406*5f757f3fSDimitry Andric else if (Offset > Other.Offset) 407*5f757f3fSDimitry Andric return ComparisonCategoryResult::Greater; 408*5f757f3fSDimitry Andric 409*5f757f3fSDimitry Andric return ComparisonCategoryResult::Equal; 410*5f757f3fSDimitry Andric } 411*5f757f3fSDimitry Andric 412a7dea167SDimitry Andric /// Checks if two pointers are comparable. 413a7dea167SDimitry Andric static bool hasSameBase(const Pointer &A, const Pointer &B); 414a7dea167SDimitry Andric /// Checks if two pointers can be subtracted. 415a7dea167SDimitry Andric static bool hasSameArray(const Pointer &A, const Pointer &B); 416a7dea167SDimitry Andric 417a7dea167SDimitry Andric /// Prints the pointer. 418a7dea167SDimitry Andric void print(llvm::raw_ostream &OS) const { 419*5f757f3fSDimitry Andric OS << Pointee << " {"; 420*5f757f3fSDimitry Andric if (Base == RootPtrMark) 421*5f757f3fSDimitry Andric OS << "rootptr, "; 422*5f757f3fSDimitry Andric else 423*5f757f3fSDimitry Andric OS << Base << ", "; 424*5f757f3fSDimitry Andric 425*5f757f3fSDimitry Andric if (Offset == PastEndMark) 426*5f757f3fSDimitry Andric OS << "pastend, "; 427*5f757f3fSDimitry Andric else 428*5f757f3fSDimitry Andric OS << Offset << ", "; 429*5f757f3fSDimitry Andric 430a7dea167SDimitry Andric if (Pointee) 431a7dea167SDimitry Andric OS << Pointee->getSize(); 432a7dea167SDimitry Andric else 433a7dea167SDimitry Andric OS << "nullptr"; 434a7dea167SDimitry Andric OS << "}"; 435a7dea167SDimitry Andric } 436a7dea167SDimitry Andric 437a7dea167SDimitry Andric private: 438a7dea167SDimitry Andric friend class Block; 439a7dea167SDimitry Andric friend class DeadBlock; 440*5f757f3fSDimitry Andric friend struct InitMap; 441a7dea167SDimitry Andric 442a7dea167SDimitry Andric Pointer(Block *Pointee, unsigned Base, unsigned Offset); 443a7dea167SDimitry Andric 444a7dea167SDimitry Andric /// Returns the embedded descriptor preceding a field. 445a7dea167SDimitry Andric InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); } 446a7dea167SDimitry Andric 447a7dea167SDimitry Andric /// Returns a descriptor at a given offset. 448a7dea167SDimitry Andric InlineDescriptor *getDescriptor(unsigned Offset) const { 449a7dea167SDimitry Andric assert(Offset != 0 && "Not a nested pointer"); 450*5f757f3fSDimitry Andric assert(Pointee); 451bdd1243dSDimitry Andric return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) - 452bdd1243dSDimitry Andric 1; 453a7dea167SDimitry Andric } 454a7dea167SDimitry Andric 455*5f757f3fSDimitry Andric /// Returns a reference to the InitMapPtr which stores the initialization map. 456*5f757f3fSDimitry Andric InitMapPtr &getInitMap() const { 457*5f757f3fSDimitry Andric assert(Pointee); 458*5f757f3fSDimitry Andric return *reinterpret_cast<InitMapPtr *>(Pointee->rawData() + Base); 459a7dea167SDimitry Andric } 460a7dea167SDimitry Andric 461a7dea167SDimitry Andric /// The block the pointer is pointing to. 462a7dea167SDimitry Andric Block *Pointee = nullptr; 463a7dea167SDimitry Andric /// Start of the current subfield. 464a7dea167SDimitry Andric unsigned Base = 0; 465a7dea167SDimitry Andric /// Offset into the block. 466a7dea167SDimitry Andric unsigned Offset = 0; 467a7dea167SDimitry Andric 468a7dea167SDimitry Andric /// Previous link in the pointer chain. 469a7dea167SDimitry Andric Pointer *Prev = nullptr; 470a7dea167SDimitry Andric /// Next link in the pointer chain. 471a7dea167SDimitry Andric Pointer *Next = nullptr; 472a7dea167SDimitry Andric }; 473a7dea167SDimitry Andric 474a7dea167SDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { 475a7dea167SDimitry Andric P.print(OS); 476a7dea167SDimitry Andric return OS; 477a7dea167SDimitry Andric } 478a7dea167SDimitry Andric 479a7dea167SDimitry Andric } // namespace interp 480a7dea167SDimitry Andric } // namespace clang 481a7dea167SDimitry Andric 482a7dea167SDimitry Andric #endif 483