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