clang: lib/AST/ByteCode/Pointer.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
21
22using namespace clang;
24
26 : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
27 Pointee->getDescriptor()->getMetadataSize()) {}
28
30 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
31
33 : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
34 StorageKind(P.StorageKind) {
35
37 PointeeStorage.BS.Pointee->addPointer(this);
38}
39
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
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
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
70
71
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
107
108
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
146
149 false, true);
151 return APValue(static_cast<const Expr *>(nullptr),
154 false, false);
157
164 }
165
166
169 if (const auto *VD = Desc->asValueDecl())
171 else if (const auto *E = Desc->asExpr()) {
172
173 if (const auto *NewExpr = dyn_cast(E)) {
175 if (NewExpr->isArray()) {
177 APInt ArraySize(64, static_cast<uint64_t>(Desc->getNumElems()),
178 false);
179 AllocatedType =
182 } else {
183 AllocatedType = NewExpr->getAllocatedType();
184 }
185
186
187 static int ReportedDynamicAllocs = 0;
190 } else {
192 }
193 } else
194 llvm_unreachable("Invalid allocation type");
195
198 isOnePastEnd(), false);
199
201
203
204
205 if (FD->getParent()->isInvalidDecl())
208 unsigned FieldIndex = FD->getFieldIndex();
210 };
211
212
215
217
220 unsigned Index = Ptr.getIndex();
225 } else {
228
229 if (const auto *FD =
232
234 }
237 unsigned Index;
240 else
242
247 } else {
248 bool IsVirtual = false;
249
250
252 if (const auto *BaseOrMember = Desc->asDecl()) {
253 if (const auto *FD = dyn_cast(BaseOrMember)) {
256 } else if (const auto *RD = dyn_cast(BaseOrMember)) {
260
262 cast(BaseRecord->getDecl()));
263 if (IsVirtual)
265 else
267
268 } else {
270 }
272 continue;
273 }
274 llvm_unreachable("Invalid field type");
275 }
276 }
277
278
279
280
281
282 std::reverse(Path.begin(), Path.end());
283
285 false);
286}
287
289 switch (StorageKind) {
291 const Block *B = PointeeStorage.BS.Pointee;
292 OS << "(Block) " << B << " {";
293
295 OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
296 else
297 OS << PointeeStorage.BS.Base << ", ";
298
300 OS << "pastend, ";
301 else
302 OS << Offset << ", ";
303
304 if (B)
306 else
307 OS << "nullptr";
308 OS << "}";
309 } break;
311 OS << "(Int) {";
312 OS << PointeeStorage.Int.Value << " + " << Offset << ", "
313 << PointeeStorage.Int.Desc;
314 OS << "}";
315 break;
318 << " }";
319 break;
321 OS << "(Typeid)";
322 }
323}
324
327 return "nullptr";
328
330 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
331
333}
334
337 return true;
338
343 }
344
345 assert(PointeeStorage.BS.Pointee &&
346 "Cannot check if null pointer was initialized");
348 assert(Desc);
350 if (isStatic() && PointeeStorage.BS.Base == 0)
351 return true;
352
354
355 if (!IM)
356 return false;
357
358 if (IM->first)
359 return true;
360
361 return IM->second->isElementInitialized(getIndex());
362 }
363
365 return true;
366
367
369}
370
373 return;
374
375 assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
377
382 return;
383 }
384
385 assert(Desc);
387
388 if (isStatic() && PointeeStorage.BS.Base == 0)
389 return;
390
391
393 return;
394
396 if (!IM)
397 IM =
398 std::make_pair(false, std::make_shared(Desc->getNumElems()));
399
400 assert(IM);
401
402
403 if (IM->first)
404 return;
405
406 if (IM->second->initializeElement(getIndex())) {
407 IM->first = true;
408 IM->second.reset();
409 }
410 return;
411 }
412
413
414 assert(PointeeStorage.BS.Base != 0 &&
415 "Only composite fields can be initialised");
417}
418
420
421 assert(PointeeStorage.BS.Base != 0 &&
422 "Only composite fields can be activated");
423
425 return;
426 if (!getInlineDesc()->InUnion)
427 return;
428
429 getInlineDesc()->IsActive = true;
430
431
434 UnionPtr = UnionPtr.getBase();
435
437 for (const Record::Field &F : UnionRecord->fields()) {
439 if (FieldPtr == *this) {
440 } else {
441 FieldPtr.getInlineDesc()->IsActive = false;
442
443 }
444 }
445
448
449 B.getInlineDesc()->IsActive = true;
452 }
453}
454
456
457}
458
460
462 return true;
463
465 return true;
467 return true;
469 return true;
470
473
474 if (A.StorageKind != B.StorageKind)
475 return false;
476
478}
479
482 return false;
484}
485
488 A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
490}
491
494 return false;
495
497 return false;
498
500 return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
501}
502
506 assert(!ResultType.isNull());
507
509 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
511 if (const auto *AT = Ty->getAs<AtomicType>())
512 Ty = AT->getValueType();
513
514
515 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
516 Ptr.isPastEnd())
517 return false;
518
519
520 if (std::optional T = Ctx.classify(Ty)) {
521 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
522 return true;
523 }
524
525 if (const auto *RT = Ty->getAs<RecordType>()) {
526 const auto *Record = Ptr.getRecord();
527 assert(Record && "Missing record descriptor");
528
529 bool Ok = true;
530 if (RT->getDecl()->isUnion()) {
531 const FieldDecl *ActiveField = nullptr;
535 QualType FieldTy = F.Decl->getType();
537 if (std::optional T = Ctx.classify(FieldTy)) {
539 } else {
540 Ok &= Composite(FieldTy, FP, Value);
541 }
543 break;
544 }
545 }
547 } else {
551
553
554 for (unsigned I = 0; I < NF; ++I) {
556 QualType FieldTy = FD->Decl->getType();
559
560 if (std::optional T = Ctx.classify(FieldTy)) {
562 } else {
563 Ok &= Composite(FieldTy, FP, Value);
564 }
565 }
566
567 for (unsigned I = 0; I < NB; ++I) {
571 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
572 }
573
574 for (unsigned I = 0; I < NV; ++I) {
578 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
579 }
580 }
581 return Ok;
582 }
583
584 if (Ty->isIncompleteArrayType()) {
586 return true;
587 }
588
589 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
590 const size_t NumElems = Ptr.getNumElems();
591 QualType ElemTy = AT->getElementType();
593
594 bool Ok = true;
595 for (unsigned I = 0; I < NumElems; ++I) {
598 if (std::optional T = Ctx.classify(ElemTy)) {
600 } else {
601 Ok &= Composite(ElemTy, EP.narrow(), Slot);
602 }
603 }
604 return Ok;
605 }
606
607
608 if (const auto *CT = Ty->getAs<ComplexType>()) {
609 QualType ElemTy = CT->getElementType();
610
612 std::optional ElemT = Ctx.classify(ElemTy);
613 assert(ElemT);
615 auto V1 = Ptr.atIndex(0).deref();
616 auto V2 = Ptr.atIndex(1).deref();
617 R = APValue(V1.toAPSInt(), V2.toAPSInt());
618 return true;
619 });
623 return true;
624 }
625 return false;
626 }
627
628
629 if (const auto *VT = Ty->getAs<VectorType>()) {
630 assert(Ptr.getFieldDesc()->isPrimitiveArray());
631 QualType ElemTy = VT->getElementType();
633
635 Values.reserve(VT->getNumElements());
636 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
638 Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
639 });
640 }
641
642 assert(Values.size() == VT->getNumElements());
643 R = APValue(Values.data(), Values.size());
644 return true;
645 }
646
647 llvm_unreachable("invalid value to return");
648 };
649
650
652 return std::nullopt;
653
654
657
658
659 if (std::optional T = Ctx.classify(ResultType)) {
661 }
662
663
665 if (!Composite(ResultType, *this, Result))
666 return std::nullopt;
668}
669
671 unsigned Offset) const {
672 if (!this->Desc)
673 return *this;
675 if (!R)
676 return *this;
677
678 const Record::Field *F = nullptr;
679 for (auto &It : R->fields()) {
680 if (It.Offset == Offset) {
681 F = &It;
682 break;
683 }
684 }
685 if (!F)
686 return *this;
687
691 uint64_t FieldOffset =
695}
696
698 unsigned BaseOffset) const {
700 const Descriptor *BaseDesc = nullptr;
701
702
703
704 for (const Record::Base &B : R->bases()) {
705 if (B.Offset == BaseOffset) {
706 BaseDesc = B.Desc;
707 break;
708 }
709 }
710 assert(BaseDesc);
711
712
716
718}
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 ...
QualType getRecordType(const RecordDecl *Decl) const
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
QualType getConstantArrayType(QualType EltTy, const llvm::APInt &ArySize, const Expr *SizeExpr, ArraySizeModifier ASM, unsigned IndexTypeQuals) const
Return the unique reference to the type for a constant array of the specified element type.
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.
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.
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.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Symbolic representation of typeid(T) for some type T.
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
bool isFloatingType() const
Represents a GCC generic vector type.
A memory block, either on the stack or in the heap.
unsigned getSize() const
Returns the size of the block.
const Descriptor * getDescriptor() const
Returns the block's descriptor.
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
Holds all information required to evaluate constexpr code in a module.
ASTContext & getASTContext() const
Returns the AST context.
std::optional< PrimType > classify(QualType T) const
Classifies a type.
const APFloat & getAPFloat() const
const Function * getFunction() const
APValue toAPValue(const ASTContext &) const
A pointer to a memory block, live or dead.
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Pointer narrow() const
Restricts the scope of an array element pointer.
void deactivate() const
Deactivates an entire strurcutre.
bool isInitialized() const
Checks if an object was initialized.
bool isStatic() const
Checks if the storage is static.
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
bool isDummy() const
Checks if the pointer points to a dummy value.
void print(llvm::raw_ostream &OS) const
Prints the pointer.
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.
DeclTy getSource() const
Returns the expression or declaration the pointer has been created for.
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.
void operator=(const Pointer &P)
bool isIntegralPointer() const
QualType getType() const
Returns the type of the innermost field.
bool isArrayElement() const
Checks if the pointer points to an array.
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
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.
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.
bool isZero() const
Checks if the pointer is null.
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.
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
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.
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.
const FunctionPointer & asFunctionPointer() const
const Block * block() const
bool isFunctionPointer() const
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
bool isVirtualBaseClass() const
const BlockPointer & asBlockPointer() const
void initialize() const
Initializes a field.
bool isField() const
Checks if the item is a field in an object.
const Record * getRecord() const
Returns the record descriptor of a class.
Structure/Class descriptor.
const RecordDecl * getDecl() const
Returns the underlying declaration.
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.
std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr
PrimType
Enumeration of the primitive types of the VM.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
const FunctionProtoType * T
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
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 Record *const ElemRecord
Pointer to the record, if block contains records.
bool isUnion() const
Checks if the descriptor is of a union.
const Expr * asExpr() const
bool isArray() const
Checks if the descriptor is of an array.
Descriptor used for global variables.
GlobalInitState InitState
unsigned IsActive
Flag indicating if the field is the active member of a union.
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const