1a07aba5dSTimm Baeder //===--- Pointer.cpp - Types for the constexpr VM ---------------*- C++ -*-===// 2a07aba5dSTimm Baeder // 3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a07aba5dSTimm Baeder // 7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 8a07aba5dSTimm Baeder 9a07aba5dSTimm Baeder #include "Pointer.h" 10a07aba5dSTimm Baeder #include "Boolean.h" 11a07aba5dSTimm Baeder #include "Context.h" 12a07aba5dSTimm Baeder #include "Floating.h" 13a07aba5dSTimm Baeder #include "Function.h" 14a07aba5dSTimm Baeder #include "Integral.h" 15a07aba5dSTimm Baeder #include "InterpBlock.h" 16a07aba5dSTimm Baeder #include "MemberPointer.h" 17a07aba5dSTimm Baeder #include "PrimType.h" 18a07aba5dSTimm Baeder #include "Record.h" 19a07aba5dSTimm Baeder #include "clang/AST/ExprCXX.h" 20a07aba5dSTimm Baeder #include "clang/AST/RecordLayout.h" 21a07aba5dSTimm Baeder 22a07aba5dSTimm Baeder using namespace clang; 23a07aba5dSTimm Baeder using namespace clang::interp; 24a07aba5dSTimm Baeder 25a07aba5dSTimm Baeder Pointer::Pointer(Block *Pointee) 26a07aba5dSTimm Baeder : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(), 27a07aba5dSTimm Baeder Pointee->getDescriptor()->getMetadataSize()) {} 28a07aba5dSTimm Baeder 29a07aba5dSTimm Baeder Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset) 30a07aba5dSTimm Baeder : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} 31a07aba5dSTimm Baeder 32a07aba5dSTimm Baeder Pointer::Pointer(const Pointer &P) 33a07aba5dSTimm Baeder : Offset(P.Offset), PointeeStorage(P.PointeeStorage), 34a07aba5dSTimm Baeder StorageKind(P.StorageKind) { 35a07aba5dSTimm Baeder 36a07aba5dSTimm Baeder if (isBlockPointer() && PointeeStorage.BS.Pointee) 37a07aba5dSTimm Baeder PointeeStorage.BS.Pointee->addPointer(this); 38a07aba5dSTimm Baeder } 39a07aba5dSTimm Baeder 40a07aba5dSTimm Baeder Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset) 41a07aba5dSTimm Baeder : Offset(Offset), StorageKind(Storage::Block) { 42a07aba5dSTimm Baeder assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); 43a07aba5dSTimm Baeder 44a07aba5dSTimm Baeder PointeeStorage.BS = {Pointee, Base}; 45a07aba5dSTimm Baeder 46a07aba5dSTimm Baeder if (Pointee) 47a07aba5dSTimm Baeder Pointee->addPointer(this); 48a07aba5dSTimm Baeder } 49a07aba5dSTimm Baeder 50a07aba5dSTimm Baeder Pointer::Pointer(Pointer &&P) 51a07aba5dSTimm Baeder : Offset(P.Offset), PointeeStorage(P.PointeeStorage), 52a07aba5dSTimm Baeder StorageKind(P.StorageKind) { 53a07aba5dSTimm Baeder 54a07aba5dSTimm Baeder if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) 55a07aba5dSTimm Baeder PointeeStorage.BS.Pointee->replacePointer(&P, this); 56a07aba5dSTimm Baeder } 57a07aba5dSTimm Baeder 58a07aba5dSTimm Baeder Pointer::~Pointer() { 59a07aba5dSTimm Baeder if (!isBlockPointer()) 60a07aba5dSTimm Baeder return; 61a07aba5dSTimm Baeder 62a07aba5dSTimm Baeder if (Block *Pointee = PointeeStorage.BS.Pointee) { 63a07aba5dSTimm Baeder Pointee->removePointer(this); 64a07aba5dSTimm Baeder PointeeStorage.BS.Pointee = nullptr; 65a07aba5dSTimm Baeder Pointee->cleanup(); 66a07aba5dSTimm Baeder } 67a07aba5dSTimm Baeder } 68a07aba5dSTimm Baeder 69a07aba5dSTimm Baeder void Pointer::operator=(const Pointer &P) { 70a07aba5dSTimm Baeder // If the current storage type is Block, we need to remove 71a07aba5dSTimm Baeder // this pointer from the block. 72a07aba5dSTimm Baeder if (isBlockPointer()) { 73a07aba5dSTimm Baeder if (P.isBlockPointer() && this->block() == P.block()) { 74a07aba5dSTimm Baeder Offset = P.Offset; 75a07aba5dSTimm Baeder PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; 76a07aba5dSTimm Baeder return; 77a07aba5dSTimm Baeder } 78a07aba5dSTimm Baeder 79a07aba5dSTimm Baeder if (Block *Pointee = PointeeStorage.BS.Pointee) { 80a07aba5dSTimm Baeder Pointee->removePointer(this); 81a07aba5dSTimm Baeder PointeeStorage.BS.Pointee = nullptr; 82a07aba5dSTimm Baeder Pointee->cleanup(); 83a07aba5dSTimm Baeder } 84a07aba5dSTimm Baeder } 85a07aba5dSTimm Baeder 86a07aba5dSTimm Baeder StorageKind = P.StorageKind; 87a07aba5dSTimm Baeder Offset = P.Offset; 88a07aba5dSTimm Baeder 89a07aba5dSTimm Baeder if (P.isBlockPointer()) { 90a07aba5dSTimm Baeder PointeeStorage.BS = P.PointeeStorage.BS; 91a07aba5dSTimm Baeder PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee; 92a07aba5dSTimm Baeder 93a07aba5dSTimm Baeder if (PointeeStorage.BS.Pointee) 94a07aba5dSTimm Baeder PointeeStorage.BS.Pointee->addPointer(this); 95a07aba5dSTimm Baeder } else if (P.isIntegralPointer()) { 96a07aba5dSTimm Baeder PointeeStorage.Int = P.PointeeStorage.Int; 97a07aba5dSTimm Baeder } else if (P.isFunctionPointer()) { 98a07aba5dSTimm Baeder PointeeStorage.Fn = P.PointeeStorage.Fn; 99e86b68ffSTimm Baeder } else if (P.isTypeidPointer()) { 100e86b68ffSTimm Baeder PointeeStorage.Typeid = P.PointeeStorage.Typeid; 101a07aba5dSTimm Baeder } else { 102a07aba5dSTimm Baeder assert(false && "Unhandled storage kind"); 103a07aba5dSTimm Baeder } 104a07aba5dSTimm Baeder } 105a07aba5dSTimm Baeder 106a07aba5dSTimm Baeder void Pointer::operator=(Pointer &&P) { 107a07aba5dSTimm Baeder // If the current storage type is Block, we need to remove 108a07aba5dSTimm Baeder // this pointer from the block. 109a07aba5dSTimm Baeder if (isBlockPointer()) { 110a07aba5dSTimm Baeder if (P.isBlockPointer() && this->block() == P.block()) { 111a07aba5dSTimm Baeder Offset = P.Offset; 112a07aba5dSTimm Baeder PointeeStorage.BS.Base = P.PointeeStorage.BS.Base; 113a07aba5dSTimm Baeder return; 114a07aba5dSTimm Baeder } 115a07aba5dSTimm Baeder 116a07aba5dSTimm Baeder if (Block *Pointee = PointeeStorage.BS.Pointee) { 117a07aba5dSTimm Baeder assert(P.block() != this->block()); 118a07aba5dSTimm Baeder Pointee->removePointer(this); 119a07aba5dSTimm Baeder PointeeStorage.BS.Pointee = nullptr; 120a07aba5dSTimm Baeder Pointee->cleanup(); 121a07aba5dSTimm Baeder } 122a07aba5dSTimm Baeder } 123a07aba5dSTimm Baeder 124a07aba5dSTimm Baeder StorageKind = P.StorageKind; 125a07aba5dSTimm Baeder Offset = P.Offset; 126a07aba5dSTimm Baeder 127a07aba5dSTimm Baeder if (P.isBlockPointer()) { 128a07aba5dSTimm Baeder PointeeStorage.BS = P.PointeeStorage.BS; 129a07aba5dSTimm Baeder PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee; 130a07aba5dSTimm Baeder 131a07aba5dSTimm Baeder if (PointeeStorage.BS.Pointee) 132a07aba5dSTimm Baeder PointeeStorage.BS.Pointee->addPointer(this); 133a07aba5dSTimm Baeder } else if (P.isIntegralPointer()) { 134a07aba5dSTimm Baeder PointeeStorage.Int = P.PointeeStorage.Int; 135a07aba5dSTimm Baeder } else if (P.isFunctionPointer()) { 136a07aba5dSTimm Baeder PointeeStorage.Fn = P.PointeeStorage.Fn; 137e86b68ffSTimm Baeder } else if (P.isTypeidPointer()) { 138e86b68ffSTimm Baeder PointeeStorage.Typeid = P.PointeeStorage.Typeid; 139a07aba5dSTimm Baeder } else { 140a07aba5dSTimm Baeder assert(false && "Unhandled storage kind"); 141a07aba5dSTimm Baeder } 142a07aba5dSTimm Baeder } 143a07aba5dSTimm Baeder 144a07aba5dSTimm Baeder APValue Pointer::toAPValue(const ASTContext &ASTCtx) const { 145a07aba5dSTimm Baeder llvm::SmallVector<APValue::LValuePathEntry, 5> Path; 146a07aba5dSTimm Baeder 147a07aba5dSTimm Baeder if (isZero()) 148a07aba5dSTimm Baeder return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path, 149a07aba5dSTimm Baeder /*IsOnePastEnd=*/false, /*IsNullPtr=*/true); 150a07aba5dSTimm Baeder if (isIntegralPointer()) 151a07aba5dSTimm Baeder return APValue(static_cast<const Expr *>(nullptr), 152a07aba5dSTimm Baeder CharUnits::fromQuantity(asIntPointer().Value + this->Offset), 153a07aba5dSTimm Baeder Path, 154a07aba5dSTimm Baeder /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); 155a07aba5dSTimm Baeder if (isFunctionPointer()) 156a07aba5dSTimm Baeder return asFunctionPointer().toAPValue(ASTCtx); 157a07aba5dSTimm Baeder 158e86b68ffSTimm Baeder if (isTypeidPointer()) { 159e86b68ffSTimm Baeder TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr); 160e86b68ffSTimm Baeder return APValue( 161e86b68ffSTimm Baeder APValue::LValueBase::getTypeInfo( 162e86b68ffSTimm Baeder TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)), 163e86b68ffSTimm Baeder CharUnits::Zero(), APValue::NoLValuePath{}); 164e86b68ffSTimm Baeder } 165e86b68ffSTimm Baeder 166a07aba5dSTimm Baeder // Build the lvalue base from the block. 167a07aba5dSTimm Baeder const Descriptor *Desc = getDeclDesc(); 168a07aba5dSTimm Baeder APValue::LValueBase Base; 169a07aba5dSTimm Baeder if (const auto *VD = Desc->asValueDecl()) 170a07aba5dSTimm Baeder Base = VD; 171a07aba5dSTimm Baeder else if (const auto *E = Desc->asExpr()) { 172a07aba5dSTimm Baeder // Create a DynamicAlloc base of the right type. 173a07aba5dSTimm Baeder if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) { 174a07aba5dSTimm Baeder QualType AllocatedType; 175a07aba5dSTimm Baeder if (NewExpr->isArray()) { 176a07aba5dSTimm Baeder assert(Desc->isArray()); 177a07aba5dSTimm Baeder APInt ArraySize(64, static_cast<uint64_t>(Desc->getNumElems()), 178a07aba5dSTimm Baeder /*IsSigned=*/false); 179a07aba5dSTimm Baeder AllocatedType = 180a07aba5dSTimm Baeder ASTCtx.getConstantArrayType(NewExpr->getAllocatedType(), ArraySize, 181a07aba5dSTimm Baeder nullptr, ArraySizeModifier::Normal, 0); 182a07aba5dSTimm Baeder } else { 183a07aba5dSTimm Baeder AllocatedType = NewExpr->getAllocatedType(); 184a07aba5dSTimm Baeder } 185a07aba5dSTimm Baeder // FIXME: Suboptimal counting of dynamic allocations. Move this to Context 186a07aba5dSTimm Baeder // or InterpState? 187a07aba5dSTimm Baeder static int ReportedDynamicAllocs = 0; 188a07aba5dSTimm Baeder DynamicAllocLValue DA(ReportedDynamicAllocs++); 189a07aba5dSTimm Baeder Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType); 190a07aba5dSTimm Baeder } else { 191a07aba5dSTimm Baeder Base = E; 192a07aba5dSTimm Baeder } 193a07aba5dSTimm Baeder } else 194a07aba5dSTimm Baeder llvm_unreachable("Invalid allocation type"); 195a07aba5dSTimm Baeder 196a07aba5dSTimm Baeder if (isUnknownSizeArray()) 197a07aba5dSTimm Baeder return APValue(Base, CharUnits::Zero(), Path, 198a07aba5dSTimm Baeder /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false); 199a07aba5dSTimm Baeder 200a07aba5dSTimm Baeder CharUnits Offset = CharUnits::Zero(); 201a07aba5dSTimm Baeder 202a07aba5dSTimm Baeder auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits { 203a07aba5dSTimm Baeder // This shouldn't happen, but if it does, don't crash inside 204a07aba5dSTimm Baeder // getASTRecordLayout. 205a07aba5dSTimm Baeder if (FD->getParent()->isInvalidDecl()) 206a07aba5dSTimm Baeder return CharUnits::Zero(); 207a07aba5dSTimm Baeder const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent()); 208a07aba5dSTimm Baeder unsigned FieldIndex = FD->getFieldIndex(); 209a07aba5dSTimm Baeder return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)); 210a07aba5dSTimm Baeder }; 211a07aba5dSTimm Baeder 212*51c7338cSTimm Baeder bool UsePath = true; 213*51c7338cSTimm Baeder if (getType()->isLValueReferenceType()) 214*51c7338cSTimm Baeder UsePath = false; 215*51c7338cSTimm Baeder 216a07aba5dSTimm Baeder // Build the path into the object. 217a07aba5dSTimm Baeder Pointer Ptr = *this; 218a07aba5dSTimm Baeder while (Ptr.isField() || Ptr.isArrayElement()) { 2192c820799STimm Baeder 220a07aba5dSTimm Baeder if (Ptr.isArrayRoot()) { 2212c820799STimm Baeder // An array root may still be an array element itself. 2222c820799STimm Baeder if (Ptr.isArrayElement()) { 2232c820799STimm Baeder Ptr = Ptr.expand(); 224*51c7338cSTimm Baeder const Descriptor *Desc = Ptr.getFieldDesc(); 2252c820799STimm Baeder unsigned Index = Ptr.getIndex(); 226*51c7338cSTimm Baeder QualType ElemType = Desc->getElemQualType(); 2272c820799STimm Baeder Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType)); 228*51c7338cSTimm Baeder if (Ptr.getArray().getType()->isArrayType()) 229*51c7338cSTimm Baeder Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index)); 2302c820799STimm Baeder Ptr = Ptr.getArray(); 2312c820799STimm Baeder } else { 232*51c7338cSTimm Baeder const Descriptor *Desc = Ptr.getFieldDesc(); 233*51c7338cSTimm Baeder const auto *Dcl = Desc->asDecl(); 234*51c7338cSTimm Baeder Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false})); 235a07aba5dSTimm Baeder 236*51c7338cSTimm Baeder if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl)) 237a07aba5dSTimm Baeder Offset += getFieldOffset(FD); 238a07aba5dSTimm Baeder 239a07aba5dSTimm Baeder Ptr = Ptr.getBase(); 2402c820799STimm Baeder } 241a07aba5dSTimm Baeder } else if (Ptr.isArrayElement()) { 242800b0739STimm Baeder Ptr = Ptr.expand(); 243*51c7338cSTimm Baeder const Descriptor *Desc = Ptr.getFieldDesc(); 244a07aba5dSTimm Baeder unsigned Index; 245a07aba5dSTimm Baeder if (Ptr.isOnePastEnd()) 246a07aba5dSTimm Baeder Index = Ptr.getArray().getNumElems(); 247a07aba5dSTimm Baeder else 248a07aba5dSTimm Baeder Index = Ptr.getIndex(); 249a07aba5dSTimm Baeder 250*51c7338cSTimm Baeder QualType ElemType = Desc->getElemQualType(); 251800b0739STimm Baeder Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType)); 252*51c7338cSTimm Baeder if (Ptr.getArray().getType()->isArrayType()) 253a07aba5dSTimm Baeder Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index)); 254a07aba5dSTimm Baeder Ptr = Ptr.getArray(); 255a07aba5dSTimm Baeder } else { 256*51c7338cSTimm Baeder const Descriptor *Desc = Ptr.getFieldDesc(); 257a07aba5dSTimm Baeder bool IsVirtual = false; 258a07aba5dSTimm Baeder 259a07aba5dSTimm Baeder // Create a path entry for the field. 260a07aba5dSTimm Baeder if (const auto *BaseOrMember = Desc->asDecl()) { 261a07aba5dSTimm Baeder if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) { 262a07aba5dSTimm Baeder Ptr = Ptr.getBase(); 263a07aba5dSTimm Baeder Offset += getFieldOffset(FD); 264a07aba5dSTimm Baeder } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { 265a07aba5dSTimm Baeder IsVirtual = Ptr.isVirtualBaseClass(); 266a07aba5dSTimm Baeder Ptr = Ptr.getBase(); 267a07aba5dSTimm Baeder const Record *BaseRecord = Ptr.getRecord(); 268a07aba5dSTimm Baeder 269a07aba5dSTimm Baeder const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout( 270a07aba5dSTimm Baeder cast<CXXRecordDecl>(BaseRecord->getDecl())); 271a07aba5dSTimm Baeder if (IsVirtual) 272a07aba5dSTimm Baeder Offset += Layout.getVBaseClassOffset(RD); 273a07aba5dSTimm Baeder else 274a07aba5dSTimm Baeder Offset += Layout.getBaseClassOffset(RD); 275a07aba5dSTimm Baeder 276a07aba5dSTimm Baeder } else { 277a07aba5dSTimm Baeder Ptr = Ptr.getBase(); 278a07aba5dSTimm Baeder } 279a07aba5dSTimm Baeder Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); 280a07aba5dSTimm Baeder continue; 281a07aba5dSTimm Baeder } 282a07aba5dSTimm Baeder llvm_unreachable("Invalid field type"); 283a07aba5dSTimm Baeder } 284a07aba5dSTimm Baeder } 285a07aba5dSTimm Baeder 286a07aba5dSTimm Baeder // We assemble the LValuePath starting from the innermost pointer to the 287a07aba5dSTimm Baeder // outermost one. SO in a.b.c, the first element in Path will refer to 288a07aba5dSTimm Baeder // the field 'c', while later code expects it to refer to 'a'. 289a07aba5dSTimm Baeder // Just invert the order of the elements. 290a07aba5dSTimm Baeder std::reverse(Path.begin(), Path.end()); 291a07aba5dSTimm Baeder 292*51c7338cSTimm Baeder if (UsePath) 293*51c7338cSTimm Baeder return APValue(Base, Offset, Path, 294*51c7338cSTimm Baeder /*IsOnePastEnd=*/!isElementPastEnd() && isOnePastEnd()); 295*51c7338cSTimm Baeder 296*51c7338cSTimm Baeder return APValue(Base, Offset, APValue::NoLValuePath()); 297a07aba5dSTimm Baeder } 298a07aba5dSTimm Baeder 299a07aba5dSTimm Baeder void Pointer::print(llvm::raw_ostream &OS) const { 30007bd3bb9STimm Bäder switch (StorageKind) { 30107bd3bb9STimm Bäder case Storage::Block: { 302a07aba5dSTimm Baeder const Block *B = PointeeStorage.BS.Pointee; 30307bd3bb9STimm Bäder OS << "(Block) " << B << " {"; 304a07aba5dSTimm Baeder 305a07aba5dSTimm Baeder if (isRoot()) 306a07aba5dSTimm Baeder OS << "rootptr(" << PointeeStorage.BS.Base << "), "; 307a07aba5dSTimm Baeder else 308a07aba5dSTimm Baeder OS << PointeeStorage.BS.Base << ", "; 309a07aba5dSTimm Baeder 310a07aba5dSTimm Baeder if (isElementPastEnd()) 311a07aba5dSTimm Baeder OS << "pastend, "; 312a07aba5dSTimm Baeder else 313a07aba5dSTimm Baeder OS << Offset << ", "; 314a07aba5dSTimm Baeder 315a07aba5dSTimm Baeder if (B) 316a07aba5dSTimm Baeder OS << B->getSize(); 317a07aba5dSTimm Baeder else 318a07aba5dSTimm Baeder OS << "nullptr"; 319a07aba5dSTimm Baeder OS << "}"; 32007bd3bb9STimm Bäder } break; 32107bd3bb9STimm Bäder case Storage::Int: 32207bd3bb9STimm Bäder OS << "(Int) {"; 32307bd3bb9STimm Bäder OS << PointeeStorage.Int.Value << " + " << Offset << ", " 32407bd3bb9STimm Bäder << PointeeStorage.Int.Desc; 32507bd3bb9STimm Bäder OS << "}"; 32607bd3bb9STimm Bäder break; 32707bd3bb9STimm Bäder case Storage::Fn: 32807bd3bb9STimm Bäder OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset 32907bd3bb9STimm Bäder << " }"; 3303496e96fSTimm Bäder break; 331e86b68ffSTimm Baeder case Storage::Typeid: 332e86b68ffSTimm Baeder OS << "(Typeid)"; 33307bd3bb9STimm Bäder } 334a07aba5dSTimm Baeder } 335a07aba5dSTimm Baeder 336a07aba5dSTimm Baeder std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const { 337a07aba5dSTimm Baeder if (isZero()) 338a07aba5dSTimm Baeder return "nullptr"; 339a07aba5dSTimm Baeder 340a07aba5dSTimm Baeder if (isIntegralPointer()) 341a07aba5dSTimm Baeder return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str(); 342a07aba5dSTimm Baeder 343a07aba5dSTimm Baeder return toAPValue(Ctx).getAsString(Ctx, getType()); 344a07aba5dSTimm Baeder } 345a07aba5dSTimm Baeder 346a07aba5dSTimm Baeder bool Pointer::isInitialized() const { 347a07aba5dSTimm Baeder if (!isBlockPointer()) 348a07aba5dSTimm Baeder return true; 349a07aba5dSTimm Baeder 350a07aba5dSTimm Baeder if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { 351a07aba5dSTimm Baeder const GlobalInlineDescriptor &GD = 352a07aba5dSTimm Baeder *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData()); 353a07aba5dSTimm Baeder return GD.InitState == GlobalInitState::Initialized; 354a07aba5dSTimm Baeder } 355a07aba5dSTimm Baeder 356a07aba5dSTimm Baeder assert(PointeeStorage.BS.Pointee && 357a07aba5dSTimm Baeder "Cannot check if null pointer was initialized"); 358a07aba5dSTimm Baeder const Descriptor *Desc = getFieldDesc(); 359a07aba5dSTimm Baeder assert(Desc); 360a07aba5dSTimm Baeder if (Desc->isPrimitiveArray()) { 361a07aba5dSTimm Baeder if (isStatic() && PointeeStorage.BS.Base == 0) 362a07aba5dSTimm Baeder return true; 363a07aba5dSTimm Baeder 364a07aba5dSTimm Baeder InitMapPtr &IM = getInitMap(); 365a07aba5dSTimm Baeder 366a07aba5dSTimm Baeder if (!IM) 367a07aba5dSTimm Baeder return false; 368a07aba5dSTimm Baeder 369a07aba5dSTimm Baeder if (IM->first) 370a07aba5dSTimm Baeder return true; 371a07aba5dSTimm Baeder 372a07aba5dSTimm Baeder return IM->second->isElementInitialized(getIndex()); 373a07aba5dSTimm Baeder } 374a07aba5dSTimm Baeder 375a07aba5dSTimm Baeder if (asBlockPointer().Base == 0) 376a07aba5dSTimm Baeder return true; 377a07aba5dSTimm Baeder 378a07aba5dSTimm Baeder // Field has its bit in an inline descriptor. 379a07aba5dSTimm Baeder return getInlineDesc()->IsInitialized; 380a07aba5dSTimm Baeder } 381a07aba5dSTimm Baeder 382a07aba5dSTimm Baeder void Pointer::initialize() const { 383a07aba5dSTimm Baeder if (!isBlockPointer()) 384a07aba5dSTimm Baeder return; 385a07aba5dSTimm Baeder 386a07aba5dSTimm Baeder assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer"); 387a07aba5dSTimm Baeder const Descriptor *Desc = getFieldDesc(); 388a07aba5dSTimm Baeder 389a07aba5dSTimm Baeder if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) { 390a07aba5dSTimm Baeder GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>( 391a07aba5dSTimm Baeder asBlockPointer().Pointee->rawData()); 392a07aba5dSTimm Baeder GD.InitState = GlobalInitState::Initialized; 393a07aba5dSTimm Baeder return; 394a07aba5dSTimm Baeder } 395a07aba5dSTimm Baeder 396a07aba5dSTimm Baeder assert(Desc); 397a07aba5dSTimm Baeder if (Desc->isPrimitiveArray()) { 398a07aba5dSTimm Baeder // Primitive global arrays don't have an initmap. 399a07aba5dSTimm Baeder if (isStatic() && PointeeStorage.BS.Base == 0) 400a07aba5dSTimm Baeder return; 401a07aba5dSTimm Baeder 402a07aba5dSTimm Baeder // Nothing to do for these. 403a07aba5dSTimm Baeder if (Desc->getNumElems() == 0) 404a07aba5dSTimm Baeder return; 405a07aba5dSTimm Baeder 406a07aba5dSTimm Baeder InitMapPtr &IM = getInitMap(); 407a07aba5dSTimm Baeder if (!IM) 408a07aba5dSTimm Baeder IM = 409a07aba5dSTimm Baeder std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems())); 410a07aba5dSTimm Baeder 411a07aba5dSTimm Baeder assert(IM); 412a07aba5dSTimm Baeder 413a07aba5dSTimm Baeder // All initialized. 414a07aba5dSTimm Baeder if (IM->first) 415a07aba5dSTimm Baeder return; 416a07aba5dSTimm Baeder 417a07aba5dSTimm Baeder if (IM->second->initializeElement(getIndex())) { 418a07aba5dSTimm Baeder IM->first = true; 419a07aba5dSTimm Baeder IM->second.reset(); 420a07aba5dSTimm Baeder } 421a07aba5dSTimm Baeder return; 422a07aba5dSTimm Baeder } 423a07aba5dSTimm Baeder 424a07aba5dSTimm Baeder // Field has its bit in an inline descriptor. 425a07aba5dSTimm Baeder assert(PointeeStorage.BS.Base != 0 && 426a07aba5dSTimm Baeder "Only composite fields can be initialised"); 427a07aba5dSTimm Baeder getInlineDesc()->IsInitialized = true; 428a07aba5dSTimm Baeder } 429a07aba5dSTimm Baeder 430a07aba5dSTimm Baeder void Pointer::activate() const { 431a07aba5dSTimm Baeder // Field has its bit in an inline descriptor. 432a07aba5dSTimm Baeder assert(PointeeStorage.BS.Base != 0 && 433a07aba5dSTimm Baeder "Only composite fields can be activated"); 434a07aba5dSTimm Baeder 435a07aba5dSTimm Baeder if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) 436a07aba5dSTimm Baeder return; 437a07aba5dSTimm Baeder if (!getInlineDesc()->InUnion) 438a07aba5dSTimm Baeder return; 439a07aba5dSTimm Baeder 440a07aba5dSTimm Baeder getInlineDesc()->IsActive = true; 441a07aba5dSTimm Baeder 442a07aba5dSTimm Baeder // Get the union, iterate over its fields and DEactivate all others. 443a07aba5dSTimm Baeder Pointer UnionPtr = getBase(); 444a07aba5dSTimm Baeder while (!UnionPtr.getFieldDesc()->isUnion()) 445a07aba5dSTimm Baeder UnionPtr = UnionPtr.getBase(); 446a07aba5dSTimm Baeder 447a07aba5dSTimm Baeder const Record *UnionRecord = UnionPtr.getRecord(); 448a07aba5dSTimm Baeder for (const Record::Field &F : UnionRecord->fields()) { 449a07aba5dSTimm Baeder Pointer FieldPtr = UnionPtr.atField(F.Offset); 450a07aba5dSTimm Baeder if (FieldPtr == *this) { 451a07aba5dSTimm Baeder } else { 452a07aba5dSTimm Baeder FieldPtr.getInlineDesc()->IsActive = false; 453a07aba5dSTimm Baeder // FIXME: Recurse. 454a07aba5dSTimm Baeder } 455a07aba5dSTimm Baeder } 456a07aba5dSTimm Baeder 457a07aba5dSTimm Baeder Pointer B = getBase(); 458a07aba5dSTimm Baeder while (!B.isRoot() && B.inUnion()) { 459a07aba5dSTimm Baeder // FIXME: Need to de-activate other fields of parent records. 460a07aba5dSTimm Baeder B.getInlineDesc()->IsActive = true; 461a07aba5dSTimm Baeder assert(B.isActive()); 462a07aba5dSTimm Baeder B = B.getBase(); 463a07aba5dSTimm Baeder } 464a07aba5dSTimm Baeder } 465a07aba5dSTimm Baeder 466a07aba5dSTimm Baeder void Pointer::deactivate() const { 467a07aba5dSTimm Baeder // TODO: this only appears in constructors, so nothing to deactivate. 468a07aba5dSTimm Baeder } 469a07aba5dSTimm Baeder 470a07aba5dSTimm Baeder bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { 471a07aba5dSTimm Baeder // Two null pointers always have the same base. 472a07aba5dSTimm Baeder if (A.isZero() && B.isZero()) 473a07aba5dSTimm Baeder return true; 474a07aba5dSTimm Baeder 475a07aba5dSTimm Baeder if (A.isIntegralPointer() && B.isIntegralPointer()) 476a07aba5dSTimm Baeder return true; 477a07aba5dSTimm Baeder if (A.isFunctionPointer() && B.isFunctionPointer()) 478a07aba5dSTimm Baeder return true; 479e86b68ffSTimm Baeder if (A.isTypeidPointer() && B.isTypeidPointer()) 480e86b68ffSTimm Baeder return true; 481a07aba5dSTimm Baeder 482a07aba5dSTimm Baeder if (A.isIntegralPointer() || B.isIntegralPointer()) 483a07aba5dSTimm Baeder return A.getSource() == B.getSource(); 484a07aba5dSTimm Baeder 485a07aba5dSTimm Baeder if (A.StorageKind != B.StorageKind) 486a07aba5dSTimm Baeder return false; 487a07aba5dSTimm Baeder 488a07aba5dSTimm Baeder return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee; 489a07aba5dSTimm Baeder } 490a07aba5dSTimm Baeder 491a07aba5dSTimm Baeder bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) { 492a07aba5dSTimm Baeder if (!A.isBlockPointer() || !B.isBlockPointer()) 493a07aba5dSTimm Baeder return false; 494a07aba5dSTimm Baeder return A.block() == B.block(); 495a07aba5dSTimm Baeder } 496a07aba5dSTimm Baeder 497a07aba5dSTimm Baeder bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { 498a07aba5dSTimm Baeder return hasSameBase(A, B) && 499a07aba5dSTimm Baeder A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base && 500a07aba5dSTimm Baeder A.getFieldDesc()->IsArray; 501a07aba5dSTimm Baeder } 502a07aba5dSTimm Baeder 503360e4abfSTimm Baeder bool Pointer::pointsToLiteral() const { 504360e4abfSTimm Baeder if (isZero() || !isBlockPointer()) 505360e4abfSTimm Baeder return false; 506360e4abfSTimm Baeder 507360e4abfSTimm Baeder if (block()->isDynamic()) 508360e4abfSTimm Baeder return false; 509360e4abfSTimm Baeder 51039e8953fSTimm Baeder const Expr *E = block()->getDescriptor()->asExpr(); 511360e4abfSTimm Baeder return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E); 512360e4abfSTimm Baeder } 513360e4abfSTimm Baeder 514a07aba5dSTimm Baeder std::optional<APValue> Pointer::toRValue(const Context &Ctx, 515a07aba5dSTimm Baeder QualType ResultType) const { 516a07aba5dSTimm Baeder const ASTContext &ASTCtx = Ctx.getASTContext(); 517a07aba5dSTimm Baeder assert(!ResultType.isNull()); 518a07aba5dSTimm Baeder // Method to recursively traverse composites. 519a07aba5dSTimm Baeder std::function<bool(QualType, const Pointer &, APValue &)> Composite; 520a07aba5dSTimm Baeder Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr, 521a07aba5dSTimm Baeder APValue &R) { 522a07aba5dSTimm Baeder if (const auto *AT = Ty->getAs<AtomicType>()) 523a07aba5dSTimm Baeder Ty = AT->getValueType(); 524a07aba5dSTimm Baeder 525a07aba5dSTimm Baeder // Invalid pointers. 526a07aba5dSTimm Baeder if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() || 527a07aba5dSTimm Baeder Ptr.isPastEnd()) 528a07aba5dSTimm Baeder return false; 529a07aba5dSTimm Baeder 530a07aba5dSTimm Baeder // Primitive values. 531a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(Ty)) { 532a07aba5dSTimm Baeder TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx)); 533a07aba5dSTimm Baeder return true; 534a07aba5dSTimm Baeder } 535a07aba5dSTimm Baeder 536a07aba5dSTimm Baeder if (const auto *RT = Ty->getAs<RecordType>()) { 537a07aba5dSTimm Baeder const auto *Record = Ptr.getRecord(); 538a07aba5dSTimm Baeder assert(Record && "Missing record descriptor"); 539a07aba5dSTimm Baeder 540a07aba5dSTimm Baeder bool Ok = true; 541a07aba5dSTimm Baeder if (RT->getDecl()->isUnion()) { 542a07aba5dSTimm Baeder const FieldDecl *ActiveField = nullptr; 543a07aba5dSTimm Baeder APValue Value; 544a07aba5dSTimm Baeder for (const auto &F : Record->fields()) { 545a07aba5dSTimm Baeder const Pointer &FP = Ptr.atField(F.Offset); 546a07aba5dSTimm Baeder QualType FieldTy = F.Decl->getType(); 547a07aba5dSTimm Baeder if (FP.isActive()) { 548a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { 549a07aba5dSTimm Baeder TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); 550a07aba5dSTimm Baeder } else { 551a07aba5dSTimm Baeder Ok &= Composite(FieldTy, FP, Value); 552a07aba5dSTimm Baeder } 553a07aba5dSTimm Baeder ActiveField = FP.getFieldDesc()->asFieldDecl(); 554a07aba5dSTimm Baeder break; 555a07aba5dSTimm Baeder } 556a07aba5dSTimm Baeder } 557a07aba5dSTimm Baeder R = APValue(ActiveField, Value); 558a07aba5dSTimm Baeder } else { 559a07aba5dSTimm Baeder unsigned NF = Record->getNumFields(); 560a07aba5dSTimm Baeder unsigned NB = Record->getNumBases(); 561a07aba5dSTimm Baeder unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases(); 562a07aba5dSTimm Baeder 563a07aba5dSTimm Baeder R = APValue(APValue::UninitStruct(), NB, NF); 564a07aba5dSTimm Baeder 565a07aba5dSTimm Baeder for (unsigned I = 0; I < NF; ++I) { 566a07aba5dSTimm Baeder const Record::Field *FD = Record->getField(I); 567a07aba5dSTimm Baeder QualType FieldTy = FD->Decl->getType(); 568a07aba5dSTimm Baeder const Pointer &FP = Ptr.atField(FD->Offset); 569a07aba5dSTimm Baeder APValue &Value = R.getStructField(I); 570a07aba5dSTimm Baeder 571a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(FieldTy)) { 572a07aba5dSTimm Baeder TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx)); 573a07aba5dSTimm Baeder } else { 574a07aba5dSTimm Baeder Ok &= Composite(FieldTy, FP, Value); 575a07aba5dSTimm Baeder } 576a07aba5dSTimm Baeder } 577a07aba5dSTimm Baeder 578a07aba5dSTimm Baeder for (unsigned I = 0; I < NB; ++I) { 579a07aba5dSTimm Baeder const Record::Base *BD = Record->getBase(I); 580a07aba5dSTimm Baeder QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl); 581a07aba5dSTimm Baeder const Pointer &BP = Ptr.atField(BD->Offset); 582a07aba5dSTimm Baeder Ok &= Composite(BaseTy, BP, R.getStructBase(I)); 583a07aba5dSTimm Baeder } 584a07aba5dSTimm Baeder 585a07aba5dSTimm Baeder for (unsigned I = 0; I < NV; ++I) { 586a07aba5dSTimm Baeder const Record::Base *VD = Record->getVirtualBase(I); 587a07aba5dSTimm Baeder QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl); 588a07aba5dSTimm Baeder const Pointer &VP = Ptr.atField(VD->Offset); 589a07aba5dSTimm Baeder Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I)); 590a07aba5dSTimm Baeder } 591a07aba5dSTimm Baeder } 592a07aba5dSTimm Baeder return Ok; 593a07aba5dSTimm Baeder } 594a07aba5dSTimm Baeder 595a07aba5dSTimm Baeder if (Ty->isIncompleteArrayType()) { 596a07aba5dSTimm Baeder R = APValue(APValue::UninitArray(), 0, 0); 597a07aba5dSTimm Baeder return true; 598a07aba5dSTimm Baeder } 599a07aba5dSTimm Baeder 600a07aba5dSTimm Baeder if (const auto *AT = Ty->getAsArrayTypeUnsafe()) { 601a07aba5dSTimm Baeder const size_t NumElems = Ptr.getNumElems(); 602a07aba5dSTimm Baeder QualType ElemTy = AT->getElementType(); 603a07aba5dSTimm Baeder R = APValue(APValue::UninitArray{}, NumElems, NumElems); 604a07aba5dSTimm Baeder 605a07aba5dSTimm Baeder bool Ok = true; 606a07aba5dSTimm Baeder for (unsigned I = 0; I < NumElems; ++I) { 607a07aba5dSTimm Baeder APValue &Slot = R.getArrayInitializedElt(I); 608a07aba5dSTimm Baeder const Pointer &EP = Ptr.atIndex(I); 609a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(ElemTy)) { 610a07aba5dSTimm Baeder TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx)); 611a07aba5dSTimm Baeder } else { 612a07aba5dSTimm Baeder Ok &= Composite(ElemTy, EP.narrow(), Slot); 613a07aba5dSTimm Baeder } 614a07aba5dSTimm Baeder } 615a07aba5dSTimm Baeder return Ok; 616a07aba5dSTimm Baeder } 617a07aba5dSTimm Baeder 618a07aba5dSTimm Baeder // Complex types. 619a07aba5dSTimm Baeder if (const auto *CT = Ty->getAs<ComplexType>()) { 620a07aba5dSTimm Baeder QualType ElemTy = CT->getElementType(); 621a07aba5dSTimm Baeder 622a07aba5dSTimm Baeder if (ElemTy->isIntegerType()) { 623a07aba5dSTimm Baeder std::optional<PrimType> ElemT = Ctx.classify(ElemTy); 624a07aba5dSTimm Baeder assert(ElemT); 625a07aba5dSTimm Baeder INT_TYPE_SWITCH(*ElemT, { 626a07aba5dSTimm Baeder auto V1 = Ptr.atIndex(0).deref<T>(); 627a07aba5dSTimm Baeder auto V2 = Ptr.atIndex(1).deref<T>(); 628a07aba5dSTimm Baeder R = APValue(V1.toAPSInt(), V2.toAPSInt()); 629a07aba5dSTimm Baeder return true; 630a07aba5dSTimm Baeder }); 631a07aba5dSTimm Baeder } else if (ElemTy->isFloatingType()) { 632a07aba5dSTimm Baeder R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(), 633a07aba5dSTimm Baeder Ptr.atIndex(1).deref<Floating>().getAPFloat()); 634a07aba5dSTimm Baeder return true; 635a07aba5dSTimm Baeder } 636a07aba5dSTimm Baeder return false; 637a07aba5dSTimm Baeder } 638a07aba5dSTimm Baeder 639a07aba5dSTimm Baeder // Vector types. 640a07aba5dSTimm Baeder if (const auto *VT = Ty->getAs<VectorType>()) { 641a07aba5dSTimm Baeder assert(Ptr.getFieldDesc()->isPrimitiveArray()); 642a07aba5dSTimm Baeder QualType ElemTy = VT->getElementType(); 643a07aba5dSTimm Baeder PrimType ElemT = *Ctx.classify(ElemTy); 644a07aba5dSTimm Baeder 645a07aba5dSTimm Baeder SmallVector<APValue> Values; 646a07aba5dSTimm Baeder Values.reserve(VT->getNumElements()); 647a07aba5dSTimm Baeder for (unsigned I = 0; I != VT->getNumElements(); ++I) { 648a07aba5dSTimm Baeder TYPE_SWITCH(ElemT, { 649a07aba5dSTimm Baeder Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx)); 650a07aba5dSTimm Baeder }); 651a07aba5dSTimm Baeder } 652a07aba5dSTimm Baeder 653a07aba5dSTimm Baeder assert(Values.size() == VT->getNumElements()); 654a07aba5dSTimm Baeder R = APValue(Values.data(), Values.size()); 655a07aba5dSTimm Baeder return true; 656a07aba5dSTimm Baeder } 657a07aba5dSTimm Baeder 658a07aba5dSTimm Baeder llvm_unreachable("invalid value to return"); 659a07aba5dSTimm Baeder }; 660a07aba5dSTimm Baeder 661a07aba5dSTimm Baeder // Invalid to read from. 662a07aba5dSTimm Baeder if (isDummy() || !isLive() || isPastEnd()) 663a07aba5dSTimm Baeder return std::nullopt; 664a07aba5dSTimm Baeder 665a07aba5dSTimm Baeder // We can return these as rvalues, but we can't deref() them. 666a07aba5dSTimm Baeder if (isZero() || isIntegralPointer()) 667a07aba5dSTimm Baeder return toAPValue(ASTCtx); 668a07aba5dSTimm Baeder 669a07aba5dSTimm Baeder // Just load primitive types. 670a07aba5dSTimm Baeder if (std::optional<PrimType> T = Ctx.classify(ResultType)) { 671a07aba5dSTimm Baeder TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx)); 672a07aba5dSTimm Baeder } 673a07aba5dSTimm Baeder 674a07aba5dSTimm Baeder // Return the composite type. 675a07aba5dSTimm Baeder APValue Result; 676df8b7858STimm Baeder if (!Composite(ResultType, *this, Result)) 677a07aba5dSTimm Baeder return std::nullopt; 678a07aba5dSTimm Baeder return Result; 679a07aba5dSTimm Baeder } 680a07aba5dSTimm Baeder 681a07aba5dSTimm Baeder IntPointer IntPointer::atOffset(const ASTContext &ASTCtx, 682a07aba5dSTimm Baeder unsigned Offset) const { 683a07aba5dSTimm Baeder if (!this->Desc) 684a07aba5dSTimm Baeder return *this; 685a07aba5dSTimm Baeder const Record *R = this->Desc->ElemRecord; 686a07aba5dSTimm Baeder if (!R) 687a07aba5dSTimm Baeder return *this; 688a07aba5dSTimm Baeder 689a07aba5dSTimm Baeder const Record::Field *F = nullptr; 690a07aba5dSTimm Baeder for (auto &It : R->fields()) { 691a07aba5dSTimm Baeder if (It.Offset == Offset) { 692a07aba5dSTimm Baeder F = &It; 693a07aba5dSTimm Baeder break; 694a07aba5dSTimm Baeder } 695a07aba5dSTimm Baeder } 696a07aba5dSTimm Baeder if (!F) 697a07aba5dSTimm Baeder return *this; 698a07aba5dSTimm Baeder 699a07aba5dSTimm Baeder const FieldDecl *FD = F->Decl; 700a07aba5dSTimm Baeder const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent()); 701a07aba5dSTimm Baeder unsigned FieldIndex = FD->getFieldIndex(); 702a07aba5dSTimm Baeder uint64_t FieldOffset = 703a07aba5dSTimm Baeder ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex)) 704a07aba5dSTimm Baeder .getQuantity(); 705904f58e6STimm Baeder return IntPointer{F->Desc, this->Value + FieldOffset}; 706a07aba5dSTimm Baeder } 70743fd2c40STimm Baeder 70843fd2c40STimm Baeder IntPointer IntPointer::baseCast(const ASTContext &ASTCtx, 70943fd2c40STimm Baeder unsigned BaseOffset) const { 71043fd2c40STimm Baeder const Record *R = Desc->ElemRecord; 71143fd2c40STimm Baeder const Descriptor *BaseDesc = nullptr; 71243fd2c40STimm Baeder 71343fd2c40STimm Baeder // This iterates over bases and checks for the proper offset. That's 71443fd2c40STimm Baeder // potentially slow but this case really shouldn't happen a lot. 71543fd2c40STimm Baeder for (const Record::Base &B : R->bases()) { 71643fd2c40STimm Baeder if (B.Offset == BaseOffset) { 71743fd2c40STimm Baeder BaseDesc = B.Desc; 71843fd2c40STimm Baeder break; 71943fd2c40STimm Baeder } 72043fd2c40STimm Baeder } 72143fd2c40STimm Baeder assert(BaseDesc); 72243fd2c40STimm Baeder 72343fd2c40STimm Baeder // Adjust the offset value based on the information from the record layout. 72443fd2c40STimm Baeder const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl()); 72543fd2c40STimm Baeder CharUnits BaseLayoutOffset = 72643fd2c40STimm Baeder Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl())); 72743fd2c40STimm Baeder 72843fd2c40STimm Baeder return {BaseDesc, Value + BaseLayoutOffset.getQuantity()}; 72943fd2c40STimm Baeder } 730