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"
20
21using namespace clang;
22using namespace clang::interp;
23
25 : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
26 Pointee->getDescriptor()->getMetadataSize()) {}
27
28Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
29 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
30
32 : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
33 StorageKind(P.StorageKind) {
34
35 if (isBlockPointer() && PointeeStorage.BS.Pointee)
36 PointeeStorage.BS.Pointee->addPointer(this);
37}
38
39Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
40 : Offset(Offset), StorageKind(Storage::Block) {
41 assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
42
43 PointeeStorage.BS = {Pointee, Base};
44
45 if (Pointee)
46 Pointee->addPointer(this);
47}
48
50 : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
51 StorageKind(P.StorageKind) {
52
53 if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
54 PointeeStorage.BS.Pointee->replacePointer(&P, this);
55}
56
58 if (!isBlockPointer())
59 return;
60
61 if (Block *Pointee = PointeeStorage.BS.Pointee) {
62 Pointee->removePointer(this);
63 Pointee->cleanup();
64 }
65}
66
68 // If the current storage type is Block, we need to remove
69 // this pointer from the block.
70 bool WasBlockPointer = isBlockPointer();
71 if (StorageKind == Storage::Block) {
72 Block *Old = PointeeStorage.BS.Pointee;
73 if (WasBlockPointer && Old) {
74 PointeeStorage.BS.Pointee->removePointer(this);
75 Old->cleanup();
76 }
77 }
78
79 StorageKind = P.StorageKind;
80 Offset = P.Offset;
81
82 if (P.isBlockPointer()) {
83 PointeeStorage.BS = P.PointeeStorage.BS;
84 PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
85
86 if (PointeeStorage.BS.Pointee)
87 PointeeStorage.BS.Pointee->addPointer(this);
88 } else if (P.isIntegralPointer()) {
89 PointeeStorage.Int = P.PointeeStorage.Int;
90 } else if (P.isFunctionPointer()) {
91 PointeeStorage.Fn = P.PointeeStorage.Fn;
92 } else {
93 assert(false && "Unhandled storage kind");
94 }
95}
96
98 // If the current storage type is Block, we need to remove
99 // this pointer from the block.
100 bool WasBlockPointer = isBlockPointer();
101 if (StorageKind == Storage::Block) {
102 Block *Old = PointeeStorage.BS.Pointee;
103 if (WasBlockPointer && Old) {
104 PointeeStorage.BS.Pointee->removePointer(this);
105 Old->cleanup();
106 }
107 }
108
109 StorageKind = P.StorageKind;
110 Offset = P.Offset;
111
112 if (P.isBlockPointer()) {
113 PointeeStorage.BS = P.PointeeStorage.BS;
114 PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
115
116 if (PointeeStorage.BS.Pointee)
117 PointeeStorage.BS.Pointee->addPointer(this);
118 } else if (P.isIntegralPointer()) {
119 PointeeStorage.Int = P.PointeeStorage.Int;
120 } else if (P.isFunctionPointer()) {
121 PointeeStorage.Fn = P.PointeeStorage.Fn;
122 } else {
123 assert(false && "Unhandled storage kind");
124 }
125}
126
129
130 if (isZero())
131 return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
132 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
133 if (isIntegralPointer())
134 return APValue(static_cast<const Expr *>(nullptr),
136 Path,
137 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
138 if (isFunctionPointer())
139 return asFunctionPointer().toAPValue(ASTCtx);
140
141 // Build the lvalue base from the block.
142 const Descriptor *Desc = getDeclDesc();
144 if (const auto *VD = Desc->asValueDecl())
145 Base = VD;
146 else if (const auto *E = Desc->asExpr())
147 Base = E;
148 else
149 llvm_unreachable("Invalid allocation type");
150
151 if (isUnknownSizeArray() || Desc->asExpr())
152 return APValue(Base, CharUnits::Zero(), Path,
153 /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
154
155 CharUnits Offset = CharUnits::Zero();
156
157 auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
158 // This shouldn't happen, but if it does, don't crash inside
159 // getASTRecordLayout.
160 if (FD->getParent()->isInvalidDecl())
161 return CharUnits::Zero();
162 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
163 unsigned FieldIndex = FD->getFieldIndex();
164 return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
165 };
166
167 // Build the path into the object.
168 Pointer Ptr = *this;
169 while (Ptr.isField() || Ptr.isArrayElement()) {
170 if (Ptr.isArrayRoot()) {
172 {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));
173
174 if (const auto *FD = dyn_cast<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
175 Offset += getFieldOffset(FD);
176
177 Ptr = Ptr.getBase();
178 } else if (Ptr.isArrayElement()) {
179 unsigned Index;
180 if (Ptr.isOnePastEnd())
181 Index = Ptr.getArray().getNumElems();
182 else
183 Index = Ptr.getIndex();
184
185 Offset += (Index * ASTCtx.getTypeSizeInChars(Ptr.getType()));
187 Ptr = Ptr.getArray();
188 } else {
189 bool IsVirtual = false;
190
191 // Create a path entry for the field.
192 const Descriptor *Desc = Ptr.getFieldDesc();
193 if (const auto *BaseOrMember = Desc->asDecl()) {
194 if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
195 Ptr = Ptr.getBase();
196 Offset += getFieldOffset(FD);
197 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
198 IsVirtual = Ptr.isVirtualBaseClass();
199 Ptr = Ptr.getBase();
200 const Record *BaseRecord = Ptr.getRecord();
201
202 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
203 cast<CXXRecordDecl>(BaseRecord->getDecl()));
204 if (IsVirtual)
205 Offset += Layout.getVBaseClassOffset(RD);
206 else
207 Offset += Layout.getBaseClassOffset(RD);
208
209 } else {
210 Ptr = Ptr.getBase();
211 }
212 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
213 continue;
214 }
215 llvm_unreachable("Invalid field type");
216 }
217 }
218
219 // FIXME(perf): We compute the lvalue path above, but we can't supply it
220 // for dummy pointers (that causes crashes later in CheckConstantExpression).
221 if (isDummy())
222 Path.clear();
223
224 // We assemble the LValuePath starting from the innermost pointer to the
225 // outermost one. SO in a.b.c, the first element in Path will refer to
226 // the field 'c', while later code expects it to refer to 'a'.
227 // Just invert the order of the elements.
228 std::reverse(Path.begin(), Path.end());
229
230 return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
231 /*IsNullPtr=*/false);
232}
233
234void Pointer::print(llvm::raw_ostream &OS) const {
235 OS << PointeeStorage.BS.Pointee << " (";
236 if (isBlockPointer()) {
237 const Block *B = PointeeStorage.BS.Pointee;
238 OS << "Block) {";
239
240 if (isRoot())
241 OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
242 else
243 OS << PointeeStorage.BS.Base << ", ";
244
245 if (isElementPastEnd())
246 OS << "pastend, ";
247 else
248 OS << Offset << ", ";
249
250 if (B)
251 OS << B->getSize();
252 else
253 OS << "nullptr";
254 } else {
255 OS << "Int) {";
256 OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc;
257 }
258 OS << "}";
259}
260
261std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
262 if (isZero())
263 return "nullptr";
264
265 if (isIntegralPointer())
266 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
267
268 return toAPValue(Ctx).getAsString(Ctx, getType());
269}
270
272 if (!isBlockPointer())
273 return true;
274
275 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
276 const GlobalInlineDescriptor &GD =
277 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
279 }
280
281 assert(PointeeStorage.BS.Pointee &&
282 "Cannot check if null pointer was initialized");
283 const Descriptor *Desc = getFieldDesc();
284 assert(Desc);
285 if (Desc->isPrimitiveArray()) {
286 if (isStatic() && PointeeStorage.BS.Base == 0)
287 return true;
288
289 InitMapPtr &IM = getInitMap();
290
291 if (!IM)
292 return false;
293
294 if (IM->first)
295 return true;
296
297 return IM->second->isElementInitialized(getIndex());
298 }
299
300 if (asBlockPointer().Base == 0)
301 return true;
302
303 // Field has its bit in an inline descriptor.
304 return getInlineDesc()->IsInitialized;
305}
306
308 if (!isBlockPointer())
309 return;
310
311 assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
312 const Descriptor *Desc = getFieldDesc();
313
314 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
315 GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
318 return;
319 }
320
321 assert(Desc);
322 if (Desc->isPrimitiveArray()) {
323 // Primitive global arrays don't have an initmap.
324 if (isStatic() && PointeeStorage.BS.Base == 0)
325 return;
326
327 // Nothing to do for these.
328 if (Desc->getNumElems() == 0)
329 return;
330
331 InitMapPtr &IM = getInitMap();
332 if (!IM)
333 IM =
334 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
335
336 assert(IM);
337
338 // All initialized.
339 if (IM->first)
340 return;
341
342 if (IM->second->initializeElement(getIndex())) {
343 IM->first = true;
344 IM->second.reset();
345 }
346 return;
347 }
348
349 // Field has its bit in an inline descriptor.
350 assert(PointeeStorage.BS.Base != 0 &&
351 "Only composite fields can be initialised");
352 getInlineDesc()->IsInitialized = true;
353}
354
355void Pointer::activate() const {
356 // Field has its bit in an inline descriptor.
357 assert(PointeeStorage.BS.Base != 0 &&
358 "Only composite fields can be initialised");
359
360 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
361 return;
362
363 getInlineDesc()->IsActive = true;
364}
365
367 // TODO: this only appears in constructors, so nothing to deactivate.
368}
369
370bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
371 // Two null pointers always have the same base.
372 if (A.isZero() && B.isZero())
373 return true;
374
376 return true;
378 return true;
379
381 return A.getSource() == B.getSource();
382
383 if (A.StorageKind != B.StorageKind)
384 return false;
385
387}
388
389bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
390 return hasSameBase(A, B) &&
391 A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
393}
394
395std::optional<APValue> Pointer::toRValue(const Context &Ctx,
396 QualType ResultType) const {
397 const ASTContext &ASTCtx = Ctx.getASTContext();
398 assert(!ResultType.isNull());
399 // Method to recursively traverse composites.
400 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
401 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
402 APValue &R) {
403 if (const auto *AT = Ty->getAs<AtomicType>())
404 Ty = AT->getValueType();
405
406 // Invalid pointers.
407 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
408 Ptr.isPastEnd())
409 return false;
410
411 // Primitive values.
412 if (std::optional<PrimType> T = Ctx.classify(Ty)) {
413 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
414 return true;
415 }
416
417 if (const auto *RT = Ty->getAs<RecordType>()) {
418 const auto *Record = Ptr.getRecord();
419 assert(Record && "Missing record descriptor");
420
421 bool Ok = true;
422 if (RT->getDecl()->isUnion()) {
423 const FieldDecl *ActiveField = nullptr;
425 for (const auto &F : Record->fields()) {
426 const Pointer &FP = Ptr.atField(F.Offset);
427 QualType FieldTy = F.Decl->getType();
428 if (FP.isActive()) {
429 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
430 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
431 } else {
432 Ok &= Composite(FieldTy, FP, Value);
433 }
434 ActiveField = FP.getFieldDesc()->asFieldDecl();
435 break;
436 }
437 }
438 R = APValue(ActiveField, Value);
439 } else {
440 unsigned NF = Record->getNumFields();
441 unsigned NB = Record->getNumBases();
442 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
443
444 R = APValue(APValue::UninitStruct(), NB, NF);
445
446 for (unsigned I = 0; I < NF; ++I) {
447 const Record::Field *FD = Record->getField(I);
448 QualType FieldTy = FD->Decl->getType();
449 const Pointer &FP = Ptr.atField(FD->Offset);
450 APValue &Value = R.getStructField(I);
451
452 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
453 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
454 } else {
455 Ok &= Composite(FieldTy, FP, Value);
456 }
457 }
458
459 for (unsigned I = 0; I < NB; ++I) {
460 const Record::Base *BD = Record->getBase(I);
461 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
462 const Pointer &BP = Ptr.atField(BD->Offset);
463 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
464 }
465
466 for (unsigned I = 0; I < NV; ++I) {
467 const Record::Base *VD = Record->getVirtualBase(I);
468 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
469 const Pointer &VP = Ptr.atField(VD->Offset);
470 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
471 }
472 }
473 return Ok;
474 }
475
476 if (Ty->isIncompleteArrayType()) {
477 R = APValue(APValue::UninitArray(), 0, 0);
478 return true;
479 }
480
481 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
482 const size_t NumElems = Ptr.getNumElems();
483 QualType ElemTy = AT->getElementType();
484 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
485
486 bool Ok = true;
487 for (unsigned I = 0; I < NumElems; ++I) {
488 APValue &Slot = R.getArrayInitializedElt(I);
489 const Pointer &EP = Ptr.atIndex(I);
490 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
491 TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
492 } else {
493 Ok &= Composite(ElemTy, EP.narrow(), Slot);
494 }
495 }
496 return Ok;
497 }
498
499 // Complex types.
500 if (const auto *CT = Ty->getAs<ComplexType>()) {
501 QualType ElemTy = CT->getElementType();
502
503 if (ElemTy->isIntegerType()) {
504 std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
505 assert(ElemT);
506 INT_TYPE_SWITCH(*ElemT, {
507 auto V1 = Ptr.atIndex(0).deref<T>();
508 auto V2 = Ptr.atIndex(1).deref<T>();
509 R = APValue(V1.toAPSInt(), V2.toAPSInt());
510 return true;
511 });
512 } else if (ElemTy->isFloatingType()) {
513 R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
514 Ptr.atIndex(1).deref<Floating>().getAPFloat());
515 return true;
516 }
517 return false;
518 }
519
520 // Vector types.
521 if (const auto *VT = Ty->getAs<VectorType>()) {
522 assert(Ptr.getFieldDesc()->isPrimitiveArray());
523 QualType ElemTy = VT->getElementType();
524 PrimType ElemT = *Ctx.classify(ElemTy);
525
527 Values.reserve(VT->getNumElements());
528 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
529 TYPE_SWITCH(ElemT, {
530 Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
531 });
532 }
533
534 assert(Values.size() == VT->getNumElements());
535 R = APValue(Values.data(), Values.size());
536 return true;
537 }
538
539 llvm_unreachable("invalid value to return");
540 };
541
542 // Invalid to read from.
543 if (isDummy() || !isLive() || isPastEnd())
544 return std::nullopt;
545
546 // We can return these as rvalues, but we can't deref() them.
547 if (isZero() || isIntegralPointer())
548 return toAPValue(ASTCtx);
549
550 // Just load primitive types.
551 if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
552 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
553 }
554
555 // Return the composite type.
557 if (!Composite(getType(), *this, Result))
558 return std::nullopt;
559 return Result;
560}
StringRef P
IndirectLocalPath & Path
Expr * E
#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)
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,...
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
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:3108
This represents one expression.
Definition: Expr.h:110
Represents a member of a struct/union/class.
Definition: Decl.h:3030
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:5936
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:8335
bool isFloatingType() const
Definition: Type.cpp:2249
Represents a GCC generic vector type.
Definition: Type.h:3991
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:127
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:80
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:370
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:179
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:366
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:271
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:470
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:144
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:517
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition: Pointer.cpp:234
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:562
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:506
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:163
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:609
DeclTy getSource() const
Returns the expression or declaration the pointer has been created for.
Definition: Pointer.h:292
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:553
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:313
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:406
void activate() const
Activats a field.
Definition: Pointer.cpp:355
void operator=(const Pointer &P)
Definition: Pointer.cpp:67
bool isIntegralPointer() const
Definition: Pointer.h:447
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:334
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:412
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:389
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:265
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:304
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:261
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:256
const IntPointer & asIntPointer() const
Definition: Pointer.h:437
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:418
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:279
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
Definition: Pointer.cpp:127
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:580
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:389
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition: Pointer.h:595
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:603
bool isBlockPointer() const
Definition: Pointer.h:446
BlockPointer BS
Definition: Pointer.h:716
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition: Pointer.cpp:395
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:441
const Block * block() const
Definition: Pointer.h:559
bool isFunctionPointer() const
Definition: Pointer.h:448
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:324
bool isVirtualBaseClass() const
Definition: Pointer.h:513
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:433
void initialize() const
Initializes a field.
Definition: Pointer.cpp:307
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:271
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:451
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
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:107
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:233
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:198
const Decl * asDecl() const
Definition: Descriptor.h:194
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:151
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:238
const FieldDecl * asFieldDecl() const
Definition: Descriptor.h:206
const Expr * asExpr() const
Definition: Descriptor.h:195
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:90
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition: Descriptor.h:82