clang: lib/AST/ByteCode/Pointer.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

22

23using namespace clang;

25

27 : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),

28 Pointee->getDescriptor()->getMetadataSize()) {}

29

31 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}

32

34 : Offset(Offset), StorageKind(Storage::Block) {

35 assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");

37

38 BS = {Pointee, Base, nullptr, nullptr};

39

40 if (Pointee)

41 Pointee->addPointer(this);

42}

43

45 : Offset(P.Offset), StorageKind(P.StorageKind) {

46 switch (StorageKind) {

49 break;

52 if (BS.Pointee)

53 BS.Pointee->addPointer(this);

54 break;

57 break;

60 break;

61 }

62}

63

65 switch (StorageKind) {

67 Int = P.Int;

68 break;

70 BS = P.BS;

71 if (BS.Pointee)

72 BS.Pointee->replacePointer(&P, this);

73 break;

75 Fn = P.Fn;

76 break;

79 break;

80 }

81}

82

85 return;

86

87 if (Block *Pointee = BS.Pointee) {

88 Pointee->removePointer(this);

89 BS.Pointee = nullptr;

90 Pointee->cleanup();

91 }

92}

93

95

96

99 Offset = P.Offset;

101 return *this;

102 }

103

104 if (Block *Pointee = BS.Pointee) {

105 Pointee->removePointer(this);

106 BS.Pointee = nullptr;

107 Pointee->cleanup();

108 }

109 }

110

111 StorageKind = P.StorageKind;

112 Offset = P.Offset;

113

114 switch (StorageKind) {

117 break;

120

121 if (BS.Pointee)

122 BS.Pointee->addPointer(this);

123 break;

126 break;

129 }

130 return *this;

131}

132

134

135

137 if (P.isBlockPointer() && this->block() == P.block()) {

138 Offset = P.Offset;

139 BS.Base = P.BS.Base;

140 return *this;

141 }

142

143 if (Block *Pointee = BS.Pointee) {

144 Pointee->removePointer(this);

145 BS.Pointee = nullptr;

146 Pointee->cleanup();

147 }

148 }

149

150 StorageKind = P.StorageKind;

151 Offset = P.Offset;

152

153 switch (StorageKind) {

155 Int = P.Int;

156 break;

158 BS = P.BS;

159

160 if (BS.Pointee)

161 BS.Pointee->addPointer(this);

162 break;

164 Fn = P.Fn;

165 break;

168 }

169 return *this;

170}

171

174

177 false, true);

179 return APValue(static_cast<const Expr *>(nullptr),

181 Path,

182 false, false);

187 false, false);

189 {},

190 false, false);

191 }

192

198 false, false);

199 }

200

201

204 if (const auto *VD = Desc->asValueDecl())

206 else if (const auto *E = Desc->asExpr()) {

211 } else {

213 }

214 } else

215 llvm_unreachable("Invalid allocation type");

216

219 isOnePastEnd(), false);

220

222

224

225

226 if (FD->getParent()->isInvalidDecl())

229 unsigned FieldIndex = FD->getFieldIndex();

231 };

232

233 bool UsePath = true;

235 VD && VD->getType()->isReferenceType())

236 UsePath = false;

237

238

242

244

248 unsigned Index = Ptr.getIndex();

254 } else {

256 const auto *Dcl = Desc->asDecl();

258

259 if (const auto *FD = dyn_cast_if_present(Dcl))

261

263 }

267 unsigned Index;

270 OnePastEnd = false;

271 } else

273

277

278 } else {

280 }

284 } else {

286

287

288 if (const auto *BaseOrMember = Desc->asDecl()) {

289 bool IsVirtual = false;

290 if (const auto *FD = dyn_cast(BaseOrMember)) {

293 } else if (const auto *RD = dyn_cast(BaseOrMember)) {

297

300 if (IsVirtual)

302 else

304

305 } else {

307 }

309 continue;

310 }

311 llvm_unreachable("Invalid field type");

312 }

313 }

314

315

316

317

318

319 std::reverse(Path.begin(), Path.end());

320

321 if (UsePath)

322 return APValue(Base, Offset, Path, OnePastEnd);

323

325}

326

328 switch (StorageKind) {

330 const Block *B = BS.Pointee;

331 OS << "(Block) " << B << " {";

332

334 OS << "rootptr(" << BS.Base << "), ";

335 else

336 OS << BS.Base << ", ";

337

339 OS << "pastend, ";

340 else

341 OS << Offset << ", ";

342

343 if (B)

345 else

346 OS << "nullptr";

347 OS << "}";

348 } break;

