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 OS << PointeeStorage.BS.Pointee << " (";
269 if (isBlockPointer()) {
270 const Block *B = PointeeStorage.BS.Pointee;
271 OS << "Block) {";
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 } else {
288 OS << "Int) {";
289 OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc;
290 }
291 OS << "}";
292}
293
294std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
295 if (isZero())
296 return "nullptr";
297
298 if (isIntegralPointer())
299 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
300
301 return toAPValue(Ctx).getAsString(Ctx, getType());
302}
303
305 if (!isBlockPointer())
306 return true;
307
308 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
309 const GlobalInlineDescriptor &GD =
310 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
312 }
313
314 assert(PointeeStorage.BS.Pointee &&
315 "Cannot check if null pointer was initialized");
316 const Descriptor *Desc = getFieldDesc();
317 assert(Desc);
318 if (Desc->isPrimitiveArray()) {
319 if (isStatic() && PointeeStorage.BS.Base == 0)
320 return true;
321
322 InitMapPtr &IM = getInitMap();
323
324 if (!IM)
325 return false;
326
327 if (IM->first)
328 return true;
329
330 return IM->second->isElementInitialized(getIndex());
331 }
332
333 if (asBlockPointer().Base == 0)
334 return true;
335
336 // Field has its bit in an inline descriptor.
337 return getInlineDesc()->IsInitialized;
338}
339
341 if (!isBlockPointer())
342 return;
343
344 assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
345 const Descriptor *Desc = getFieldDesc();
346
347 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
348 GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
351 return;
352 }
353
354 assert(Desc);
355 if (Desc->isPrimitiveArray()) {
356 // Primitive global arrays don't have an initmap.
357 if (isStatic() && PointeeStorage.BS.Base == 0)
358 return;
359
360 // Nothing to do for these.
361 if (Desc->getNumElems() == 0)
362 return;
363
364 InitMapPtr &IM = getInitMap();
365 if (!IM)
366 IM =
367 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
368
369 assert(IM);
370
371 // All initialized.
372 if (IM->first)
373 return;
374
375 if (IM->second->initializeElement(getIndex())) {
376 IM->first = true;
377 IM->second.reset();
378 }
379 return;
380 }
381
382 // Field has its bit in an inline descriptor.
383 assert(PointeeStorage.BS.Base != 0 &&
384 "Only composite fields can be initialised");
385 getInlineDesc()->IsInitialized = true;
386}
387
388void Pointer::activate() const {
389 // Field has its bit in an inline descriptor.
390 assert(PointeeStorage.BS.Base != 0 &&
391 "Only composite fields can be activated");
392
393 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
394 return;
395 if (!getInlineDesc()->InUnion)
396 return;
397
398 getInlineDesc()->IsActive = true;
399
400 // Get the union, iterate over its fields and DEactivate all others.
401 Pointer UnionPtr = getBase();
402 while (!UnionPtr.getFieldDesc()->isUnion())
403 UnionPtr = UnionPtr.getBase();
404
405 const Record *UnionRecord = UnionPtr.getRecord();
406 for (const Record::Field &F : UnionRecord->fields()) {
407 Pointer FieldPtr = UnionPtr.atField(F.Offset);
408 if (FieldPtr == *this) {
409 } else {
410 FieldPtr.getInlineDesc()->IsActive = false;
411 // FIXME: Recurse.
412 }
413 }
414
415 Pointer B = getBase();
416 while (!B.isRoot() && B.inUnion()) {
417 // FIXME: Need to de-activate other fields of parent records.
418 B.getInlineDesc()->IsActive = true;
419 assert(B.isActive());
420 B = B.getBase();
421 }
422}
423
425 // TODO: this only appears in constructors, so nothing to deactivate.
426}
427
428bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
429 // Two null pointers always have the same base.
430 if (A.isZero() && B.isZero())
431 return true;
432
434 return true;
436 return true;
437
439 return A.getSource() == B.getSource();
440
441 if (A.StorageKind != B.StorageKind)
442 return false;
443
445}
446
447bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
448 if (!A.isBlockPointer() || !B.isBlockPointer())
449 return false;
450 return A.block() == B.block();
451}
452
453bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
454 return hasSameBase(A, B) &&
455 A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
457}
458
459std::optional<APValue> Pointer::toRValue(const Context &Ctx,
460 QualType ResultType) const {
461 const ASTContext &ASTCtx = Ctx.getASTContext();
462 assert(!ResultType.isNull());
463 // Method to recursively traverse composites.
464 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
465 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
466 APValue &R) {
467 if (const auto *AT = Ty->getAs<AtomicType>())
468 Ty = AT->getValueType();
469
470 // Invalid pointers.
471 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
472 Ptr.isPastEnd())
473 return false;
474
475 // Primitive values.
476 if (std::optional<PrimType> T = Ctx.classify(Ty)) {
477 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
478 return true;
479 }
480
481 if (const auto *RT = Ty->getAs<RecordType>()) {
482 const auto *Record = Ptr.getRecord();
483 assert(Record && "Missing record descriptor");
484
485 bool Ok = true;
486 if (RT->getDecl()->isUnion()) {
487 const FieldDecl *ActiveField = nullptr;
489 for (const auto &F : Record->fields()) {
490 const Pointer &FP = Ptr.atField(F.Offset);
491 QualType FieldTy = F.Decl->getType();
492 if (FP.isActive()) {
493 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
494 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
495 } else {
496 Ok &= Composite(FieldTy, FP, Value);
497 }
498 ActiveField = FP.getFieldDesc()->asFieldDecl();
499 break;
500 }
501 }
502 R = APValue(ActiveField, Value);
503 } else {
504 unsigned NF = Record->getNumFields();
505 unsigned NB = Record->getNumBases();
506 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
507
508 R = APValue(APValue::UninitStruct(), NB, NF);
509
510 for (unsigned I = 0; I < NF; ++I) {
511 const Record::Field *FD = Record->getField(I);
512 QualType FieldTy = FD->Decl->getType();
513 const Pointer &FP = Ptr.atField(FD->Offset);
514 APValue &Value = R.getStructField(I);
515
516 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
517 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
518 } else {
519 Ok &= Composite(FieldTy, FP, Value);
520 }
521 }
522
523 for (unsigned I = 0; I < NB; ++I) {
524 const Record::Base *BD = Record->getBase(I);
525 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
526 const Pointer &BP = Ptr.atField(BD->Offset);
527 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
528 }
529
530 for (unsigned I = 0; I < NV; ++I) {
531 const Record::Base *VD = Record->getVirtualBase(I);
532 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
533 const Pointer &VP = Ptr.atField(VD->Offset);
534 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
535 }
536 }
537 return Ok;
538 }
539
540 if (Ty->isIncompleteArrayType()) {
541 R = APValue(APValue::UninitArray(), 0, 0);
542 return true;
543 }
544
545 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
546 const size_t NumElems = Ptr.getNumElems();
547 QualType ElemTy = AT->getElementType();
548 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
549
550 bool Ok = true;
551 for (unsigned I = 0; I < NumElems; ++I) {
552 APValue &Slot = R.getArrayInitializedElt(I);
553 const Pointer &EP = Ptr.atIndex(I);
554 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
555 TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
556 } else {
557 Ok &= Composite(ElemTy, EP.narrow(), Slot);
558 }
559 }
560 return Ok;
561 }
562
563 // Complex types.
564 if (const auto *CT = Ty->getAs<ComplexType>()) {
565 QualType ElemTy = CT->getElementType();
566
567 if (ElemTy->isIntegerType()) {
568 std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
569 assert(ElemT);
570 INT_TYPE_SWITCH(*ElemT, {
571 auto V1 = Ptr.atIndex(0).deref<T>();
572 auto V2 = Ptr.atIndex(1).deref<T>();
573 R = APValue(V1.toAPSInt(), V2.toAPSInt());
574 return true;
575 });
576 } else if (ElemTy->isFloatingType()) {
577 R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
578 Ptr.atIndex(1).deref<Floating>().getAPFloat());
579 return true;
580 }
581 return false;
582 }
583
584 // Vector types.
585 if (const auto *VT = Ty->getAs<VectorType>()) {
586 assert(Ptr.getFieldDesc()->isPrimitiveArray());
587 QualType ElemTy = VT->getElementType();
588 PrimType ElemT = *Ctx.classify(ElemTy);
589
591 Values.reserve(VT->getNumElements());
592 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
593 TYPE_SWITCH(ElemT, {
594 Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
595 });
596 }
597
598 assert(Values.size() == VT->getNumElements());
599 R = APValue(Values.data(), Values.size());
600 return true;
601 }
602
603 llvm_unreachable("invalid value to return");
604 };
605
606 // Invalid to read from.
607 if (isDummy() || !isLive() || isPastEnd())
608 return std::nullopt;
609
610 // We can return these as rvalues, but we can't deref() them.
611 if (isZero() || isIntegralPointer())
612 return toAPValue(ASTCtx);
613
614 // Just load primitive types.
615 if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
616 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
617 }
618
619 // Return the composite type.
621 if (!Composite(getType(), *this, Result))
622 return std::nullopt;
623 return Result;
624}
625
627 unsigned Offset) const {
628 if (!this->Desc)
629 return *this;
630 const Record *R = this->Desc->ElemRecord;
631 if (!R)
632 return *this;
633
634 const Record::Field *F = nullptr;
635 for (auto &It : R->fields()) {
636 if (It.Offset == Offset) {
637 F = &It;
638 break;
639 }
640 }
641 if (!F)
642 return *this;
643
644 const FieldDecl *FD = F->Decl;
645 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
646 unsigned FieldIndex = FD->getFieldIndex();
647 uint64_t FieldOffset =
648 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
649 .getQuantity();
650 return IntPointer{this->Desc, FieldOffset};
651}
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:143
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:122
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:186
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:3134
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:3243
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:5965
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:8359
bool isFloatingType() const
Definition: Type.cpp:2249
Represents a GCC generic vector type.
Definition: Type.h:4021
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
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:428
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:424
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:304
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:619
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:388
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:294
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:447
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:453
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:728
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition: Pointer.cpp:459
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:340
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:416
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:626
const Descriptor * Desc
Definition: Pointer.h:45