brintos

brintos / llvm-project-archived public Read only

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