350 OS << "(Int) {";

351 OS << Int.Value << " + " << Offset << ", " << Int.Desc;

352 OS << "}";

353 break;

356 << " }";

357 break;

361 << "}";

362 }

363}

364

366 switch (StorageKind) {

368 return Int.Value + Offset;

370

371 break;

373 return Fn.getIntegerRepresentation() + Offset;

376 }

377

380 while (true) {

381

383 Result += getInlineDesc()->Offset;

385 continue;

386 }

387

392 continue;

393 }

398 continue;

399 }

400

404 break;

405 }

406

410

412 continue;

413 }

414

415

419

422 break;

423 }

424

426}

427

430 return "nullptr";

431

433 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();

434

437

439}

440

443 return true;

444

446 Offset == BS.Base) {

449 }

450

451 assert(BS.Pointee && "Cannot check if null pointer was initialized");

453 assert(Desc);

456

458 return true;

459

460 return getInlineDesc()->IsInitialized;

461}

462

465 return true;

466

468 assert(Desc);

469

471 return true;

472

474 Offset == BS.Base) {

477 }

478

481 if (!IM)

482 return false;

483

484 if (IM->first)

485 return true;

486

487 return IM->second->isElementInitialized(Index);

488 }

490}

491

494 return;

495

496 assert(BS.Pointee && "Cannot initialize null pointer");

497

499 Offset == BS.Base) {

502 return;

503 }

504

506 assert(Desc);

510 return;

511 }

512

513

514 assert(BS.Base != 0 && "Only composite fields can be initialised");

515 getInlineDesc()->IsInitialized = true;

516}

517

519

521 return;

522

524

526 if (!IM) {

528 IM = std::make_pair(false, std::make_shared(Desc->getNumElems()));

529 }

530

531 assert(IM);

532

533

534 if (IM->first)

535 return;

536

537 if (IM->second->initializeElement(Index)) {

538 IM->first = true;

539 IM->second.reset();

540 }

541}

542

546

548 if (!IM) {

549 IM = std::make_pair(true, nullptr);

550 } else {

551 IM->first = true;

552 IM->second.reset();

553 }

554}

555

559

561 return true;

562

564 Offset == BS.Base) {

567 }

568

570 return IM && IM->first;

571}

572

574

575 assert(BS.Base != 0 && "Only composite fields can be activated");

576

578 return;

579 if (!getInlineDesc()->InUnion)

580 return;

581

584 P.getInlineDesc()->IsActive = true;

585 if (const Record *R = P.getRecord(); R && !R->isUnion()) {

586 for (const Record::Field &F : R->fields()) {

587 Pointer FieldPtr = P.atField(F.Offset);

588 if (!FieldPtr.getInlineDesc()->IsActive)

590 }

591

592 }

593 };

594

597 P.getInlineDesc()->IsActive = false;

598

599 if (const Record *R = P.getRecord()) {

600 for (const Record::Field &F : R->fields()) {

601 Pointer FieldPtr = P.atField(F.Offset);

602 if (FieldPtr.getInlineDesc()->IsActive)

604 }

605

606 }

607 };

608

612

613

614

618 for (const Record::Field &F : BR->fields()) {

620 if (FieldPtr != Cur)

622 }

623 }

624 }

625}

626

630

632

634 return true;

635

637 return true;

639 return true;

641 return true;

642

643 if (A.StorageKind != B.StorageKind)

644 return false;

645

647}

648

654

659

662 return false;

663

665 return false;

666

669}

670

673 return false;

674

676 return false;

677

679 return isa_and_nonnull(E);

680}

681

682std::optional<std::pair<Pointer, Pointer>>

685 return std::nullopt;

686

688 return std::nullopt;

690 return std::nullopt;

691

692 if (A == B)

693 return std::make_pair(A, B);

694

696 if (P.isArrayElement())

697 return P.expand().getArray();

698 return P.getBase();

699 };

700

705 for (;;) {

707 CurA = IterA;

709 } else {

710 CurB = IterB;

712 }

713

714 if (IterA == IterB)

715 return std::make_pair(CurA, CurB);

716

718 return std::nullopt;

719 }

720

721 llvm_unreachable("The loop above should've returned.");

722}

723

727 assert(!ResultType.isNull());

728

730 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,

732 if (const auto *AT = Ty->getAs<AtomicType>())

733 Ty = AT->getValueType();

