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