clang 20.0.0git
Pointer.cpp
Go to the documentation of this file.
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"
21
22using namespace clang;
23using namespace clang::interp;
24
26 : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
27 Pointee->getDescriptor()->getMetadataSize()) {}
28
29Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
30 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
31
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
40Pointer::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
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
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
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 {
100 assert(false && "Unhandled storage kind");
101 }
102}
103
105 // If the current storage type is Block, we need to remove
106 // this pointer from the block.
107 if (isBlockPointer()) {
108 if (P.isBlockPointer() && this->block() == P.block()) {
109 Offset = P.Offset;
110 PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
111 return;
112 }
113
114 if (Block *Pointee = PointeeStorage.BS.Pointee) {
115 assert(P.block() != this->block());
116 Pointee->removePointer(this);
117 PointeeStorage.BS.Pointee = nullptr;
118 Pointee->cleanup();
119 }
120 }
121
122 StorageKind = P.StorageKind;
123 Offset = P.Offset;
124
125 if (P.isBlockPointer()) {
126 PointeeStorage.BS = P.PointeeStorage.BS;
127 PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
128
129 if (PointeeStorage.BS.Pointee)
130 PointeeStorage.BS.Pointee->addPointer(this);
131 } else if (P.isIntegralPointer()) {
132 PointeeStorage.Int = P.PointeeStorage.Int;
133 } else if (P.isFunctionPointer()) {
134 PointeeStorage.Fn = P.PointeeStorage.Fn;
135 } else {
136 assert(false && "Unhandled storage kind");
137 }
138}
139
142
143 if (isZero())
144 return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
145 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
146 if (isIntegralPointer())
147 return APValue(static_cast<const Expr *>(nullptr),
149 Path,
150 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
151 if (isFunctionPointer())
152 return asFunctionPointer().toAPValue(ASTCtx);
153
154 // Build the lvalue base from the block.
155 const Descriptor *Desc = getDeclDesc();
157 if (const auto *VD = Desc->asValueDecl())
158 Base = VD;
159 else if (const auto *E = Desc->asExpr()) {
160 // Create a DynamicAlloc base of the right type.
161 if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
162 QualType AllocatedType;
163 if (NewExpr->isArray()) {
164 assert(Desc->isArray());
165 APInt ArraySize(64, static_cast<uint64_t>(Desc->getNumElems()),
166 /*IsSigned=*/false);
167 AllocatedType =
168 ASTCtx.getConstantArrayType(NewExpr->getAllocatedType(), ArraySize,
169 nullptr, ArraySizeModifier::Normal, 0);
170 } else {
171 AllocatedType = NewExpr->getAllocatedType();
172 }
173 // FIXME: Suboptimal counting of dynamic allocations. Move this to Context
174 // or InterpState?
175 static int ReportedDynamicAllocs = 0;
176 DynamicAllocLValue DA(ReportedDynamicAllocs++);
177 Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
178 } else {
179 Base = E;
180 }
181 } else
182 llvm_unreachable("Invalid allocation type");
183
184 if (isUnknownSizeArray())
185 return APValue(Base, CharUnits::Zero(), Path,
186 /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
187
188 CharUnits Offset = CharUnits::Zero();
189
190 auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
191 // This shouldn't happen, but if it does, don't crash inside
192 // getASTRecordLayout.
193 if (FD->getParent()->isInvalidDecl())
194 return CharUnits::Zero();
195 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
196 unsigned FieldIndex = FD->getFieldIndex();
197 return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
198 };
199
200 // Build the path into the object.
201 Pointer Ptr = *this;
202 while (Ptr.isField() || Ptr.isArrayElement()) {
203 if (Ptr.isArrayRoot()) {
205 {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));
206
207 if (const auto *FD = dyn_cast<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
208 Offset += getFieldOffset(FD);
209
210 Ptr = Ptr.getBase();
211 } else if (Ptr.isArrayElement()) {
212 unsigned Index;
213 if (Ptr.isOnePastEnd())
214 Index = Ptr.getArray().getNumElems();
215 else
216 Index = Ptr.getIndex();
217
218 Offset += (Index * ASTCtx.getTypeSizeInChars(Ptr.getType()));
220 Ptr = Ptr.getArray();
221 } else {
222 bool IsVirtual = false;
223
224 // Create a path entry for the field.
225 const Descriptor *Desc = Ptr.getFieldDesc();
226 if (const auto *BaseOrMember = Desc->asDecl()) {
227 if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
228 Ptr = Ptr.getBase();
229 Offset += getFieldOffset(FD);
230 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
231 IsVirtual = Ptr.isVirtualBaseClass();
232 Ptr = Ptr.getBase();
233 const Record *BaseRecord = Ptr.getRecord();
234
235 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
236 cast<CXXRecordDecl>(BaseRecord->getDecl()));
237 if (IsVirtual)
238 Offset += Layout.getVBaseClassOffset(RD);
239 else
240 Offset += Layout.getBaseClassOffset(RD);
241
242 } else {
243 Ptr = Ptr.getBase();
244 }
245 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
246 continue;
247 }
248 llvm_unreachable("Invalid field type");
249 }
250 }
251
252 // FIXME(perf): We compute the lvalue path above, but we can't supply it
253 // for dummy pointers (that causes crashes later in CheckConstantExpression).
254 if (isDummy())
255 Path.clear();
256
257 // We assemble the LValuePath starting from the innermost pointer to the
258 // outermost one. SO in a.b.c, the first element in Path will refer to
259 // the field 'c', while later code expects it to refer to 'a'.
260 // Just invert the order of the elements.
261 std::reverse(Path.begin(), Path.end());
262
263 return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
264 /*IsNullPtr=*/false);
265}
266
267void Pointer::print(llvm::raw_ostream &OS) const {
268 switch (StorageKind) {
269 case Storage::Block: {
270 const Block *B = PointeeStorage.BS.Pointee;
271 OS << "(Block) " << B << " {";
272
273 if (isRoot())
274 OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
275 else
276 OS << PointeeStorage.BS.Base << ", ";
277
278 if (isElementPastEnd())
279 OS << "pastend, ";
280 else
281 OS << Offset << ", ";
282
283 if (B)
284 OS << B->getSize();
285 else
286 OS << "nullptr";
287 OS << "}";
288 } break;
289 case Storage::Int:
290 OS << "(Int) {";
291 OS << PointeeStorage.Int.Value << " + " << Offset << ", "
292 << PointeeStorage.Int.Desc;
293 OS << "}";
294 break;
295 case Storage::Fn:
296 OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
297 << " }";
298 }
299}
300
301std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
302 if (isZero())
303 return "nullptr";
304
305 if (isIntegralPointer())
306 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
307
308 return toAPValue(Ctx).getAsString(Ctx, getType());
309}
310
312 if (!isBlockPointer())
313 return true;
314
315 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
316 const GlobalInlineDescriptor &GD =
317 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
319 }
320
321 assert(PointeeStorage.BS.Pointee &&
322 "Cannot check if null pointer was initialized");
323 const Descriptor *Desc = getFieldDesc();
324 assert(Desc);
325 if (Desc->isPrimitiveArray()) {
326 if (isStatic() && PointeeStorage.BS.Base == 0)
327 return true;
328
329 InitMapPtr &IM = getInitMap();
330
331 if (!IM)
332 return false;
333
334 if (IM->first)
335 return true;
336
337 return IM->second->isElementInitialized(getIndex());
338 }
339
340 if (asBlockPointer().Base == 0)
341 return true;
342
343 // Field has its bit in an inline descriptor.
344 return getInlineDesc()->IsInitialized;
345}
346
348 if (!isBlockPointer())
349 return;
350
351 assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
352 const Descriptor *Desc = getFieldDesc();
353
354 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
355 GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
358 return;
359 }
360
361 assert(Desc);
362 if (Desc->isPrimitiveArray()) {
363 // Primitive global arrays don't have an initmap.
364 if (isStatic() && PointeeStorage.BS.Base == 0)
365 return;
366
367 // Nothing to do for these.
368 if (Desc->getNumElems() == 0)
369 return;
370
371 InitMapPtr &IM = getInitMap();
372 if (!IM)
373 IM =
374 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
375
376 assert(IM);
377
378 // All initialized.
379 if (IM->first)
380 return;
381
382 if (IM->second->initializeElement(getIndex())) {
383 IM->first = true;
384 IM->second.reset();
385 }
386 return;
387 }
388
389 // Field has its bit in an inline descriptor.
390 assert(PointeeStorage.BS.Base != 0 &&
391 "Only composite fields can be initialised");
392 getInlineDesc()->IsInitialized = true;
393}
394
395void Pointer::activate() const {
396 // Field has its bit in an inline descriptor.
397 assert(PointeeStorage.BS.Base != 0 &&
398 "Only composite fields can be activated");
399
400 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
401 return;
402 if (!getInlineDesc()->InUnion)
403 return;
404
405 getInlineDesc()->IsActive = true;
406
407 // Get the union, iterate over its fields and DEactivate all others.
408 Pointer UnionPtr = getBase();
409 while (!UnionPtr.getFieldDesc()->isUnion())
410 UnionPtr = UnionPtr.getBase();
411
412 const Record *UnionRecord = UnionPtr.getRecord();
413 for (const Record::Field &F : UnionRecord->fields()) {
414 Pointer FieldPtr = UnionPtr.atField(F.Offset);
415 if (FieldPtr == *this) {
416 } else {
417 FieldPtr.getInlineDesc()->IsActive = false;
418 // FIXME: Recurse.
419 }
420 }
421
422 Pointer B = getBase();
423 while (!B.isRoot() && B.inUnion()) {
424 // FIXME: Need to de-activate other fields of parent records.
425 B.getInlineDesc()->IsActive = true;
426 assert(B.isActive());
427 B = B.getBase();
428 }
429}
430
432 // TODO: this only appears in constructors, so nothing to deactivate.
433}
434
435bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
436 // Two null pointers always have the same base.
437 if (A.isZero() && B.isZero())
438 return true;
439
441 return true;
443 return true;
444
446 return A.getSource() == B.getSource();
447
448 if (A.StorageKind != B.StorageKind)
449 return false;
450
452}
453
454bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
455 if (!A.isBlockPointer() || !B.isBlockPointer())
456 return false;
457 return A.block() == B.block();
458}
459
460bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
461 return hasSameBase(A, B) &&
462 A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
464}
465
466std::optional<APValue> Pointer::toRValue(const Context &Ctx,
467 QualType ResultType) const {
468 const ASTContext &ASTCtx = Ctx.getASTContext();
469 assert(!ResultType.isNull());
470 // Method to recursively traverse composites.
471 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
472 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
473 APValue &R) {
474 if (const auto *AT = Ty->getAs<AtomicType>())
475 Ty = AT->getValueType();
476
477 // Invalid pointers.
478 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
479 Ptr.isPastEnd())
480 return false;
481
482 // Primitive values.
483 if (std::optional<PrimType> T = Ctx.classify(Ty)) {
484 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
485 return true;
486 }
487
488 if (const auto *RT = Ty->getAs<RecordType>()) {
489 const auto *Record = Ptr.getRecord();
490 assert(Record && "Missing record descriptor");
491
492 bool Ok = true;
493 if (RT->getDecl()->isUnion()) {
494 const FieldDecl *ActiveField = nullptr;
496 for (const auto &F : Record->fields()) {
497 const Pointer &FP = Ptr.atField(F.Offset);
498 QualType FieldTy = F.Decl->getType();
499 if (FP.isActive()) {
500 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
501 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
502 } else {
503 Ok &= Composite(FieldTy, FP, Value);
504 }
505 ActiveField = FP.getFieldDesc()->asFieldDecl();
506 break;
507 }
508 }
509 R = APValue(ActiveField, Value);
510 } else {
511 unsigned NF = Record->getNumFields();
512 unsigned NB = Record->getNumBases();
513 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
514
515 R = APValue(APValue::UninitStruct(), NB, NF);
516
517 for (unsigned I = 0; I < NF; ++I) {
518 const Record::Field *FD = Record->getField(I);
519 QualType FieldTy = FD->Decl->getType();
520 const Pointer &FP = Ptr.atField(FD->Offset);
521 APValue &Value = R.getStructField(I);
522
523 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
524 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
525 } else {
526 Ok &= Composite(FieldTy, FP, Value);
527 }
528 }
529
530 for (unsigned I = 0; I < NB; ++I) {
531 const Record::Base *BD = Record->getBase(I);
532 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
533 const Pointer &BP = Ptr.atField(BD->Offset);
534 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
535 }
536
537 for (unsigned I = 0; I < NV; ++I) {
538 const Record::Base *VD = Record->getVirtualBase(I);
539 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
540 const Pointer &VP = Ptr.atField(VD->Offset);
541 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
542 }
543 }
544 return Ok;
545 }
546
547 if (Ty->isIncompleteArrayType()) {
548 R = APValue(APValue::UninitArray(), 0, 0);
549 return true;
550 }
551
552 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
553 const size_t NumElems = Ptr.getNumElems();
554 QualType ElemTy = AT->getElementType();
555 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
556
557 bool Ok = true;
558 for (unsigned I = 0; I < NumElems; ++I) {
559 APValue &Slot = R.getArrayInitializedElt(I);
560 const Pointer &EP = Ptr.atIndex(I);
561 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
562 TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
563 } else {
564 Ok &= Composite(ElemTy, EP.narrow(), Slot);
565 }
566 }
567 return Ok;
568 }
569
570 // Complex types.
571 if (const auto *CT = Ty->getAs<ComplexType>()) {
572 QualType ElemTy = CT->getElementType();
573
574 if (ElemTy->isIntegerType()) {
575 std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
576 assert(ElemT);
577 INT_TYPE_SWITCH(*ElemT, {
578 auto V1 = Ptr.atIndex(0).deref<T>();
579 auto V2 = Ptr.atIndex(1).deref<T>();
580 R = APValue(V1.toAPSInt(), V2.toAPSInt());
581 return true;
582 });
583 } else if (ElemTy->isFloatingType()) {
584 R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
585 Ptr.atIndex(1).deref<Floating>().getAPFloat());
586 return true;
587 }
588 return false;
589 }
590
591 // Vector types.
592 if (const auto *VT = Ty->getAs<VectorType>()) {
593 assert(Ptr.getFieldDesc()->isPrimitiveArray());
594 QualType ElemTy = VT->getElementType();
595 PrimType ElemT = *Ctx.classify(ElemTy);
596
598 Values.reserve(VT->getNumElements());
599 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
600 TYPE_SWITCH(ElemT, {
601 Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
602 });
603 }
604
605 assert(Values.size() == VT->getNumElements());
606 R = APValue(Values.data(), Values.size());
607 return true;
608 }
609
610 llvm_unreachable("invalid value to return");
611 };
612
613 // Invalid to read from.
614 if (isDummy() || !isLive() || isPastEnd())
615 return std::nullopt;
616
617 // We can return these as rvalues, but we can't deref() them.
618 if (isZero() || isIntegralPointer())
619 return toAPValue(ASTCtx);
620
621 // Just load primitive types.
622 if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
623 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
624 }
625
626 // Return the composite type.
628 if (!Composite(getType(), *this, Result))
629 return std::nullopt;
630 return Result;
631}
632
634 unsigned Offset) const {
635 if (!this->Desc)
636 return *this;
637 const Record *R = this->Desc->ElemRecord;
638 if (!R)
639 return *this;
640
641 const Record::Field *F = nullptr;
642 for (auto &It : R->fields()) {
643 if (It.Offset == Offset) {
644 F = &It;
645 break;
646 }
647 }
648 if (!F)
649 return *this;
650
651 const FieldDecl *FD = F->Decl;
652 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
653 unsigned FieldIndex = FD->getFieldIndex();
654 uint64_t FieldOffset =
655 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
656 .getQuantity();
657 return IntPointer{this->Desc, this->Value + FieldOffset};
658}
StringRef P
IndirectLocalPath & Path
Expr * E
Defines the clang::Expr interface and subclasses for C++ expressions.
#define INT_TYPE_SWITCH(Expr, B)
Definition: PrimType.h:169
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:148
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD)
static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type)
Definition: APValue.cpp:47
A non-discriminated union of a base, field, or array index.
Definition: APValue.h:208
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition: APValue.h:216
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
APValue & getArrayInitializedElt(unsigned I)
Definition: APValue.h:510
std::string getAsString(const ASTContext &Ctx, QualType Ty) const
Definition: APValue.cpp:946
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:187
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/...
Definition: RecordLayout.h:38
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
Definition: RecordLayout.h:200
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:249
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:259
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition: CharUnits.h:185
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition: CharUnits.h:53
Complex values, per C99 6.2.5p11.
Definition: Type.h:3139
Decl()=delete
Symbolic representation of a dynamic allocation.
Definition: APValue.h:65
This represents one expression.
Definition: Expr.h:110
Represents a member of a struct/union/class.
Definition: Decl.h:3030
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition: Decl.cpp:4630
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition: Decl.h:3247
A (possibly-)qualified type.
Definition: Type.h:941
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:1008
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:5970
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:8364
bool isFloatingType() const
Definition: Type.cpp:2249
Represents a GCC generic vector type.
Definition: Type.h:4026
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:49
unsigned getSize() const
Returns the size of the block.
Definition: InterpBlock.h:78
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
Definition: InterpBlock.h:102
Holds all information required to evaluate constexpr code in a module.
Definition: Context.h:40
ASTContext & getASTContext() const
Returns the AST context.
Definition: Context.h:61
std::optional< PrimType > classify(QualType T) const
Classifies a type.
Definition: Context.cpp:130
const APFloat & getAPFloat() const
Definition: Floating.h:40
const Function * getFunction() const
APValue toAPValue(const ASTContext &) const
A pointer to a memory block, live or dead.
Definition: Pointer.h:82
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:435
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:183
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:431
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:311
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:480
bool inUnion() const
Definition: Pointer.h:403
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:149
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:527
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition: Pointer.cpp:267
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:572
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:516
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:168
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:623
DeclTy getSource() const
Returns the expression or declaration the pointer has been created for.
Definition: Pointer.h:296
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:563
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:317
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:416
void activate() const
Activats a field.
Definition: Pointer.cpp:395
void operator=(const Pointer &P)
Definition: Pointer.cpp:69
bool isIntegralPointer() const
Definition: Pointer.h:457
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:338
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:422
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:393
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:269
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:308
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:301
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:260
const IntPointer & asIntPointer() const
Definition: Pointer.h:447
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:428
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:283
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition: Pointer.cpp:454
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
Definition: Pointer.cpp:140
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:590
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:460
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition: Pointer.h:605
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:613
bool isBlockPointer() const
Definition: Pointer.h:456
BlockPointer BS
Definition: Pointer.h:732
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition: Pointer.cpp:466
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:451
const Block * block() const
Definition: Pointer.h:569
bool isFunctionPointer() const
Definition: Pointer.h:458
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:328
bool isVirtualBaseClass() const
Definition: Pointer.h:523
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:443
void initialize() const
Initializes a field.
Definition: Pointer.cpp:347
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:275
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:461
Structure/Class descriptor.
Definition: Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition: Record.h:52
unsigned getNumBases() const
Definition: Record.h:89
const Field * getField(const FieldDecl *FD) const
Returns a field.
Definition: Record.cpp:39
const Base * getVirtualBase(const RecordDecl *RD) const
Returns a virtual base descriptor.
Definition: Record.cpp:59
unsigned getNumFields() const
Definition: Record.h:81
unsigned getNumVirtualBases() const
Definition: Record.h:100
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:77
const Base * getBase(const RecordDecl *FD) const
Returns a base descriptor.
Definition: Record.cpp:45
std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr
Definition: Descriptor.h:29
llvm::APInt APInt
Definition: Integral.h:29
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:33
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
const FunctionProtoType * T
#define bool
Definition: stdbool.h:24
unsigned Base
Start of the current subfield.
Definition: Pointer.h:41
Block * Pointee
The block the pointer is pointing to.
Definition: Pointer.h:39
Describes a memory block created by an allocation site.
Definition: Descriptor.h:111
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:237
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:202
const Decl * asDecl() const
Definition: Descriptor.h:198
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:155
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:242
const FieldDecl * asFieldDecl() const
Definition: Descriptor.h:210
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:141
bool isUnion() const
Checks if the descriptor is of a union.
Definition: Descriptor.cpp:424
const Expr * asExpr() const
Definition: Descriptor.h:199
bool isArray() const
Checks if the descriptor is of an array.
Definition: Descriptor.h:254
Descriptor used for global variables.
Definition: Descriptor.h:58
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition: Descriptor.h:91
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition: Descriptor.h:82
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:633
const Descriptor * Desc
Definition: Pointer.h:45