734

735

736 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||

737 Ptr.isPastEnd())

738 return false;

739

740

742 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));

743 return true;

744 }

745

746 if (const auto *RT = Ty->getAsCanonical()) {

747 const auto *Record = Ptr.getRecord();

748 assert(Record && "Missing record descriptor");

749

750 bool Ok = true;

751 if (RT->getDecl()->isUnion()) {

752 const FieldDecl *ActiveField = nullptr;

755 const Pointer &FP = Ptr.atField(F.Offset);

756 QualType FieldTy = F.Decl->getType();

760 } else {

761 Ok &= Composite(FieldTy, FP, Value);

762 }

764 break;

765 }

766 }

768 } else {

772

774

775 for (unsigned I = 0; I < NF; ++I) {

777 QualType FieldTy = FD->Decl->getType();

778 const Pointer &FP = Ptr.atField(FD->Offset);

780

783 } else {

784 Ok &= Composite(FieldTy, FP, Value);

785 }

786 }

787

788 for (unsigned I = 0; I < NB; ++I) {

791 const Pointer &BP = Ptr.atField(BD->Offset);

792 Ok &= Composite(BaseTy, BP, R.getStructBase(I));

793 }

794

795 for (unsigned I = 0; I < NV; ++I) {

799 const Pointer &VP = Ptr.atField(VD->Offset);

800 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));

801 }

802 }

803 return Ok;

804 }

805

806 if (Ty->isIncompleteArrayType()) {

808 return true;

809 }

810

811 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {

812 const size_t NumElems = Ptr.getNumElems();

813 QualType ElemTy = AT->getElementType();

815

816 bool Ok = true;

818 for (unsigned I = 0; I != NumElems; ++I) {

820 if (ElemT) {

821 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));

822 } else {

823 Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);

824 }

825 }

826 return Ok;

827 }

828

829

830 if (const auto *CT = Ty->getAs<ComplexType>()) {

831

832 if (!Ptr.getFieldDesc()->isPrimitiveArray())

833 return false;

834

835 QualType ElemTy = CT->getElementType();

838 assert(ElemT);

840 auto V1 = Ptr.elem<T>(0);

841 auto V2 = Ptr.elem<T>(1);

842 R = APValue(V1.toAPSInt(), V2.toAPSInt());

843 return true;

844 });

848 return true;

849 }

850 return false;

851 }

852

853

854 if (const auto *VT = Ty->getAs<VectorType>()) {

855 assert(Ptr.getFieldDesc()->isPrimitiveArray());

856 QualType ElemTy = VT->getElementType();

858

860 Values.reserve(VT->getNumElements());

861 for (unsigned I = 0; I != VT->getNumElements(); ++I) {

863 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });

864 }

865

866 assert(Values.size() == VT->getNumElements());

867 R = APValue(Values.data(), Values.size());

868 return true;

869 }

870

871 llvm_unreachable("invalid value to return");

872 };

873

874

876 return std::nullopt;

877

878

881

882

885 }

886

887

889 if (!Composite(ResultType, *this, Result))

890 return std::nullopt;

892}

893

895 unsigned Offset) const {

896 if (!this->Desc)

897 return *this;

898 const Record *R = this->Desc->ElemRecord;

899 if (!R)

900 return *this;

901

902 const Record::Field *F = nullptr;

903 for (auto &It : R->fields()) {

904 if (It.Offset == Offset) {

905 F = &It;

906 break;

907 }

908 }

909 if (!F)

910 return *this;

911

914 return std::nullopt;

915

918 uint64_t FieldOffset =

922}

923

925 unsigned BaseOffset) const {

927 assert(Value == 0);

928 return *this;

929 }

931 const Descriptor *BaseDesc = nullptr;

932

933

934

935 for (const Record::Base &B : R->bases()) {

936 if (B.Offset == BaseOffset) {

937 BaseDesc = B.Desc;

938 break;

939 }

940 }

941 assert(BaseDesc);

942

943

947

949}

Defines the clang::Expr interface and subclasses for C++ expressions.

#define INT_TYPE_SWITCH(Expr, B)

#define TYPE_SWITCH(Expr, B)

static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD)

static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo)

static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type)

A non-discriminated union of a base, field, or array index.

static LValuePathEntry ArrayIndex(uint64_t Index)

APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...

APValue & getArrayInitializedElt(unsigned I)

std::string getAsString(const ASTContext &Ctx, QualType Ty) const

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const

