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