1a7dea167SDimitry Andric //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "Pointer.h" 105f757f3fSDimitry Andric #include "Boolean.h" 115f757f3fSDimitry Andric #include "Context.h" 125f757f3fSDimitry Andric #include "Floating.h" 13a7dea167SDimitry Andric #include "Function.h" 145f757f3fSDimitry Andric #include "Integral.h" 155ffd83dbSDimitry Andric #include "InterpBlock.h" 16*0fca6ea1SDimitry Andric #include "MemberPointer.h" 17a7dea167SDimitry Andric #include "PrimType.h" 185f757f3fSDimitry Andric #include "Record.h" 19*0fca6ea1SDimitry Andric #include "clang/AST/RecordLayout.h" 20a7dea167SDimitry Andric 21a7dea167SDimitry Andric using namespace clang; 22a7dea167SDimitry Andric using namespace clang::interp; 23a7dea167SDimitry Andric 24*0fca6ea1SDimitry Andric Pointer::Pointer(Block *Pointee) 25*0fca6ea1SDimitry Andric : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(), 26*0fca6ea1SDimitry Andric Pointee->getDescriptor()->getMetadataSize()) {} 27a7dea167SDimitry Andric 28*0fca6ea1SDimitry Andric Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset) 29bdd1243dSDimitry Andric : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} 30bdd1243dSDimitry Andric 31*0fca6ea1SDimitry Andric Pointer::Pointer(const Pointer &P) 32*0fca6ea1SDimitry Andric : Offset(P.Offset), PointeeStorage(P.PointeeStorage), 33*0fca6ea1SDimitry Andric StorageKind(P.StorageKind) { 34a7dea167SDimitry Andric 35*0fca6ea1SDimitry Andric if (isBlockPointer() && PointeeStorage.BS.Pointee) 36*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee->addPointer(this); 37a7dea167SDimitry Andric } 38a7dea167SDimitry Andric 39*0fca6ea1SDimitry Andric Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset) 40*0fca6ea1SDimitry Andric : Offset(Offset), StorageKind(Storage::Block) { 41a7dea167SDimitry Andric assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric PointeeStorage.BS = {Pointee, Base}; 44*0fca6ea1SDimitry Andric 45a7dea167SDimitry Andric if (Pointee) 46a7dea167SDimitry Andric Pointee->addPointer(this); 47a7dea167SDimitry Andric } 48a7dea167SDimitry Andric 49*0fca6ea1SDimitry Andric Pointer::Pointer(Pointer &&P) 50*0fca6ea1SDimitry Andric : Offset(P.Offset), PointeeStorage(P.PointeeStorage), 51*0fca6ea1SDimitry Andric StorageKind(P.StorageKind) { 52*0fca6ea1SDimitry Andric 53*0fca6ea1SDimitry Andric if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) 54*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee->replacePointer(&P, this); 55*0fca6ea1SDimitry Andric } 56*0fca6ea1SDimitry Andric 57a7dea167SDimitry Andric Pointer::~Pointer() { 58*0fca6ea1SDimitry Andric if (isIntegralPointer()) 59*0fca6ea1SDimitry Andric return; 60*0fca6ea1SDimitry Andric 61*0fca6ea1SDimitry Andric if (Block *Pointee = PointeeStorage.BS.Pointee) { 62a7dea167SDimitry Andric Pointee->removePointer(this); 63a7dea167SDimitry Andric Pointee->cleanup(); 64a7dea167SDimitry Andric } 65a7dea167SDimitry Andric } 66a7dea167SDimitry Andric 67a7dea167SDimitry Andric void Pointer::operator=(const Pointer &P) { 68*0fca6ea1SDimitry Andric // If the current storage type is Block, we need to remove 69*0fca6ea1SDimitry Andric // this pointer from the block. 70*0fca6ea1SDimitry Andric bool WasBlockPointer = isBlockPointer(); 71*0fca6ea1SDimitry Andric if (StorageKind == Storage::Block) { 72*0fca6ea1SDimitry Andric Block *Old = PointeeStorage.BS.Pointee; 73*0fca6ea1SDimitry Andric if (WasBlockPointer && Old) { 74*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee->removePointer(this); 75a7dea167SDimitry Andric Old->cleanup(); 76a7dea167SDimitry Andric } 77*0fca6ea1SDimitry Andric } 78*0fca6ea1SDimitry Andric 79*0fca6ea1SDimitry Andric StorageKind = P.StorageKind; 80*0fca6ea1SDimitry Andric Offset = P.Offset; 81*0fca6ea1SDimitry Andric 82*0fca6ea1SDimitry Andric if (P.isBlockPointer()) { 83*0fca6ea1SDimitry Andric PointeeStorage.BS = P.PointeeStorage.BS; 84*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee; 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric if (PointeeStorage.BS.Pointee) 87*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee->addPointer(this); 88*0fca6ea1SDimitry Andric } else if (P.isIntegralPointer()) { 89*0fca6ea1SDimitry Andric PointeeStorage.Int = P.PointeeStorage.Int; 90*0fca6ea1SDimitry Andric } else { 91*0fca6ea1SDimitry Andric assert(false && "Unhandled storage kind"); 92*0fca6ea1SDimitry Andric } 93*0fca6ea1SDimitry Andric } 94a7dea167SDimitry Andric 95a7dea167SDimitry Andric void Pointer::operator=(Pointer &&P) { 96*0fca6ea1SDimitry Andric // If the current storage type is Block, we need to remove 97*0fca6ea1SDimitry Andric // this pointer from the block. 98*0fca6ea1SDimitry Andric bool WasBlockPointer = isBlockPointer(); 99*0fca6ea1SDimitry Andric if (StorageKind == Storage::Block) { 100*0fca6ea1SDimitry Andric Block *Old = PointeeStorage.BS.Pointee; 101*0fca6ea1SDimitry Andric if (WasBlockPointer && Old) { 102*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee->removePointer(this); 103a7dea167SDimitry Andric Old->cleanup(); 104a7dea167SDimitry Andric } 105*0fca6ea1SDimitry Andric } 106a7dea167SDimitry Andric 107*0fca6ea1SDimitry Andric StorageKind = P.StorageKind; 108*0fca6ea1SDimitry Andric Offset = P.Offset; 109a7dea167SDimitry Andric 110*0fca6ea1SDimitry Andric if (P.isBlockPointer()) { 111*0fca6ea1SDimitry Andric PointeeStorage.BS = P.PointeeStorage.BS; 112*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee; 113*0fca6ea1SDimitry Andric 114*0fca6ea1SDimitry Andric if (PointeeStorage.BS.Pointee) 115*0fca6ea1SDimitry Andric PointeeStorage.BS.Pointee->addPointer(this); 116*0fca6ea1SDimitry Andric } else if (P.isIntegralPointer()) { 117*0fca6ea1SDimitry Andric PointeeStorage.Int = P.PointeeStorage.Int; 118a7dea167SDimitry Andric } else { 119*0fca6ea1SDimitry Andric assert(false && "Unhandled storage kind"); 120*0fca6ea1SDimitry Andric } 121*0fca6ea1SDimitry Andric } 122*0fca6ea1SDimitry Andric 123*0fca6ea1SDimitry Andric APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { 124*0fca6ea1SDimitry Andric llvm::SmallVector<APValue::LValuePathEntry, 5> Path; 125*0fca6ea1SDimitry Andric 126*0fca6ea1SDimitry Andric if (isZero()) 127*0fca6ea1SDimitry Andric return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path, 128*0fca6ea1SDimitry Andric /*IsOnePastEnd=*/false, /*IsNullPtr=*/true); 129*0fca6ea1SDimitry Andric if (isIntegralPointer()) 130*0fca6ea1SDimitry Andric return APValue(static_cast<const Expr *>(nullptr), 131*0fca6ea1SDimitry Andric CharUnits::fromQuantity(asIntPointer().Value + this->Offset), 132*0fca6ea1SDimitry Andric Path, 133*0fca6ea1SDimitry Andric /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); 134*0fca6ea1SDimitry Andric 135a7dea167SDimitry Andric // Build the lvalue base from the block. 1365f757f3fSDimitry Andric const Descriptor *Desc = getDeclDesc(); 137*0fca6ea1SDimitry Andric APValue::LValueBase Base; 138*0fca6ea1SDimitry Andric if (const auto *VD = Desc->asValueDecl()) 139a7dea167SDimitry Andric Base = VD; 140*0fca6ea1SDimitry Andric else if (const auto *E = Desc->asExpr()) 141a7dea167SDimitry Andric Base = E; 142a7dea167SDimitry Andric else 143a7dea167SDimitry Andric llvm_unreachable("Invalid allocation type"); 144a7dea167SDimitry Andric 145*0fca6ea1SDimitry Andric if (isUnknownSizeArray() || Desc->asExpr()) 146*0fca6ea1SDimitry Andric return APValue(Base, CharUnits::Zero(), Path, 147*0fca6ea1SDimitry Andric /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false); 148a7dea167SDimitry Andric 149*0fca6ea1SDimitry Andric CharUnits Offset = CharUnits::Zero(); 150*0fca6ea1SDimitry Andric 151*0fca6ea1SDimitry Andric auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits { 152*0fca6ea1SDimitry Andric // This shouldn't happen, but if it does, don't crash inside 153*0fca6ea1SDimitry Andric // getASTRecordLayout. 154*0fca6ea1SDimitry Andric if (FD->getParent()->isInvalidDecl()) 155*0fca6ea1SDimitry Andric return CharUnits::Zero(); 156*0fca6ea1SDimitry Andric const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent()); 157*0fca6ea1SDimitry Andric unsigned FieldIndex = FD->getFieldIndex(); 158*0fca6ea1SDimitry Andric return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)); 159*0fca6ea1SDimitry Andric }; 160a7dea167SDimitry Andric 161a7dea167SDimitry Andric // Build the path into the object. 162a7dea167SDimitry Andric Pointer Ptr = *this; 163bdd1243dSDimitry Andric while (Ptr.isField() || Ptr.isArrayElement()) { 164*0fca6ea1SDimitry Andric if (Ptr.isArrayRoot()) { 165*0fca6ea1SDimitry Andric Path.push_back(APValue::LValuePathEntry( 166*0fca6ea1SDimitry Andric {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false})); 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(Ptr.getFieldDesc()->asDecl())) 169*0fca6ea1SDimitry Andric Offset += getFieldOffset(FD); 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric Ptr = Ptr.getBase(); 172*0fca6ea1SDimitry Andric } else if (Ptr.isArrayElement()) { 173*0fca6ea1SDimitry Andric unsigned Index; 174*0fca6ea1SDimitry Andric if (Ptr.isOnePastEnd()) 175*0fca6ea1SDimitry Andric Index = Ptr.getArray().getNumElems(); 176*0fca6ea1SDimitry Andric else 177*0fca6ea1SDimitry Andric Index = Ptr.getIndex(); 178*0fca6ea1SDimitry Andric 179*0fca6ea1SDimitry Andric Offset += (Index * ASTCtx.getTypeSizeInChars(Ptr.getType())); 180*0fca6ea1SDimitry Andric Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index)); 181a7dea167SDimitry Andric Ptr = Ptr.getArray(); 182a7dea167SDimitry Andric } else { 183a7dea167SDimitry Andric bool IsVirtual = false; 184a7dea167SDimitry Andric 185a7dea167SDimitry Andric // Create a path entry for the field. 1865f757f3fSDimitry Andric const Descriptor *Desc = Ptr.getFieldDesc(); 1875f757f3fSDimitry Andric if (const auto *BaseOrMember = Desc->asDecl()) { 188*0fca6ea1SDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) { 189a7dea167SDimitry Andric Ptr = Ptr.getBase(); 190*0fca6ea1SDimitry Andric Offset += getFieldOffset(FD); 191*0fca6ea1SDimitry Andric } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { 192*0fca6ea1SDimitry Andric IsVirtual = Ptr.isVirtualBaseClass(); 193*0fca6ea1SDimitry Andric Ptr = Ptr.getBase(); 194*0fca6ea1SDimitry Andric const Record *BaseRecord = Ptr.getRecord(); 195*0fca6ea1SDimitry Andric 196*0fca6ea1SDimitry Andric const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout( 197*0fca6ea1SDimitry Andric cast<CXXRecordDecl>(BaseRecord->getDecl())); 198*0fca6ea1SDimitry Andric if (IsVirtual) 199*0fca6ea1SDimitry Andric Offset += Layout.getVBaseClassOffset(RD); 200*0fca6ea1SDimitry Andric else 201*0fca6ea1SDimitry Andric Offset += Layout.getBaseClassOffset(RD); 202*0fca6ea1SDimitry Andric 203*0fca6ea1SDimitry Andric } else { 204*0fca6ea1SDimitry Andric Ptr = Ptr.getBase(); 205*0fca6ea1SDimitry Andric } 206*0fca6ea1SDimitry Andric Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); 207a7dea167SDimitry Andric continue; 208a7dea167SDimitry Andric } 209a7dea167SDimitry Andric llvm_unreachable("Invalid field type"); 210a7dea167SDimitry Andric } 211a7dea167SDimitry Andric } 212a7dea167SDimitry Andric 213*0fca6ea1SDimitry Andric // FIXME(perf): We compute the lvalue path above, but we can't supply it 214*0fca6ea1SDimitry Andric // for dummy pointers (that causes crashes later in CheckConstantExpression). 215*0fca6ea1SDimitry Andric if (isDummy()) 216*0fca6ea1SDimitry Andric Path.clear(); 217a7dea167SDimitry Andric 218bdd1243dSDimitry Andric // We assemble the LValuePath starting from the innermost pointer to the 219bdd1243dSDimitry Andric // outermost one. SO in a.b.c, the first element in Path will refer to 220bdd1243dSDimitry Andric // the field 'c', while later code expects it to refer to 'a'. 221bdd1243dSDimitry Andric // Just invert the order of the elements. 222bdd1243dSDimitry Andric std::reverse(Path.begin(), Path.end()); 223bdd1243dSDimitry Andric 224*0fca6ea1SDimitry Andric return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(), 225*0fca6ea1SDimitry Andric /*IsNullPtr=*/false); 226*0fca6ea1SDimitry Andric } 227*0fca6ea1SDimitry Andric 228*0fca6ea1SDimitry Andric void Pointer::print(llvm::raw_ostream &OS) const { 229*0fca6ea1SDimitry Andric OS << PointeeStorage.BS.Pointee << " ("; 230*0fca6ea1SDimitry Andric if (isBlockPointer()) { 231*0fca6ea1SDimitry Andric const Block *B = PointeeStorage.BS.Pointee; 232*0fca6ea1SDimitry Andric OS << "Block) {"; 233*0fca6ea1SDimitry Andric 234*0fca6ea1SDimitry Andric if (isRoot()) 235*0fca6ea1SDimitry Andric OS << "rootptr(" << PointeeStorage.BS.Base << "), "; 236*0fca6ea1SDimitry Andric else 237*0fca6ea1SDimitry Andric OS << PointeeStorage.BS.Base << ", "; 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric if (isElementPastEnd()) 240*0fca6ea1SDimitry Andric OS << "pastend, "; 241*0fca6ea1SDimitry Andric else 242*0fca6ea1SDimitry Andric OS << Offset << ", "; 243*0fca6ea1SDimitry Andric 244*0fca6ea1SDimitry Andric if (B) 245*0fca6ea1SDimitry Andric OS << B->getSize(); 246*0fca6ea1SDimitry Andric else 247*0fca6ea1SDimitry Andric OS << "nullptr"; 248*0fca6ea1SDimitry Andric } else { 249*0fca6ea1SDimitry Andric OS << "Int) {"; 250*0fca6ea1SDimitry Andric OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc; 251*0fca6ea1SDimitry Andric } 252*0fca6ea1SDimitry Andric OS << "}"; 253a7dea167SDimitry Andric } 254a7dea167SDimitry Andric 2555f757f3fSDimitry Andric std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const { 256*0fca6ea1SDimitry Andric if (isZero()) 2575f757f3fSDimitry Andric return "nullptr"; 2585f757f3fSDimitry Andric 259*0fca6ea1SDimitry Andric if (isIntegralPointer()) 260*0fca6ea1SDimitry Andric return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str(); 261*0fca6ea1SDimitry Andric 262*0fca6ea1SDimitry Andric return toAPValue(Ctx).getAsString(Ctx, getType()); 2635f757f3fSDimitry Andric } 2645f757f3fSDimitry Andric 265a7dea167SDimitry Andric bool Pointer::isInitialized() const { 266*0fca6ea1SDimitry Andric if (isIntegralPointer()) 267*0fca6ea1SDimitry Andric return true; 268*0fca6ea1SDimitry Andric 269*0fca6ea1SDimitry Andric if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { 270*0fca6ea1SDimitry Andric const GlobalInlineDescriptor &GD = 271*0fca6ea1SDimitry Andric *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); 272*0fca6ea1SDimitry Andric return GD.InitState == GlobalInitState::Initialized; 273*0fca6ea1SDimitry Andric } 274*0fca6ea1SDimitry Andric 275*0fca6ea1SDimitry Andric assert(PointeeStorage.BS.Pointee && 276*0fca6ea1SDimitry Andric "Cannot check if null pointer was initialized"); 27706c3fb27SDimitry Andric const Descriptor *Desc = getFieldDesc(); 278bdd1243dSDimitry Andric assert(Desc); 279a7dea167SDimitry Andric if (Desc->isPrimitiveArray()) { 280*0fca6ea1SDimitry Andric if (isStatic() && PointeeStorage.BS.Base == 0) 281a7dea167SDimitry Andric return true; 2825f757f3fSDimitry Andric 2835f757f3fSDimitry Andric InitMapPtr &IM = getInitMap(); 2845f757f3fSDimitry Andric 2855f757f3fSDimitry Andric if (!IM) 286a7dea167SDimitry Andric return false; 2875f757f3fSDimitry Andric 2885f757f3fSDimitry Andric if (IM->first) 289a7dea167SDimitry Andric return true; 2905f757f3fSDimitry Andric 2915f757f3fSDimitry Andric return IM->second->isElementInitialized(getIndex()); 29206c3fb27SDimitry Andric } 29306c3fb27SDimitry Andric 294*0fca6ea1SDimitry Andric if (asBlockPointer().Base == 0) 295*0fca6ea1SDimitry Andric return true; 296*0fca6ea1SDimitry Andric 297a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 298*0fca6ea1SDimitry Andric return getInlineDesc()->IsInitialized; 299a7dea167SDimitry Andric } 300a7dea167SDimitry Andric 301a7dea167SDimitry Andric void Pointer::initialize() const { 302*0fca6ea1SDimitry Andric if (isIntegralPointer()) 303*0fca6ea1SDimitry Andric return; 304*0fca6ea1SDimitry Andric 305*0fca6ea1SDimitry Andric assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer"); 30606c3fb27SDimitry Andric const Descriptor *Desc = getFieldDesc(); 307bdd1243dSDimitry Andric 308*0fca6ea1SDimitry Andric if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { 309*0fca6ea1SDimitry Andric GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>( 310*0fca6ea1SDimitry Andric asBlockPointer().Pointee->rawData()); 311*0fca6ea1SDimitry Andric GD.InitState = GlobalInitState::Initialized; 312*0fca6ea1SDimitry Andric return; 313*0fca6ea1SDimitry Andric } 314*0fca6ea1SDimitry Andric 315bdd1243dSDimitry Andric assert(Desc); 316a7dea167SDimitry Andric if (Desc->isPrimitiveArray()) { 317bdd1243dSDimitry Andric // Primitive global arrays don't have an initmap. 318*0fca6ea1SDimitry Andric if (isStatic() && PointeeStorage.BS.Base == 0) 319*0fca6ea1SDimitry Andric return; 320*0fca6ea1SDimitry Andric 321*0fca6ea1SDimitry Andric // Nothing to do for these. 322*0fca6ea1SDimitry Andric if (Desc->getNumElems() == 0) 323bdd1243dSDimitry Andric return; 324bdd1243dSDimitry Andric 3255f757f3fSDimitry Andric InitMapPtr &IM = getInitMap(); 3265f757f3fSDimitry Andric if (!IM) 3275f757f3fSDimitry Andric IM = 3285f757f3fSDimitry Andric std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems())); 3295f757f3fSDimitry Andric 3305f757f3fSDimitry Andric assert(IM); 3315f757f3fSDimitry Andric 3325f757f3fSDimitry Andric // All initialized. 3335f757f3fSDimitry Andric if (IM->first) 334a7dea167SDimitry Andric return; 3355f757f3fSDimitry Andric 3365f757f3fSDimitry Andric if (IM->second->initializeElement(getIndex())) { 3375f757f3fSDimitry Andric IM->first = true; 3385f757f3fSDimitry Andric IM->second.reset(); 339a7dea167SDimitry Andric } 34006c3fb27SDimitry Andric return; 341a7dea167SDimitry Andric } 34206c3fb27SDimitry Andric 343a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 344*0fca6ea1SDimitry Andric assert(PointeeStorage.BS.Base != 0 && 345*0fca6ea1SDimitry Andric "Only composite fields can be initialised"); 346a7dea167SDimitry Andric getInlineDesc()->IsInitialized = true; 347a7dea167SDimitry Andric } 348a7dea167SDimitry Andric 349a7dea167SDimitry Andric void Pointer::activate() const { 350a7dea167SDimitry Andric // Field has its bit in an inline descriptor. 351*0fca6ea1SDimitry Andric assert(PointeeStorage.BS.Base != 0 && 352*0fca6ea1SDimitry Andric "Only composite fields can be initialised"); 353*0fca6ea1SDimitry Andric 354*0fca6ea1SDimitry Andric if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) 355*0fca6ea1SDimitry Andric return; 356*0fca6ea1SDimitry Andric 357a7dea167SDimitry Andric getInlineDesc()->IsActive = true; 358a7dea167SDimitry Andric } 359a7dea167SDimitry Andric 360a7dea167SDimitry Andric void Pointer::deactivate() const { 361a7dea167SDimitry Andric // TODO: this only appears in constructors, so nothing to deactivate. 362a7dea167SDimitry Andric } 363a7dea167SDimitry Andric 364a7dea167SDimitry Andric bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { 365*0fca6ea1SDimitry Andric // Two null pointers always have the same base. 366*0fca6ea1SDimitry Andric if (A.isZero() && B.isZero()) 367*0fca6ea1SDimitry Andric return true; 368*0fca6ea1SDimitry Andric 369*0fca6ea1SDimitry Andric if (A.isIntegralPointer() && B.isIntegralPointer()) 370*0fca6ea1SDimitry Andric return true; 371*0fca6ea1SDimitry Andric 372*0fca6ea1SDimitry Andric if (A.isIntegralPointer() || B.isIntegralPointer()) 373*0fca6ea1SDimitry Andric return A.getSource() == B.getSource(); 374*0fca6ea1SDimitry Andric 375*0fca6ea1SDimitry Andric return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee; 376a7dea167SDimitry Andric } 377a7dea167SDimitry Andric 378a7dea167SDimitry Andric bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { 379*0fca6ea1SDimitry Andric return hasSameBase(A, B) && 380*0fca6ea1SDimitry Andric A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base && 381*0fca6ea1SDimitry Andric A.getFieldDesc()->IsArray; 382a7dea167SDimitry Andric } 3835f757f3fSDimitry Andric 384*0fca6ea1SDimitry Andric std::optional<APValue> Pointer::toRValue(const Context &Ctx, 385*0fca6ea1SDimitry Andric QualType ResultType) const { 386*0fca6ea1SDimitry Andric const ASTContext &ASTCtx = Ctx.getASTContext(); 387*0fca6ea1SDimitry Andric assert(!ResultType.isNull()); 3887a6dacacSDimitry Andric // Method to recursively traverse composites. 3897a6dacacSDimitry Andric std::function<bool(QualType, const Pointer &, APValue &)> Composite; 390*0fca6ea1SDimitry Andric Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr, 391*0fca6ea1SDimitry Andric APValue &R) { 3927a6dacacSDimitry Andric if (const auto *AT = Ty->getAs<AtomicType>()) 3937a6dacacSDimitry Andric Ty = AT->getValueType(); 3947a6dacacSDimitry Andric 3957a6dacacSDimitry Andric // Invalid pointers. 396*0fca6ea1SDimitry Andric if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() || 397*0fca6ea1SDimitry Andric Ptr.isPastEnd()) 3987a6dacacSDimitry Andric return false; 3997a6dacacSDimitry Andric 4007a6dacacSDimitry Andric // Primitive values. 4017a6dacacSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(Ty)) { 402*0fca6ea1SDimitry Andric TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx)); 4037a6dacacSDimitry Andric return true; 4045f757f3fSDimitry Andric } 4055f757f3fSDimitry Andric 4067a6dacacSDimitry Andric if (const auto *RT = Ty->getAs<RecordType>()) { 4077a6dacacSDimitry Andric const auto *Record = Ptr.getRecord(); 4087a6dacacSDimitry Andric assert(Record && "Missing record descriptor"); 4097a6dacacSDimitry Andric 4107a6dacacSDimitry Andric bool Ok = true; 4117a6dacacSDimitry Andric if (RT->getDecl()->isUnion()) { 4127a6dacacSDimitry Andric const FieldDecl *ActiveField = nullptr; 4137a6dacacSDimitry Andric APValue Value; 4147a6dacacSDimitry Andric for (const auto &F : Record->fields()) { 4157a6dacacSDimitry Andric const Pointer &FP = Ptr.atField(F.Offset); 4167a6dacacSDimitry Andric QualType FieldTy = F.Decl->getType(); 4177a6dacacSDimitry Andric if (FP.isActive()) { 4187a6dacacSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { 419*0fca6ea1SDimitry Andric TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); 4207a6dacacSDimitry Andric } else { 4217a6dacacSDimitry Andric Ok &= Composite(FieldTy, FP, Value); 4227a6dacacSDimitry Andric } 423*0fca6ea1SDimitry Andric ActiveField = FP.getFieldDesc()->asFieldDecl(); 4247a6dacacSDimitry Andric break; 4257a6dacacSDimitry Andric } 4267a6dacacSDimitry Andric } 4277a6dacacSDimitry Andric R = APValue(ActiveField, Value); 4287a6dacacSDimitry Andric } else { 4297a6dacacSDimitry Andric unsigned NF = Record->getNumFields(); 4307a6dacacSDimitry Andric unsigned NB = Record->getNumBases(); 4317a6dacacSDimitry Andric unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases(); 4327a6dacacSDimitry Andric 4337a6dacacSDimitry Andric R = APValue(APValue::UninitStruct(), NB, NF); 4347a6dacacSDimitry Andric 4357a6dacacSDimitry Andric for (unsigned I = 0; I < NF; ++I) { 4367a6dacacSDimitry Andric const Record::Field *FD = Record->getField(I); 4377a6dacacSDimitry Andric QualType FieldTy = FD->Decl->getType(); 4387a6dacacSDimitry Andric const Pointer &FP = Ptr.atField(FD->Offset); 4397a6dacacSDimitry Andric APValue &Value = R.getStructField(I); 4407a6dacacSDimitry Andric 4417a6dacacSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { 442*0fca6ea1SDimitry Andric TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); 4437a6dacacSDimitry Andric } else { 4447a6dacacSDimitry Andric Ok &= Composite(FieldTy, FP, Value); 4457a6dacacSDimitry Andric } 4467a6dacacSDimitry Andric } 4477a6dacacSDimitry Andric 4487a6dacacSDimitry Andric for (unsigned I = 0; I < NB; ++I) { 4497a6dacacSDimitry Andric const Record::Base *BD = Record->getBase(I); 4507a6dacacSDimitry Andric QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl); 4517a6dacacSDimitry Andric const Pointer &BP = Ptr.atField(BD->Offset); 4527a6dacacSDimitry Andric Ok &= Composite(BaseTy, BP, R.getStructBase(I)); 4537a6dacacSDimitry Andric } 4547a6dacacSDimitry Andric 4557a6dacacSDimitry Andric for (unsigned I = 0; I < NV; ++I) { 4567a6dacacSDimitry Andric const Record::Base *VD = Record->getVirtualBase(I); 4577a6dacacSDimitry Andric QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl); 4587a6dacacSDimitry Andric const Pointer &VP = Ptr.atField(VD->Offset); 4597a6dacacSDimitry Andric Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I)); 4607a6dacacSDimitry Andric } 4617a6dacacSDimitry Andric } 4627a6dacacSDimitry Andric return Ok; 4637a6dacacSDimitry Andric } 4647a6dacacSDimitry Andric 4657a6dacacSDimitry Andric if (Ty->isIncompleteArrayType()) { 4667a6dacacSDimitry Andric R = APValue(APValue::UninitArray(), 0, 0); 4677a6dacacSDimitry Andric return true; 4687a6dacacSDimitry Andric } 4697a6dacacSDimitry Andric 4707a6dacacSDimitry Andric if (const auto *AT = Ty->getAsArrayTypeUnsafe()) { 4717a6dacacSDimitry Andric const size_t NumElems = Ptr.getNumElems(); 4727a6dacacSDimitry Andric QualType ElemTy = AT->getElementType(); 4737a6dacacSDimitry Andric R = APValue(APValue::UninitArray{}, NumElems, NumElems); 4747a6dacacSDimitry Andric 4757a6dacacSDimitry Andric bool Ok = true; 4767a6dacacSDimitry Andric for (unsigned I = 0; I < NumElems; ++I) { 4777a6dacacSDimitry Andric APValue &Slot = R.getArrayInitializedElt(I); 4787a6dacacSDimitry Andric const Pointer &EP = Ptr.atIndex(I); 4797a6dacacSDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 480*0fca6ea1SDimitry Andric TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx)); 4817a6dacacSDimitry Andric } else { 4827a6dacacSDimitry Andric Ok &= Composite(ElemTy, EP.narrow(), Slot); 4837a6dacacSDimitry Andric } 4847a6dacacSDimitry Andric } 4857a6dacacSDimitry Andric return Ok; 4867a6dacacSDimitry Andric } 4877a6dacacSDimitry Andric 4887a6dacacSDimitry Andric // Complex types. 4897a6dacacSDimitry Andric if (const auto *CT = Ty->getAs<ComplexType>()) { 4907a6dacacSDimitry Andric QualType ElemTy = CT->getElementType(); 4917a6dacacSDimitry Andric 4927a6dacacSDimitry Andric if (ElemTy->isIntegerType()) { 493*0fca6ea1SDimitry Andric std::optional<PrimType> ElemT = Ctx.classify(ElemTy); 494*0fca6ea1SDimitry Andric assert(ElemT); 4957a6dacacSDimitry Andric INT_TYPE_SWITCH(*ElemT, { 4967a6dacacSDimitry Andric auto V1 = Ptr.atIndex(0).deref<T>(); 4977a6dacacSDimitry Andric auto V2 = Ptr.atIndex(1).deref<T>(); 4987a6dacacSDimitry Andric R = APValue(V1.toAPSInt(), V2.toAPSInt()); 4997a6dacacSDimitry Andric return true; 5007a6dacacSDimitry Andric }); 5017a6dacacSDimitry Andric } else if (ElemTy->isFloatingType()) { 5027a6dacacSDimitry Andric R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(), 5037a6dacacSDimitry Andric Ptr.atIndex(1).deref<Floating>().getAPFloat()); 5047a6dacacSDimitry Andric return true; 5057a6dacacSDimitry Andric } 5067a6dacacSDimitry Andric return false; 5077a6dacacSDimitry Andric } 5087a6dacacSDimitry Andric 509*0fca6ea1SDimitry Andric // Vector types. 510*0fca6ea1SDimitry Andric if (const auto *VT = Ty->getAs<VectorType>()) { 511*0fca6ea1SDimitry Andric assert(Ptr.getFieldDesc()->isPrimitiveArray()); 512*0fca6ea1SDimitry Andric QualType ElemTy = VT->getElementType(); 513*0fca6ea1SDimitry Andric PrimType ElemT = *Ctx.classify(ElemTy); 514*0fca6ea1SDimitry Andric 515*0fca6ea1SDimitry Andric SmallVector<APValue> Values; 516*0fca6ea1SDimitry Andric Values.reserve(VT->getNumElements()); 517*0fca6ea1SDimitry Andric for (unsigned I = 0; I != VT->getNumElements(); ++I) { 518*0fca6ea1SDimitry Andric TYPE_SWITCH(ElemT, { 519*0fca6ea1SDimitry Andric Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx)); 520*0fca6ea1SDimitry Andric }); 521*0fca6ea1SDimitry Andric } 522*0fca6ea1SDimitry Andric 523*0fca6ea1SDimitry Andric assert(Values.size() == VT->getNumElements()); 524*0fca6ea1SDimitry Andric R = APValue(Values.data(), Values.size()); 525*0fca6ea1SDimitry Andric return true; 526*0fca6ea1SDimitry Andric } 527*0fca6ea1SDimitry Andric 5287a6dacacSDimitry Andric llvm_unreachable("invalid value to return"); 5297a6dacacSDimitry Andric }; 5307a6dacacSDimitry Andric 531*0fca6ea1SDimitry Andric // Invalid to read from. 532*0fca6ea1SDimitry Andric if (isDummy() || !isLive() || isPastEnd()) 5337a6dacacSDimitry Andric return std::nullopt; 5347a6dacacSDimitry Andric 535*0fca6ea1SDimitry Andric // We can return these as rvalues, but we can't deref() them. 536*0fca6ea1SDimitry Andric if (isZero() || isIntegralPointer()) 537*0fca6ea1SDimitry Andric return toAPValue(ASTCtx); 538*0fca6ea1SDimitry Andric 539*0fca6ea1SDimitry Andric // Just load primitive types. 540*0fca6ea1SDimitry Andric if (std::optional<PrimType> T = Ctx.classify(ResultType)) { 541*0fca6ea1SDimitry Andric TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx)); 542*0fca6ea1SDimitry Andric } 543*0fca6ea1SDimitry Andric 5447a6dacacSDimitry Andric // Return the composite type. 5455f757f3fSDimitry Andric APValue Result; 5467a6dacacSDimitry Andric if (!Composite(getType(), *this, Result)) 5477a6dacacSDimitry Andric return std::nullopt; 5485f757f3fSDimitry Andric return Result; 5495f757f3fSDimitry Andric } 550