Get or compute information about the layout of the specified record (struct/union/class) D,...

CharUnits getTypeSizeInChars(QualType T) const

Return the size of the specified (complete) type T, in characters.

CharUnits toCharUnitsFromBits(int64_t BitSize) const

Convert a size in bits to a size in characters.

CanQualType getCanonicalTagType(const TagDecl *TD) const

ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...

uint64_t getFieldOffset(unsigned FieldNo) const

getFieldOffset - Get the offset of the given field index, in bits.

CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const

getBaseClassOffset - Get the offset, in chars, for the given base class.

CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const

getVBaseClassOffset - Get the offset, in chars, for the given base class.

CharUnits - This is an opaque type for sizes expressed in character units.

QuantityType getQuantity() const

getQuantity - Get the raw integer representation of this quantity.

static CharUnits fromQuantity(QuantityType Quantity)

fromQuantity - Construct a CharUnits quantity from a raw integer type.

static CharUnits Zero()

Zero - Construct a CharUnits quantity of zero.

Complex values, per C99 6.2.5p11.

bool isInvalidDecl() const

Symbolic representation of a dynamic allocation.

This represents one expression.

Represents a member of a struct/union/class.

unsigned getFieldIndex() const

Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...

const RecordDecl * getParent() const

Returns the parent of this field declaration, which is the struct in which this field is defined.

Represents a function declaration or definition.

A (possibly-)qualified type.

bool isNull() const

Return true if this QualType doesn't point to a type yet.

RecordDecl * getDefinition() const

Returns the RecordDecl that actually defines this struct/union/class.

Symbolic representation of typeid(T) for some type T.

RecordDecl * getAsRecordDecl() const

Retrieves the RecordDecl this type refers to.

bool isIntegerType() const

isIntegerType() does not include complex integers (a GCC extension).

bool isFloatingType() const

Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...

Represents a GCC generic vector type.

unsigned getSize() const

Returns the size of the block.

const Descriptor * getDescriptor() const

Returns the block's descriptor.

Holds all information required to evaluate constexpr code in a module.

ASTContext & getASTContext() const

Returns the AST context.

OptPrimType classify(QualType T) const

Classifies a type.

If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.

APFloat getAPFloat() const

const Function * getFunction() const

std::string toDiagnosticString(const ASTContext &Ctx) const

const BlockExpr * getExpr() const

const FunctionDecl * getDecl() const

Returns the original FunctionDecl.

static bool hasSameBase(const Pointer &A, const Pointer &B)

Checks if two pointers are comparable.

Definition Pointer.cpp:631

void deactivate() const

Deactivates an entire strurcutre.

Definition Pointer.cpp:627

bool isInitialized() const

Checks if an object was initialized.

Definition Pointer.cpp:441

bool isStatic() const

Checks if the storage is static.

bool isDynamic() const

Checks if the storage has been dynamically allocated.

bool isZeroSizeArray() const

Checks if the pointer is pointing to a zero-size array.

bool isElementInitialized(unsigned Index) const

Like isInitialized(), but for primitive arrays.

Definition Pointer.cpp:463

bool isDummy() const

Checks if the pointer points to a dummy value.

void print(llvm::raw_ostream &OS) const

Prints the pointer.

Definition Pointer.cpp:327

int64_t getIndex() const

Returns the index into an array.

bool isActive() const

Checks if the object is active.

Pointer atField(unsigned Off) const

Creates a pointer to a field.

T & deref() const

Dereferences the pointer, if it's live.

unsigned getNumElems() const

Returns the number of elements.

Pointer getArray() const

Returns the parent array.

bool isUnknownSizeArray() const

Checks if the structure is an array of unknown size.

void activate() const

Activats a field.

Definition Pointer.cpp:573

static std::optional< std::pair< Pointer, Pointer > > computeSplitPoint(const Pointer &A, const Pointer &B)

Definition Pointer.cpp:683

const TypeidPointer & asTypeidPointer() const

bool isIntegralPointer() const

QualType getType() const

Returns the type of the innermost field.

bool isArrayElement() const

Checks if the pointer points to an array.

void initializeAllElements() const

Initialize all elements of a primitive array at once.

Definition Pointer.cpp:543

bool pointsToStringLiteral() const

Definition Pointer.cpp:671

bool isArrayRoot() const

Whether this array refers to an array, but not to the first element.

~Pointer()

Definition Pointer.cpp:83

bool isLive() const

Checks if the pointer is live.

bool pointsToLiteral() const

