brintos

brintos / llvm-project-archived public Read only

0
0
Text · 26.6 KiB · 00e74db Raw
954 lines · cpp
1//===--- Pointer.cpp - 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#include "Pointer.h"10#include "Boolean.h"11#include "Context.h"12#include "Floating.h"13#include "Function.h"14#include "Integral.h"15#include "InterpBlock.h"16#include "MemberPointer.h"17#include "PrimType.h"18#include "Record.h"19#include "clang/AST/Expr.h"20#include "clang/AST/ExprCXX.h"21#include "clang/AST/RecordLayout.h"22 23using namespace clang;24using namespace clang::interp;25 26Pointer::Pointer(Block *Pointee)27    : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),28              Pointee->getDescriptor()->getMetadataSize()) {}29 30Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)31    : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}32 33Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)34    : Offset(Offset), StorageKind(Storage::Block) {35  assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");36  assert(Base >= Pointee->getDescriptor()->getMetadataSize());37 38  BS = {Pointee, Base, nullptr, nullptr};39 40  if (Pointee)41    Pointee->addPointer(this);42}43 44Pointer::Pointer(const Pointer &P)45    : Offset(P.Offset), StorageKind(P.StorageKind) {46  switch (StorageKind) {47  case Storage::Int:48    Int = P.Int;49    break;50  case Storage::Block:51    BS = P.BS;52    if (BS.Pointee)53      BS.Pointee->addPointer(this);54    break;55  case Storage::Fn:56    Fn = P.Fn;57    break;58  case Storage::Typeid:59    Typeid = P.Typeid;60    break;61  }62}63 64Pointer::Pointer(Pointer &&P) : Offset(P.Offset), StorageKind(P.StorageKind) {65  switch (StorageKind) {66  case Storage::Int:67    Int = P.Int;68    break;69  case Storage::Block:70    BS = P.BS;71    if (BS.Pointee)72      BS.Pointee->replacePointer(&P, this);73    break;74  case Storage::Fn:75    Fn = P.Fn;76    break;77  case Storage::Typeid:78    Typeid = P.Typeid;79    break;80  }81}82 83Pointer::~Pointer() {84  if (!isBlockPointer())85    return;86 87  if (Block *Pointee = BS.Pointee) {88    Pointee->removePointer(this);89    BS.Pointee = nullptr;90    Pointee->cleanup();91  }92}93 94Pointer &Pointer::operator=(const Pointer &P) {95  // If the current storage type is Block, we need to remove96  // this pointer from the block.97  if (isBlockPointer()) {98    if (P.isBlockPointer() && this->block() == P.block()) {99      Offset = P.Offset;100      BS.Base = P.BS.Base;101      return *this;102    }103 104    if (Block *Pointee = BS.Pointee) {105      Pointee->removePointer(this);106      BS.Pointee = nullptr;107      Pointee->cleanup();108    }109  }110 111  StorageKind = P.StorageKind;112  Offset = P.Offset;113 114  switch (StorageKind) {115  case Storage::Int:116    Int = P.Int;117    break;118  case Storage::Block:119    BS = P.BS;120 121    if (BS.Pointee)122      BS.Pointee->addPointer(this);123    break;124  case Storage::Fn:125    Fn = P.Fn;126    break;127  case Storage::Typeid:128    Typeid = P.Typeid;129  }130  return *this;131}132 133Pointer &Pointer::operator=(Pointer &&P) {134  // If the current storage type is Block, we need to remove135  // this pointer from the block.136  if (isBlockPointer()) {137    if (P.isBlockPointer() && this->block() == P.block()) {138      Offset = P.Offset;139      BS.Base = P.BS.Base;140      return *this;141    }142 143    if (Block *Pointee = BS.Pointee) {144      Pointee->removePointer(this);145      BS.Pointee = nullptr;146      Pointee->cleanup();147    }148  }149 150  StorageKind = P.StorageKind;151  Offset = P.Offset;152 153  switch (StorageKind) {154  case Storage::Int:155    Int = P.Int;156    break;157  case Storage::Block:158    BS = P.BS;159 160    if (BS.Pointee)161      BS.Pointee->addPointer(this);162    break;163  case Storage::Fn:164    Fn = P.Fn;165    break;166  case Storage::Typeid:167    Typeid = P.Typeid;168  }169  return *this;170}171 172APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {173  llvm::SmallVector<APValue::LValuePathEntry, 5> Path;174 175  if (isZero())176    return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,177                   /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);178  if (isIntegralPointer())179    return APValue(static_cast<const Expr *>(nullptr),180                   CharUnits::fromQuantity(asIntPointer().Value + this->Offset),181                   Path,182                   /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);183  if (isFunctionPointer()) {184    const FunctionPointer &FP = asFunctionPointer();185    if (const FunctionDecl *FD = FP.getFunction()->getDecl())186      return APValue(FD, CharUnits::fromQuantity(Offset), {},187                     /*OnePastTheEnd=*/false, /*IsNull=*/false);188    return APValue(FP.getFunction()->getExpr(), CharUnits::fromQuantity(Offset),189                   {},190                   /*OnePastTheEnd=*/false, /*IsNull=*/false);191  }192 193  if (isTypeidPointer()) {194    TypeInfoLValue TypeInfo(Typeid.TypePtr);195    return APValue(APValue::LValueBase::getTypeInfo(196                       TypeInfo, QualType(Typeid.TypeInfoType, 0)),197                   CharUnits::Zero(), {},198                   /*OnePastTheEnd=*/false, /*IsNull=*/false);199  }200 201  // Build the lvalue base from the block.202  const Descriptor *Desc = getDeclDesc();203  APValue::LValueBase Base;204  if (const auto *VD = Desc->asValueDecl())205    Base = VD;206  else if (const auto *E = Desc->asExpr()) {207    if (block()->isDynamic()) {208      QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);209      DynamicAllocLValue DA(*block()->DynAllocId);210      Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);211    } else {212      Base = E;213    }214  } else215    llvm_unreachable("Invalid allocation type");216 217  if (isUnknownSizeArray())218    return APValue(Base, CharUnits::Zero(), Path,219                   /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);220 221  CharUnits Offset = CharUnits::Zero();222 223  auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {224    // This shouldn't happen, but if it does, don't crash inside225    // getASTRecordLayout.226    if (FD->getParent()->isInvalidDecl())227      return CharUnits::Zero();228    const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());229    unsigned FieldIndex = FD->getFieldIndex();230    return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));231  };232 233  bool UsePath = true;234  if (const ValueDecl *VD = getDeclDesc()->asValueDecl();235      VD && VD->getType()->isReferenceType())236    UsePath = false;237 238  // Build the path into the object.239  bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();240  Pointer Ptr = *this;241  while (Ptr.isField() || Ptr.isArrayElement()) {242 243    if (Ptr.isArrayRoot()) {244      // An array root may still be an array element itself.245      if (Ptr.isArrayElement()) {246        Ptr = Ptr.expand();247        const Descriptor *Desc = Ptr.getFieldDesc();248        unsigned Index = Ptr.getIndex();249        QualType ElemType = Desc->getElemQualType();250        Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));251        if (Ptr.getArray().getType()->isArrayType())252          Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));253        Ptr = Ptr.getArray();254      } else {255        const Descriptor *Desc = Ptr.getFieldDesc();256        const auto *Dcl = Desc->asDecl();257        Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));258 259        if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl))260          Offset += getFieldOffset(FD);261 262        Ptr = Ptr.getBase();263      }264    } else if (Ptr.isArrayElement()) {265      Ptr = Ptr.expand();266      const Descriptor *Desc = Ptr.getFieldDesc();267      unsigned Index;268      if (Ptr.isOnePastEnd()) {269        Index = Ptr.getArray().getNumElems();270        OnePastEnd = false;271      } else272        Index = Ptr.getIndex();273 274      QualType ElemType = Desc->getElemQualType();275      if (const auto *RD = ElemType->getAsRecordDecl();276          RD && !RD->getDefinition()) {277        // Ignore this for the offset.278      } else {279        Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));280      }281      if (Ptr.getArray().getType()->isArrayType())282        Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));283      Ptr = Ptr.getArray();284    } else {285      const Descriptor *Desc = Ptr.getFieldDesc();286 287      // Create a path entry for the field.288      if (const auto *BaseOrMember = Desc->asDecl()) {289        bool IsVirtual = false;290        if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {291          Ptr = Ptr.getBase();292          Offset += getFieldOffset(FD);293        } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {294          IsVirtual = Ptr.isVirtualBaseClass();295          Ptr = Ptr.getBase();296          const Record *BaseRecord = Ptr.getRecord();297 298          const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(299              cast<CXXRecordDecl>(BaseRecord->getDecl()));300          if (IsVirtual)301            Offset += Layout.getVBaseClassOffset(RD);302          else303            Offset += Layout.getBaseClassOffset(RD);304 305        } else {306          Ptr = Ptr.getBase();307        }308        Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));309        continue;310      }311      llvm_unreachable("Invalid field type");312    }313  }314 315  // We assemble the LValuePath starting from the innermost pointer to the316  // outermost one. SO in a.b.c, the first element in Path will refer to317  // the field 'c', while later code expects it to refer to 'a'.318  // Just invert the order of the elements.319  std::reverse(Path.begin(), Path.end());320 321  if (UsePath)322    return APValue(Base, Offset, Path, OnePastEnd);323 324  return APValue(Base, Offset, APValue::NoLValuePath());325}326 327void Pointer::print(llvm::raw_ostream &OS) const {328  switch (StorageKind) {329  case Storage::Block: {330    const Block *B = BS.Pointee;331    OS << "(Block) " << B << " {";332 333    if (isRoot())334      OS << "rootptr(" << BS.Base << "), ";335    else336      OS << BS.Base << ", ";337 338    if (isElementPastEnd())339      OS << "pastend, ";340    else341      OS << Offset << ", ";342 343    if (B)344      OS << B->getSize();345    else346      OS << "nullptr";347    OS << "}";348  } break;349  case Storage::Int:350    OS << "(Int) {";351    OS << Int.Value << " + " << Offset << ", " << Int.Desc;352    OS << "}";353    break;354  case Storage::Fn:355    OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset356       << " }";357    break;358  case Storage::Typeid:359    OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "360       << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset361       << "}";362  }363}364 365size_t Pointer::computeOffsetForComparison() const {366  switch (StorageKind) {367  case Storage::Int:368    return Int.Value + Offset;369  case Storage::Block:370    // See below.371    break;372  case Storage::Fn:373    return Fn.getIntegerRepresentation() + Offset;374  case Storage::Typeid:375    return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;376  }377 378  size_t Result = 0;379  Pointer P = *this;380  while (true) {381 382    if (P.isVirtualBaseClass()) {383      Result += getInlineDesc()->Offset;384      P = P.getBase();385      continue;386    }387 388    if (P.isBaseClass()) {389      if (P.getRecord()->getNumVirtualBases() > 0)390        Result += P.getInlineDesc()->Offset;391      P = P.getBase();392      continue;393    }394    if (P.isArrayElement()) {395      P = P.expand();396      Result += (P.getIndex() * P.elemSize());397      P = P.getArray();398      continue;399    }400 401    if (P.isRoot()) {402      if (P.isOnePastEnd())403        ++Result;404      break;405    }406 407    if (const Record *R = P.getBase().getRecord(); R && R->isUnion()) {408      if (P.isOnePastEnd())409        ++Result;410      // Direct child of a union - all have offset 0.411      P = P.getBase();412      continue;413    }414 415    // Fields, etc.416    Result += P.getInlineDesc()->Offset;417    if (P.isOnePastEnd())418      ++Result;419 420    P = P.getBase();421    if (P.isRoot())422      break;423  }424 425  return Result;426}427 428std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {429  if (isZero())430    return "nullptr";431 432  if (isIntegralPointer())433    return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();434 435  if (isFunctionPointer())436    return asFunctionPointer().toDiagnosticString(Ctx);437 438  return toAPValue(Ctx).getAsString(Ctx, getType());439}440 441bool Pointer::isInitialized() const {442  if (!isBlockPointer())443    return true;444 445  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&446      Offset == BS.Base) {447    const GlobalInlineDescriptor &GD =448        *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());449    return GD.InitState == GlobalInitState::Initialized;450  }451 452  assert(BS.Pointee && "Cannot check if null pointer was initialized");453  const Descriptor *Desc = getFieldDesc();454  assert(Desc);455  if (Desc->isPrimitiveArray())456    return isElementInitialized(getIndex());457 458  if (asBlockPointer().Base == 0)459    return true;460  // Field has its bit in an inline descriptor.461  return getInlineDesc()->IsInitialized;462}463 464bool Pointer::isElementInitialized(unsigned Index) const {465  if (!isBlockPointer())466    return true;467 468  const Descriptor *Desc = getFieldDesc();469  assert(Desc);470 471  if (isStatic() && BS.Base == 0)472    return true;473 474  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&475      Offset == BS.Base) {476    const GlobalInlineDescriptor &GD =477        *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());478    return GD.InitState == GlobalInitState::Initialized;479  }480 481  if (Desc->isPrimitiveArray()) {482    InitMapPtr &IM = getInitMap();483    if (!IM)484      return false;485 486    if (IM->first)487      return true;488 489    return IM->second->isElementInitialized(Index);490  }491  return isInitialized();492}493 494void Pointer::initialize() const {495  if (!isBlockPointer())496    return;497 498  assert(BS.Pointee && "Cannot initialize null pointer");499 500  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&501      Offset == BS.Base) {502    GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(503        asBlockPointer().Pointee->rawData());504    GD.InitState = GlobalInitState::Initialized;505    return;506  }507 508  const Descriptor *Desc = getFieldDesc();509  assert(Desc);510  if (Desc->isPrimitiveArray()) {511    if (Desc->getNumElems() != 0)512      initializeElement(getIndex());513    return;514  }515 516  // Field has its bit in an inline descriptor.517  assert(BS.Base != 0 && "Only composite fields can be initialised");518  getInlineDesc()->IsInitialized = true;519}520 521void Pointer::initializeElement(unsigned Index) const {522  // Primitive global arrays don't have an initmap.523  if (isStatic() && BS.Base == 0)524    return;525 526  assert(Index < getFieldDesc()->getNumElems());527 528  InitMapPtr &IM = getInitMap();529  if (!IM) {530    const Descriptor *Desc = getFieldDesc();531    IM = std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));532  }533 534  assert(IM);535 536  // All initialized.537  if (IM->first)538    return;539 540  if (IM->second->initializeElement(Index)) {541    IM->first = true;542    IM->second.reset();543  }544}545 546void Pointer::initializeAllElements() const {547  assert(getFieldDesc()->isPrimitiveArray());548  assert(isArrayRoot());549 550  InitMapPtr &IM = getInitMap();551  if (!IM) {552    IM = std::make_pair(true, nullptr);553  } else {554    IM->first = true;555    IM->second.reset();556  }557}558 559bool Pointer::allElementsInitialized() const {560  assert(getFieldDesc()->isPrimitiveArray());561  assert(isArrayRoot());562 563  if (isStatic() && BS.Base == 0)564    return true;565 566  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&567      Offset == BS.Base) {568    const GlobalInlineDescriptor &GD =569        *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());570    return GD.InitState == GlobalInitState::Initialized;571  }572 573  InitMapPtr &IM = getInitMap();574  return IM && IM->first;575}576 577void Pointer::activate() const {578  // Field has its bit in an inline descriptor.579  assert(BS.Base != 0 && "Only composite fields can be activated");580 581  if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))582    return;583  if (!getInlineDesc()->InUnion)584    return;585 586  std::function<void(Pointer &)> activate;587  activate = [&activate](Pointer &P) -> void {588    P.getInlineDesc()->IsActive = true;589    if (const Record *R = P.getRecord(); R && !R->isUnion()) {590      for (const Record::Field &F : R->fields()) {591        Pointer FieldPtr = P.atField(F.Offset);592        if (!FieldPtr.getInlineDesc()->IsActive)593          activate(FieldPtr);594      }595      // FIXME: Bases?596    }597  };598 599  std::function<void(Pointer &)> deactivate;600  deactivate = [&deactivate](Pointer &P) -> void {601    P.getInlineDesc()->IsActive = false;602 603    if (const Record *R = P.getRecord()) {604      for (const Record::Field &F : R->fields()) {605        Pointer FieldPtr = P.atField(F.Offset);606        if (FieldPtr.getInlineDesc()->IsActive)607          deactivate(FieldPtr);608      }609      // FIXME: Bases?610    }611  };612 613  Pointer B = *this;614  while (!B.isRoot() && B.inUnion()) {615    activate(B);616 617    // When walking up the pointer chain, deactivate618    // all union child pointers that aren't on our path.619    Pointer Cur = B;620    B = B.getBase();621    if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {622      for (const Record::Field &F : BR->fields()) {623        Pointer FieldPtr = B.atField(F.Offset);624        if (FieldPtr != Cur)625          deactivate(FieldPtr);626      }627    }628  }629}630 631void Pointer::deactivate() const {632  // TODO: this only appears in constructors, so nothing to deactivate.633}634 635bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {636  // Two null pointers always have the same base.637  if (A.isZero() && B.isZero())638    return true;639 640  if (A.isIntegralPointer() && B.isIntegralPointer())641    return true;642  if (A.isFunctionPointer() && B.isFunctionPointer())643    return true;644  if (A.isTypeidPointer() && B.isTypeidPointer())645    return true;646 647  if (A.StorageKind != B.StorageKind)648    return false;649 650  return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;651}652 653bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {654  if (!A.isBlockPointer() || !B.isBlockPointer())655    return false;656  return A.block() == B.block();657}658 659bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {660  return hasSameBase(A, B) && A.BS.Base == B.BS.Base &&661         A.getFieldDesc()->IsArray;662}663 664bool Pointer::pointsToLiteral() const {665  if (isZero() || !isBlockPointer())666    return false;667 668  if (block()->isDynamic())669    return false;670 671  const Expr *E = block()->getDescriptor()->asExpr();672  return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);673}674 675bool Pointer::pointsToStringLiteral() const {676  if (isZero() || !isBlockPointer())677    return false;678 679  if (block()->isDynamic())680    return false;681 682  const Expr *E = block()->getDescriptor()->asExpr();683  return isa_and_nonnull<StringLiteral>(E);684}685 686std::optional<std::pair<Pointer, Pointer>>687Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {688  if (!A.isBlockPointer() || !B.isBlockPointer())689    return std::nullopt;690 691  if (A.asBlockPointer().Pointee != B.asBlockPointer().Pointee)692    return std::nullopt;693  if (A.isRoot() && B.isRoot())694    return std::nullopt;695 696  if (A == B)697    return std::make_pair(A, B);698 699  auto getBase = [](const Pointer &P) -> Pointer {700    if (P.isArrayElement())701      return P.expand().getArray();702    return P.getBase();703  };704 705  Pointer IterA = A;706  Pointer IterB = B;707  Pointer CurA = IterA;708  Pointer CurB = IterB;709  for (;;) {710    if (IterA.asBlockPointer().Base > IterB.asBlockPointer().Base) {711      CurA = IterA;712      IterA = getBase(IterA);713    } else {714      CurB = IterB;715      IterB = getBase(IterB);716    }717 718    if (IterA == IterB)719      return std::make_pair(CurA, CurB);720 721    if (IterA.isRoot() && IterB.isRoot())722      return std::nullopt;723  }724 725  llvm_unreachable("The loop above should've returned.");726}727 728std::optional<APValue> Pointer::toRValue(const Context &Ctx,729                                         QualType ResultType) const {730  const ASTContext &ASTCtx = Ctx.getASTContext();731  assert(!ResultType.isNull());732  // Method to recursively traverse composites.733  std::function<bool(QualType, const Pointer &, APValue &)> Composite;734  Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,735                                          APValue &R) {736    if (const auto *AT = Ty->getAs<AtomicType>())737      Ty = AT->getValueType();738 739    // Invalid pointers.740    if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||741        Ptr.isPastEnd())742      return false;743 744    // Primitive values.745    if (OptPrimType T = Ctx.classify(Ty)) {746      TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));747      return true;748    }749 750    if (const auto *RT = Ty->getAsCanonical<RecordType>()) {751      const auto *Record = Ptr.getRecord();752      assert(Record && "Missing record descriptor");753 754      bool Ok = true;755      if (RT->getDecl()->isUnion()) {756        const FieldDecl *ActiveField = nullptr;757        APValue Value;758        for (const auto &F : Record->fields()) {759          const Pointer &FP = Ptr.atField(F.Offset);760          QualType FieldTy = F.Decl->getType();761          if (FP.isActive()) {762            if (OptPrimType T = Ctx.classify(FieldTy)) {763              TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));764            } else {765              Ok &= Composite(FieldTy, FP, Value);766            }767            ActiveField = FP.getFieldDesc()->asFieldDecl();768            break;769          }770        }771        R = APValue(ActiveField, Value);772      } else {773        unsigned NF = Record->getNumFields();774        unsigned NB = Record->getNumBases();775        unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();776 777        R = APValue(APValue::UninitStruct(), NB, NF);778 779        for (unsigned I = 0; I < NF; ++I) {780          const Record::Field *FD = Record->getField(I);781          QualType FieldTy = FD->Decl->getType();782          const Pointer &FP = Ptr.atField(FD->Offset);783          APValue &Value = R.getStructField(I);784 785          if (OptPrimType T = Ctx.classify(FieldTy)) {786            TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));787          } else {788            Ok &= Composite(FieldTy, FP, Value);789          }790        }791 792        for (unsigned I = 0; I < NB; ++I) {793          const Record::Base *BD = Record->getBase(I);794          QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);795          const Pointer &BP = Ptr.atField(BD->Offset);796          Ok &= Composite(BaseTy, BP, R.getStructBase(I));797        }798 799        for (unsigned I = 0; I < NV; ++I) {800          const Record::Base *VD = Record->getVirtualBase(I);801          QualType VirtBaseTy =802              Ctx.getASTContext().getCanonicalTagType(VD->Decl);803          const Pointer &VP = Ptr.atField(VD->Offset);804          Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));805        }806      }807      return Ok;808    }809 810    if (Ty->isIncompleteArrayType()) {811      R = APValue(APValue::UninitArray(), 0, 0);812      return true;813    }814 815    if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {816      const size_t NumElems = Ptr.getNumElems();817      QualType ElemTy = AT->getElementType();818      R = APValue(APValue::UninitArray{}, NumElems, NumElems);819 820      bool Ok = true;821      OptPrimType ElemT = Ctx.classify(ElemTy);822      for (unsigned I = 0; I != NumElems; ++I) {823        APValue &Slot = R.getArrayInitializedElt(I);824        if (ElemT) {825          TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));826        } else {827          Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);828        }829      }830      return Ok;831    }832 833    // Complex types.834    if (const auto *CT = Ty->getAs<ComplexType>()) {835      // Can happen via C casts.836      if (!Ptr.getFieldDesc()->isPrimitiveArray())837        return false;838 839      QualType ElemTy = CT->getElementType();840      if (ElemTy->isIntegerType()) {841        OptPrimType ElemT = Ctx.classify(ElemTy);842        assert(ElemT);843        INT_TYPE_SWITCH(*ElemT, {844          auto V1 = Ptr.elem<T>(0);845          auto V2 = Ptr.elem<T>(1);846          R = APValue(V1.toAPSInt(), V2.toAPSInt());847          return true;848        });849      } else if (ElemTy->isFloatingType()) {850        R = APValue(Ptr.elem<Floating>(0).getAPFloat(),851                    Ptr.elem<Floating>(1).getAPFloat());852        return true;853      }854      return false;855    }856 857    // Vector types.858    if (const auto *VT = Ty->getAs<VectorType>()) {859      assert(Ptr.getFieldDesc()->isPrimitiveArray());860      QualType ElemTy = VT->getElementType();861      PrimType ElemT = *Ctx.classify(ElemTy);862 863      SmallVector<APValue> Values;864      Values.reserve(VT->getNumElements());865      for (unsigned I = 0; I != VT->getNumElements(); ++I) {866        TYPE_SWITCH(ElemT,867                    { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });868      }869 870      assert(Values.size() == VT->getNumElements());871      R = APValue(Values.data(), Values.size());872      return true;873    }874 875    llvm_unreachable("invalid value to return");876  };877 878  // Invalid to read from.879  if (isDummy() || !isLive() || isPastEnd())880    return std::nullopt;881 882  // We can return these as rvalues, but we can't deref() them.883  if (isZero() || isIntegralPointer())884    return toAPValue(ASTCtx);885 886  // Just load primitive types.887  if (OptPrimType T = Ctx.classify(ResultType)) {888    TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));889  }890 891  // Return the composite type.892  APValue Result;893  if (!Composite(ResultType, *this, Result))894    return std::nullopt;895  return Result;896}897 898std::optional<IntPointer> IntPointer::atOffset(const ASTContext &ASTCtx,899                                               unsigned Offset) const {900  if (!this->Desc)901    return *this;902  const Record *R = this->Desc->ElemRecord;903  if (!R)904    return *this;905 906  const Record::Field *F = nullptr;907  for (auto &It : R->fields()) {908    if (It.Offset == Offset) {909      F = &It;910      break;911    }912  }913  if (!F)914    return *this;915 916  const FieldDecl *FD = F->Decl;917  if (FD->getParent()->isInvalidDecl())918    return std::nullopt;919 920  const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());921  unsigned FieldIndex = FD->getFieldIndex();922  uint64_t FieldOffset =923      ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))924          .getQuantity();925  return IntPointer{F->Desc, this->Value + FieldOffset};926}927 928IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,929                                unsigned BaseOffset) const {930  if (!Desc) {931    assert(Value == 0);932    return *this;933  }934  const Record *R = Desc->ElemRecord;935  const Descriptor *BaseDesc = nullptr;936 937  // This iterates over bases and checks for the proper offset. That's938  // potentially slow but this case really shouldn't happen a lot.939  for (const Record::Base &B : R->bases()) {940    if (B.Offset == BaseOffset) {941      BaseDesc = B.Desc;942      break;943    }944  }945  assert(BaseDesc);946 947  // Adjust the offset value based on the information from the record layout.948  const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());949  CharUnits BaseLayoutOffset =950      Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));951 952  return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};953}954