Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Pointer.h
213799 views
//===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Defines the classes responsible for pointer tracking.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_POINTER_H13#define LLVM_CLANG_AST_INTERP_POINTER_H1415#include "Descriptor.h"16#include "FunctionPointer.h"17#include "InterpBlock.h"18#include "clang/AST/ComparisonCategories.h"19#include "clang/AST/Decl.h"20#include "clang/AST/DeclCXX.h"21#include "clang/AST/Expr.h"22#include "llvm/Support/raw_ostream.h"2324namespace clang {25namespace interp {26class Block;27class DeadBlock;28class Pointer;29class Context;30template <unsigned A, bool B> class Integral;31enum PrimType : unsigned;3233class Pointer;34inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);3536struct BlockPointer {37/// The block the pointer is pointing to.38Block *Pointee;39/// Start of the current subfield.40unsigned Base;41};4243struct IntPointer {44const Descriptor *Desc;45uint64_t Value;4647IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const;48IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const;49};5051struct TypeidPointer {52const Type *TypePtr;53const Type *TypeInfoType;54};5556enum class Storage { Block, Int, Fn, Typeid };5758/// A pointer to a memory block, live or dead.59///60/// This object can be allocated into interpreter stack frames. If pointing to61/// a live block, it is a link in the chain of pointers pointing to the block.62///63/// In the simplest form, a Pointer has a Block* (the pointee) and both Base64/// and Offset are 0, which means it will point to raw data.65///66/// The Base field is used to access metadata about the data. For primitive67/// arrays, the Base is followed by an InitMap. In a variety of cases, the68/// Base is preceded by an InlineDescriptor, which is used to track the69/// initialization state, among other things.70///71/// The Offset field is used to access the actual data. In other words, the72/// data the pointer decribes can be found at73/// Pointee->rawData() + Pointer.Offset.74///75///76/// Pointee Offset77/// │ │78/// │ │79/// ▼ ▼80/// ┌───────┬────────────┬─────────┬────────────────────────────┐81/// │ Block │ InlineDesc │ InitMap │ Actual Data │82/// └───────┴────────────┴─────────┴────────────────────────────┘83/// ▲84/// │85/// │86/// Base87class Pointer {88private:89static constexpr unsigned PastEndMark = ~0u;90static constexpr unsigned RootPtrMark = ~0u;9192public:93Pointer() {94StorageKind = Storage::Int;95PointeeStorage.Int.Value = 0;96PointeeStorage.Int.Desc = nullptr;97}98Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) {99PointeeStorage.Int = std::move(IntPtr);100}101Pointer(Block *B);102Pointer(Block *B, uint64_t BaseAndOffset);103Pointer(const Pointer &P);104Pointer(Pointer &&P);105Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)106: Offset(Offset), StorageKind(Storage::Int) {107PointeeStorage.Int.Value = Address;108PointeeStorage.Int.Desc = Desc;109}110Pointer(const Function *F, uint64_t Offset = 0)111: Offset(Offset), StorageKind(Storage::Fn) {112PointeeStorage.Fn = FunctionPointer(F);113}114Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)115: Offset(Offset), StorageKind(Storage::Typeid) {116PointeeStorage.Typeid.TypePtr = TypePtr;117PointeeStorage.Typeid.TypeInfoType = TypeInfoType;118}119Pointer(Block *Pointee, unsigned Base, uint64_t Offset);120~Pointer();121122void operator=(const Pointer &P);123void operator=(Pointer &&P);124125/// Equality operators are just for tests.126bool operator==(const Pointer &P) const {127if (P.StorageKind != StorageKind)128return false;129if (isIntegralPointer())130return P.asIntPointer().Value == asIntPointer().Value &&131P.asIntPointer().Desc == asIntPointer().Desc && P.Offset == Offset;132133if (isFunctionPointer())134return P.asFunctionPointer().getFunction() ==135asFunctionPointer().getFunction() &&136P.Offset == Offset;137138assert(isBlockPointer());139return P.asBlockPointer().Pointee == asBlockPointer().Pointee &&140P.asBlockPointer().Base == asBlockPointer().Base &&141P.Offset == Offset;142}143144bool operator!=(const Pointer &P) const { return !(P == *this); }145146/// Converts the pointer to an APValue.147APValue toAPValue(const ASTContext &ASTCtx) const;148149/// Converts the pointer to a string usable in diagnostics.150std::string toDiagnosticString(const ASTContext &Ctx) const;151152uint64_t getIntegerRepresentation() const {153if (isIntegralPointer())154return asIntPointer().Value + (Offset * elemSize());155if (isFunctionPointer())156return asFunctionPointer().getIntegerRepresentation() + Offset;157return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;158}159160/// Converts the pointer to an APValue that is an rvalue.161std::optional<APValue> toRValue(const Context &Ctx,162QualType ResultType) const;163164/// Offsets a pointer inside an array.165[[nodiscard]] Pointer atIndex(uint64_t Idx) const {166if (isIntegralPointer())167return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);168if (isFunctionPointer())169return Pointer(asFunctionPointer().getFunction(), Idx);170171if (asBlockPointer().Base == RootPtrMark)172return Pointer(asBlockPointer().Pointee, RootPtrMark,173getDeclDesc()->getSize());174uint64_t Off = Idx * elemSize();175if (getFieldDesc()->ElemDesc)176Off += sizeof(InlineDescriptor);177else178Off += sizeof(InitMapPtr);179return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,180asBlockPointer().Base + Off);181}182183/// Creates a pointer to a field.184[[nodiscard]] Pointer atField(unsigned Off) const {185assert(isBlockPointer());186unsigned Field = Offset + Off;187return Pointer(asBlockPointer().Pointee, Field, Field);188}189190/// Subtract the given offset from the current Base and Offset191/// of the pointer.192[[nodiscard]] Pointer atFieldSub(unsigned Off) const {193assert(Offset >= Off);194unsigned O = Offset - Off;195return Pointer(asBlockPointer().Pointee, O, O);196}197198/// Restricts the scope of an array element pointer.199[[nodiscard]] Pointer narrow() const {200if (!isBlockPointer())201return *this;202assert(isBlockPointer());203// Null pointers cannot be narrowed.204if (isZero() || isUnknownSizeArray())205return *this;206207unsigned Base = asBlockPointer().Base;208// Pointer to an array of base types - enter block.209if (Base == RootPtrMark)210return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor),211Offset == 0 ? Offset : PastEndMark);212213// Pointer is one past end - magic offset marks that.214if (isOnePastEnd())215return Pointer(asBlockPointer().Pointee, Base, PastEndMark);216217if (Offset != Base) {218// If we're pointing to a primitive array element, there's nothing to do.219if (inPrimitiveArray())220return *this;221// Pointer is to a composite array element - enter it.222if (Offset != Base)223return Pointer(asBlockPointer().Pointee, Offset, Offset);224}225226// Otherwise, we're pointing to a non-array element or227// are already narrowed to a composite array element. Nothing to do.228return *this;229}230231/// Expands a pointer to the containing array, undoing narrowing.232[[nodiscard]] Pointer expand() const {233assert(isBlockPointer());234Block *Pointee = asBlockPointer().Pointee;235236if (isElementPastEnd()) {237// Revert to an outer one-past-end pointer.238unsigned Adjust;239if (inPrimitiveArray())240Adjust = sizeof(InitMapPtr);241else242Adjust = sizeof(InlineDescriptor);243return Pointer(Pointee, asBlockPointer().Base,244asBlockPointer().Base + getSize() + Adjust);245}246247// Do not step out of array elements.248if (asBlockPointer().Base != Offset)249return *this;250251if (isRoot())252return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base);253254// Step into the containing array, if inside one.255unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;256const Descriptor *Desc =257(Next == Pointee->getDescriptor()->getMetadataSize())258? getDeclDesc()259: getDescriptor(Next)->Desc;260if (!Desc->IsArray)261return *this;262return Pointer(Pointee, Next, Offset);263}264265/// Checks if the pointer is null.266bool isZero() const {267if (isBlockPointer())268return asBlockPointer().Pointee == nullptr;269if (isFunctionPointer())270return asFunctionPointer().isZero();271if (isTypeidPointer())272return false;273assert(isIntegralPointer());274return asIntPointer().Value == 0 && Offset == 0;275}276/// Checks if the pointer is live.277bool isLive() const {278if (!isBlockPointer())279return true;280return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead;281}282/// Checks if the item is a field in an object.283bool isField() const {284if (!isBlockPointer())285return false;286287return !isRoot() && getFieldDesc()->asDecl();288}289290/// Accessor for information about the declaration site.291const Descriptor *getDeclDesc() const {292if (isIntegralPointer())293return asIntPointer().Desc;294if (isFunctionPointer() || isTypeidPointer())295return nullptr;296297assert(isBlockPointer());298assert(asBlockPointer().Pointee);299return asBlockPointer().Pointee->Desc;300}301SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }302303/// Returns the expression or declaration the pointer has been created for.304DeclTy getSource() const {305if (isBlockPointer())306return getDeclDesc()->getSource();307if (isFunctionPointer()) {308const Function *F = asFunctionPointer().getFunction();309return F ? F->getDecl() : DeclTy();310}311assert(isIntegralPointer());312return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy();313}314315/// Returns a pointer to the object of which this pointer is a field.316[[nodiscard]] Pointer getBase() const {317if (asBlockPointer().Base == RootPtrMark) {318assert(Offset == PastEndMark && "cannot get base of a block");319return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);320}321unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset;322return Pointer(asBlockPointer().Pointee, NewBase, NewBase);323}324/// Returns the parent array.325[[nodiscard]] Pointer getArray() const {326if (asBlockPointer().Base == RootPtrMark) {327assert(Offset != 0 && Offset != PastEndMark && "not an array element");328return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);329}330assert(Offset != asBlockPointer().Base && "not an array element");331return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,332asBlockPointer().Base);333}334335/// Accessors for information about the innermost field.336const Descriptor *getFieldDesc() const {337if (isIntegralPointer())338return asIntPointer().Desc;339340if (isRoot())341return getDeclDesc();342return getInlineDesc()->Desc;343}344345/// Returns the type of the innermost field.346QualType getType() const {347if (isTypeidPointer())348return QualType(PointeeStorage.Typeid.TypeInfoType, 0);349350if (inPrimitiveArray() && Offset != asBlockPointer().Base) {351// Unfortunately, complex and vector types are not array types in clang,352// but they are for us.353if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())354return AT->getElementType();355if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>())356return CT->getElementType();357if (const auto *CT = getFieldDesc()->getType()->getAs<VectorType>())358return CT->getElementType();359}360return getFieldDesc()->getType();361}362363[[nodiscard]] Pointer getDeclPtr() const {364return Pointer(asBlockPointer().Pointee);365}366367/// Returns the element size of the innermost field.368size_t elemSize() const {369if (isIntegralPointer()) {370if (!asIntPointer().Desc)371return 1;372return asIntPointer().Desc->getElemSize();373}374375if (asBlockPointer().Base == RootPtrMark)376return getDeclDesc()->getSize();377return getFieldDesc()->getElemSize();378}379/// Returns the total size of the innermost field.380size_t getSize() const {381assert(isBlockPointer());382return getFieldDesc()->getSize();383}384385/// Returns the offset into an array.386unsigned getOffset() const {387assert(Offset != PastEndMark && "invalid offset");388assert(isBlockPointer());389if (asBlockPointer().Base == RootPtrMark)390return Offset;391392unsigned Adjust = 0;393if (Offset != asBlockPointer().Base) {394if (getFieldDesc()->ElemDesc)395Adjust = sizeof(InlineDescriptor);396else397Adjust = sizeof(InitMapPtr);398}399return Offset - asBlockPointer().Base - Adjust;400}401402/// Whether this array refers to an array, but not403/// to the first element.404bool isArrayRoot() const {405return inArray() && Offset == asBlockPointer().Base;406}407408/// Checks if the innermost field is an array.409bool inArray() const {410if (isBlockPointer())411return getFieldDesc()->IsArray;412return false;413}414bool inUnion() const {415if (isBlockPointer() && asBlockPointer().Base >= sizeof(InlineDescriptor))416return getInlineDesc()->InUnion;417return false;418};419420/// Checks if the structure is a primitive array.421bool inPrimitiveArray() const {422if (isBlockPointer())423return getFieldDesc()->isPrimitiveArray();424return false;425}426/// Checks if the structure is an array of unknown size.427bool isUnknownSizeArray() const {428if (!isBlockPointer())429return false;430return getFieldDesc()->isUnknownSizeArray();431}432/// Checks if the pointer points to an array.433bool isArrayElement() const {434if (!isBlockPointer())435return false;436437const BlockPointer &BP = asBlockPointer();438if (inArray() && BP.Base != Offset)439return true;440441// Might be a narrow()'ed element in a composite array.442// Check the inline descriptor.443if (BP.Base >= sizeof(InlineDescriptor) && getInlineDesc()->IsArrayElement)444return true;445446return false;447}448/// Pointer points directly to a block.449bool isRoot() const {450if (isZero() || !isBlockPointer())451return true;452return (asBlockPointer().Base ==453asBlockPointer().Pointee->getDescriptor()->getMetadataSize() ||454asBlockPointer().Base == 0);455}456/// If this pointer has an InlineDescriptor we can use to initialize.457bool canBeInitialized() const {458if (!isBlockPointer())459return false;460461return asBlockPointer().Pointee && asBlockPointer().Base > 0;462}463464[[nodiscard]] const BlockPointer &asBlockPointer() const {465assert(isBlockPointer());466return PointeeStorage.BS;467}468[[nodiscard]] const IntPointer &asIntPointer() const {469assert(isIntegralPointer());470return PointeeStorage.Int;471}472[[nodiscard]] const FunctionPointer &asFunctionPointer() const {473assert(isFunctionPointer());474return PointeeStorage.Fn;475}476[[nodiscard]] const TypeidPointer &asTypeidPointer() const {477assert(isTypeidPointer());478return PointeeStorage.Typeid;479}480481bool isBlockPointer() const { return StorageKind == Storage::Block; }482bool isIntegralPointer() const { return StorageKind == Storage::Int; }483bool isFunctionPointer() const { return StorageKind == Storage::Fn; }484bool isTypeidPointer() const { return StorageKind == Storage::Typeid; }485486/// Returns the record descriptor of a class.487const Record *getRecord() const { return getFieldDesc()->ElemRecord; }488/// Returns the element record type, if this is a non-primive array.489const Record *getElemRecord() const {490const Descriptor *ElemDesc = getFieldDesc()->ElemDesc;491return ElemDesc ? ElemDesc->ElemRecord : nullptr;492}493/// Returns the field information.494const FieldDecl *getField() const {495if (const Descriptor *FD = getFieldDesc())496return FD->asFieldDecl();497return nullptr;498}499500/// Checks if the storage is extern.501bool isExtern() const {502if (isBlockPointer())503return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern();504return false;505}506/// Checks if the storage is static.507bool isStatic() const {508if (!isBlockPointer())509return true;510assert(asBlockPointer().Pointee);511return asBlockPointer().Pointee->isStatic();512}513/// Checks if the storage is temporary.514bool isTemporary() const {515if (isBlockPointer()) {516assert(asBlockPointer().Pointee);517return asBlockPointer().Pointee->isTemporary();518}519return false;520}521/// Checks if the storage has been dynamically allocated.522bool isDynamic() const {523if (isBlockPointer()) {524assert(asBlockPointer().Pointee);525return asBlockPointer().Pointee->isDynamic();526}527return false;528}529/// Checks if the storage is a static temporary.530bool isStaticTemporary() const { return isStatic() && isTemporary(); }531532/// Checks if the field is mutable.533bool isMutable() const {534if (!isBlockPointer())535return false;536return !isRoot() && getInlineDesc()->IsFieldMutable;537}538539bool isWeak() const {540if (isFunctionPointer())541return asFunctionPointer().isWeak();542if (!isBlockPointer())543return false;544545assert(isBlockPointer());546return asBlockPointer().Pointee->isWeak();547}548/// Checks if an object was initialized.549bool isInitialized() const;550/// Checks if the object is active.551bool isActive() const {552if (!isBlockPointer())553return true;554return isRoot() || getInlineDesc()->IsActive;555}556/// Checks if a structure is a base class.557bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }558bool isVirtualBaseClass() const {559return isField() && getInlineDesc()->IsVirtualBase;560}561/// Checks if the pointer points to a dummy value.562bool isDummy() const {563if (!isBlockPointer())564return false;565566if (!asBlockPointer().Pointee)567return false;568569return getDeclDesc()->isDummy();570}571572/// Checks if an object or a subfield is mutable.573bool isConst() const {574if (isIntegralPointer())575return true;576return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;577}578579/// Checks if an object or a subfield is volatile.580bool isVolatile() const {581if (!isBlockPointer())582return false;583return isRoot() ? getDeclDesc()->IsVolatile : getInlineDesc()->IsVolatile;584}585586/// Returns the declaration ID.587std::optional<unsigned> getDeclID() const {588if (isBlockPointer()) {589assert(asBlockPointer().Pointee);590return asBlockPointer().Pointee->getDeclID();591}592return std::nullopt;593}594595/// Returns the byte offset from the start.596uint64_t getByteOffset() const {597if (isIntegralPointer())598return asIntPointer().Value + Offset;599if (isTypeidPointer())600return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;601if (isOnePastEnd())602return PastEndMark;603return Offset;604}605606/// Returns the number of elements.607unsigned getNumElems() const {608if (!isBlockPointer())609return ~0u;610return getSize() / elemSize();611}612613const Block *block() const { return asBlockPointer().Pointee; }614615/// If backed by actual data (i.e. a block pointer), return616/// an address to that data.617const std::byte *getRawAddress() const {618assert(isBlockPointer());619return asBlockPointer().Pointee->rawData() + Offset;620}621622/// Returns the index into an array.623int64_t getIndex() const {624if (!isBlockPointer())625return getIntegerRepresentation();626627if (isZero())628return 0;629630// narrow()ed element in a composite array.631if (asBlockPointer().Base > sizeof(InlineDescriptor) &&632asBlockPointer().Base == Offset)633return 0;634635if (auto ElemSize = elemSize())636return getOffset() / ElemSize;637return 0;638}639640/// Checks if the index is one past end.641bool isOnePastEnd() const {642if (!isBlockPointer())643return false;644645if (!asBlockPointer().Pointee)646return false;647648if (isUnknownSizeArray())649return false;650651return isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray());652}653654/// Checks if the pointer points past the end of the object.655bool isPastEnd() const {656if (isIntegralPointer())657return false;658659return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize();660}661662/// Checks if the pointer is an out-of-bounds element pointer.663bool isElementPastEnd() const { return Offset == PastEndMark; }664665/// Checks if the pointer is pointing to a zero-size array.666bool isZeroSizeArray() const {667if (isFunctionPointer())668return false;669if (const auto *Desc = getFieldDesc())670return Desc->isZeroSizeArray();671return false;672}673674/// Dereferences the pointer, if it's live.675template <typename T> T &deref() const {676assert(isLive() && "Invalid pointer");677assert(isBlockPointer());678assert(asBlockPointer().Pointee);679assert(isDereferencable());680assert(Offset + sizeof(T) <=681asBlockPointer().Pointee->getDescriptor()->getAllocSize());682683if (isArrayRoot())684return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +685asBlockPointer().Base + sizeof(InitMapPtr));686687return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset);688}689690/// Whether this block can be read from at all. This is only true for691/// block pointers that point to a valid location inside that block.692bool isDereferencable() const {693if (!isBlockPointer())694return false;695if (isPastEnd())696return false;697698return true;699}700701/// Initializes a field.702void initialize() const;703/// Activats a field.704void activate() const;705/// Deactivates an entire strurcutre.706void deactivate() const;707708Lifetime getLifetime() const {709if (!isBlockPointer())710return Lifetime::Started;711if (asBlockPointer().Base < sizeof(InlineDescriptor))712return Lifetime::Started;713return getInlineDesc()->LifeState;714}715716void endLifetime() const {717if (!isBlockPointer())718return;719if (asBlockPointer().Base < sizeof(InlineDescriptor))720return;721getInlineDesc()->LifeState = Lifetime::Ended;722}723724void startLifetime() const {725if (!isBlockPointer())726return;727if (asBlockPointer().Base < sizeof(InlineDescriptor))728return;729getInlineDesc()->LifeState = Lifetime::Started;730}731732/// Compare two pointers.733ComparisonCategoryResult compare(const Pointer &Other) const {734if (!hasSameBase(*this, Other))735return ComparisonCategoryResult::Unordered;736737if (Offset < Other.Offset)738return ComparisonCategoryResult::Less;739else if (Offset > Other.Offset)740return ComparisonCategoryResult::Greater;741742return ComparisonCategoryResult::Equal;743}744745/// Checks if two pointers are comparable.746static bool hasSameBase(const Pointer &A, const Pointer &B);747/// Checks if two pointers can be subtracted.748static bool hasSameArray(const Pointer &A, const Pointer &B);749/// Checks if both given pointers point to the same block.750static bool pointToSameBlock(const Pointer &A, const Pointer &B);751752static std::optional<std::pair<Pointer, Pointer>>753computeSplitPoint(const Pointer &A, const Pointer &B);754755/// Whether this points to a block that's been created for a "literal lvalue",756/// i.e. a non-MaterializeTemporaryExpr Expr.757bool pointsToLiteral() const;758bool pointsToStringLiteral() const;759760/// Prints the pointer.761void print(llvm::raw_ostream &OS) const;762763/// Compute an integer that can be used to compare this pointer to764/// another one. This is usually NOT the same as the pointer offset765/// regarding the AST record layout.766size_t computeOffsetForComparison() const;767768private:769friend class Block;770friend class DeadBlock;771friend class MemberPointer;772friend class InterpState;773friend struct InitMap;774friend class DynamicAllocator;775776/// Returns the embedded descriptor preceding a field.777InlineDescriptor *getInlineDesc() const {778assert(isBlockPointer());779assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));780assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());781assert(asBlockPointer().Base >= sizeof(InlineDescriptor));782return getDescriptor(asBlockPointer().Base);783}784785/// Returns a descriptor at a given offset.786InlineDescriptor *getDescriptor(unsigned Offset) const {787assert(Offset != 0 && "Not a nested pointer");788assert(isBlockPointer());789assert(!isZero());790return reinterpret_cast<InlineDescriptor *>(791asBlockPointer().Pointee->rawData() + Offset) -7921;793}794795/// Returns a reference to the InitMapPtr which stores the initialization map.796InitMapPtr &getInitMap() const {797assert(isBlockPointer());798assert(!isZero());799return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() +800asBlockPointer().Base);801}802803/// Offset into the storage.804uint64_t Offset = 0;805806/// Previous link in the pointer chain.807Pointer *Prev = nullptr;808/// Next link in the pointer chain.809Pointer *Next = nullptr;810811Storage StorageKind = Storage::Int;812union {813BlockPointer BS;814IntPointer Int;815FunctionPointer Fn;816TypeidPointer Typeid;817} PointeeStorage;818};819820inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {821P.print(OS);822return OS;823}824825} // namespace interp826} // namespace clang827828#endif829830831