Whether this points to a block that's been created for a "literal lvalue", i.e.

Definition Pointer.cpp:660

Pointer getBase() const

Returns a pointer to the object of which this pointer is a field.

bool isTypeidPointer() const

std::string toDiagnosticString(const ASTContext &Ctx) const

Converts the pointer to a string usable in diagnostics.

Definition Pointer.cpp:428

bool isZero() const

Checks if the pointer is null.

Pointer & operator=(const Pointer &P)

Definition Pointer.cpp:94

const IntPointer & asIntPointer() const

bool isRoot() const

Pointer points directly to a block.

const Descriptor * getDeclDesc() const

Accessor for information about the declaration site.

static bool pointToSameBlock(const Pointer &A, const Pointer &B)

Checks if both given pointers point to the same block.

Definition Pointer.cpp:649

APValue toAPValue(const ASTContext &ASTCtx) const

Converts the pointer to an APValue.

Definition Pointer.cpp:172

bool isOnePastEnd() const

Checks if the index is one past end.

static bool hasSameArray(const Pointer &A, const Pointer &B)

Checks if two pointers can be subtracted.

Definition Pointer.cpp:655

bool isPastEnd() const

Checks if the pointer points past the end of the object.

Pointer expand() const

Expands a pointer to the containing array, undoing narrowing.

bool isElementPastEnd() const

Checks if the pointer is an out-of-bounds element pointer.

bool isBlockPointer() const

std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const

Converts the pointer to an APValue that is an rvalue.

Definition Pointer.cpp:724

const FunctionPointer & asFunctionPointer() const

bool allElementsInitialized() const

Definition Pointer.cpp:556

const Block * block() const

bool isFunctionPointer() const

Pointer getDeclPtr() const

const Descriptor * getFieldDesc() const

Accessors for information about the innermost field.

bool isVirtualBaseClass() const

bool isBaseClass() const

Checks if a structure is a base class.

size_t elemSize() const

Returns the element size of the innermost field.

size_t computeOffsetForComparison() const

Compute an integer that can be used to compare this pointer to another one.

Definition Pointer.cpp:365

const BlockPointer & asBlockPointer() const

void initialize() const

Initializes a field.

Definition Pointer.cpp:492

bool isField() const

Checks if the item is a field in an object.

void initializeElement(unsigned Index) const

Initialized the given element of a primitive array.

Definition Pointer.cpp:518

const Record * getRecord() const

Returns the record descriptor of a class.

Structure/Class descriptor.

const RecordDecl * getDecl() const

Returns the underlying declaration.

bool isUnion() const

Checks if the record is a union.

unsigned getNumBases() const

const Field * getField(const FieldDecl *FD) const

Returns a field.

llvm::iterator_range< const_base_iter > bases() const

const Base * getVirtualBase(const RecordDecl *RD) const

Returns a virtual base descriptor.

unsigned getNumFields() const

unsigned getNumVirtualBases() const

llvm::iterator_range< const_field_iter > fields() const

const Base * getBase(const RecordDecl *FD) const

Returns a base descriptor.

PrimType

Enumeration of the primitive types of the VM.

std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr

The JSON file list parser is used to communicate input to InstallAPI.

bool isa(CodeGen::Address addr)

@ Result

The result type of a method or function.

const FunctionProtoType * T

U cast(CodeGen::Address addr)

int const char * function

__UINTPTR_TYPE__ uintptr_t

An unsigned integer type with the property that any valid pointer to void can be converted to this ty...

unsigned Base

Start of the current subfield.

Block * Pointee

The block the pointer is pointing to.

Describes a memory block created by an allocation site.

unsigned getNumElems() const

Returns the number of elements stored in the block.

QualType getElemQualType() const

const ValueDecl * asValueDecl() const

const Decl * asDecl() const

unsigned getMetadataSize() const

Returns the size of the metadata.

QualType getDataType(const ASTContext &Ctx) const

const bool IsArray

Flag indicating if the block is an array.

bool isPrimitiveArray() const

Checks if the descriptor is of an array of primitives.

const FieldDecl * asFieldDecl() const

const Expr * asExpr() const

Descriptor used for global variables.

GlobalInitState InitState

unsigned IsActive

Flag indicating if the field is the active member of a union.

unsigned Offset

Offset inside the structure/array.

std::optional< IntPointer > atOffset(const ASTContext &ASTCtx, unsigned Offset) const

Definition Pointer.cpp:894

IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const

Definition Pointer.cpp:924

const Type * TypeInfoType