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
204 if (Ptr.isArrayRoot()) {
205 // An array root may still be an array element itself.
206 if (Ptr.isArrayElement()) {
207 Ptr = Ptr.expand();
208 unsigned Index = Ptr.getIndex();
210 QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
211 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
212 Ptr = Ptr.getArray();
213 } else {
215 {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));
216
217 if (const auto *FD =
218 dyn_cast_if_present<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
219 Offset += getFieldOffset(FD);
220
221 Ptr = Ptr.getBase();
222 }
223 } else if (Ptr.isArrayElement()) {
224 Ptr = Ptr.expand();
225 unsigned Index;
226 if (Ptr.isOnePastEnd())
227 Index = Ptr.getArray().getNumElems();
228 else
229 Index = Ptr.getIndex();
230
231 QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
232 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
234 Ptr = Ptr.getArray();
235 } else {
236 bool IsVirtual = false;
237
238 // Create a path entry for the field.
239 const Descriptor *Desc = Ptr.getFieldDesc();
240 if (const auto *BaseOrMember = Desc->asDecl()) {
241 if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
242 Ptr = Ptr.getBase();
243 Offset += getFieldOffset(FD);
244 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
245 IsVirtual = Ptr.isVirtualBaseClass();
246 Ptr = Ptr.getBase();
247 const Record *BaseRecord = Ptr.getRecord();
248
249 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
250 cast<CXXRecordDecl>(BaseRecord->getDecl()));
251 if (IsVirtual)
252 Offset += Layout.getVBaseClassOffset(RD);
253 else
254 Offset += Layout.getBaseClassOffset(RD);
255
256 } else {
257 Ptr = Ptr.getBase();
258 }
259 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
260 continue;
261 }
262 llvm_unreachable("Invalid field type");
263 }
264 }
265
266 // We assemble the LValuePath starting from the innermost pointer to the
267 // outermost one. SO in a.b.c, the first element in Path will refer to
268 // the field 'c', while later code expects it to refer to 'a'.
269 // Just invert the order of the elements.
270 std::reverse(Path.begin(), Path.end());
271
272 return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
273 /*IsNullPtr=*/false);
274}
275
276void Pointer::print(llvm::raw_ostream &OS) const {
277 switch (StorageKind) {
278 case Storage::Block: {
279 const Block *B = PointeeStorage.BS.Pointee;
280 OS << "(Block) " << B << " {";
281
282 if (isRoot())
283 OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
284 else
285 OS << PointeeStorage.BS.Base << ", ";
286
287 if (isElementPastEnd())
288 OS << "pastend, ";
289 else
290 OS << Offset << ", ";
291
292 if (B)
293 OS << B->getSize();
294 else
295 OS << "nullptr";
296 OS << "}";
297 } break;
298 case Storage::Int:
299 OS << "(Int) {";
300 OS << PointeeStorage.Int.Value << " + " << Offset << ", "
301 << PointeeStorage.Int.Desc;
302 OS << "}";
303 break;
304 case Storage::Fn:
305 OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
306 << " }";
307 }
308}
309
310std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
311 if (isZero())
312 return "nullptr";
313
314 if (isIntegralPointer())
315 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
316
317 return toAPValue(Ctx).getAsString(Ctx, getType());
318}
319
321 if (!isBlockPointer())
322 return true;
323
324 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
325 const GlobalInlineDescriptor &GD =
326 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
328 }
329
330 assert(PointeeStorage.BS.Pointee &&
331 "Cannot check if null pointer was initialized");
332 const Descriptor *Desc = getFieldDesc();
333 assert(Desc);
334 if (Desc->isPrimitiveArray()) {
335 if (isStatic() && PointeeStorage.BS.Base == 0)
336 return true;
337
338 InitMapPtr &IM = getInitMap();
339
340 if (!IM)
341 return false;
342
343 if (IM->first)
344 return true;
345
346 return IM->second->isElementInitialized(getIndex());
347 }
348
349 if (asBlockPointer().Base == 0)
350 return true;
351
352 // Field has its bit in an inline descriptor.
353 return getInlineDesc()->IsInitialized;
354}
355
357 if (!isBlockPointer())
358 return;
359
360 assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
361 const Descriptor *Desc = getFieldDesc();
362
363 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
364 GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
367 return;
368 }
369
370 assert(Desc);
371 if (Desc->isPrimitiveArray()) {
372 // Primitive global arrays don't have an initmap.
373 if (isStatic() && PointeeStorage.BS.Base == 0)
374 return;
375
376 // Nothing to do for these.
377 if (Desc->getNumElems() == 0)
378 return;
379
380 InitMapPtr &IM = getInitMap();
381 if (!IM)
382 IM =
383 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
384
385 assert(IM);
386
387 // All initialized.
388 if (IM->first)
389 return;
390
391 if (IM->second->initializeElement(getIndex())) {
392 IM->first = true;
393 IM->second.reset();
394 }
395 return;
396 }
397
398 // Field has its bit in an inline descriptor.
399 assert(PointeeStorage.BS.Base != 0 &&
400 "Only composite fields can be initialised");
401 getInlineDesc()->IsInitialized = true;
402}
403
404void Pointer::activate() const {
405 // Field has its bit in an inline descriptor.
406 assert(PointeeStorage.BS.Base != 0 &&
407 "Only composite fields can be activated");
408
409 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
410 return;
411 if (!getInlineDesc()->InUnion)
412 return;
413
414 getInlineDesc()->IsActive = true;
415
416 // Get the union, iterate over its fields and DEactivate all others.
417 Pointer UnionPtr = getBase();
418 while (!UnionPtr.getFieldDesc()->isUnion())
419 UnionPtr = UnionPtr.getBase();
420
421 const Record *UnionRecord = UnionPtr.getRecord();
422 for (const Record::Field &F : UnionRecord->fields()) {
423 Pointer FieldPtr = UnionPtr.atField(F.Offset);
424 if (FieldPtr == *this) {
425 } else {
426 FieldPtr.getInlineDesc()->IsActive = false;
427 // FIXME: Recurse.
428 }
429 }
430
431 Pointer B = getBase();
432 while (!B.isRoot() && B.inUnion()) {
433 // FIXME: Need to de-activate other fields of parent records.
434 B.getInlineDesc()->IsActive = true;
435 assert(B.isActive());
436 B = B.getBase();
437 }
438}
439
441 // TODO: this only appears in constructors, so nothing to deactivate.
442}
443
444bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
445 // Two null pointers always have the same base.
446 if (A.isZero() && B.isZero())
447 return true;
448
450 return true;
452 return true;
453
455 return A.getSource() == B.getSource();
456
457 if (A.StorageKind != B.StorageKind)
458 return false;
459
461}
462
463bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
464 if (!A.isBlockPointer() || !B.isBlockPointer())
465 return false;
466 return A.block() == B.block();
467}
468
469bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
470 return hasSameBase(A, B) &&
471 A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
473}
474
476 if (isZero() || !isBlockPointer())
477 return false;
478
479 const Expr *E = block()->getDescriptor()->asExpr();
480 if (block()->isDynamic())
481 return false;
482
483 return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
484}
485
486std::optional<APValue> Pointer::toRValue(const Context &Ctx,
487 QualType ResultType) const {
488 const ASTContext &ASTCtx = Ctx.getASTContext();
489 assert(!ResultType.isNull());
490 // Method to recursively traverse composites.
491 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
492 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
493 APValue &R) {
494 if (const auto *AT = Ty->getAs<AtomicType>())
495 Ty = AT->getValueType();
496
497 // Invalid pointers.
498 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
499 Ptr.isPastEnd())
500 return false;
501
502 // Primitive values.
503 if (std::optional<PrimType> T = Ctx.classify(Ty)) {
504 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
505 return true;
506 }
507
508 if (const auto *RT = Ty->getAs<RecordType>()) {
509 const auto *Record = Ptr.getRecord();
510 assert(Record && "Missing record descriptor");
511
512 bool Ok = true;
513 if (RT->getDecl()->isUnion()) {
514 const FieldDecl *ActiveField = nullptr;
516 for (const auto &F : Record->fields()) {
517 const Pointer &FP = Ptr.atField(F.Offset);
518 QualType FieldTy = F.Decl->getType();
519 if (FP.isActive()) {
520 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
521 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
522 } else {
523 Ok &= Composite(FieldTy, FP, Value);
524 }
525 ActiveField = FP.getFieldDesc()->asFieldDecl();
526 break;
527 }
528 }
529 R = APValue(ActiveField, Value);
530 } else {
531 unsigned NF = Record->getNumFields();
532 unsigned NB = Record->getNumBases();
533 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
534
535 R = APValue(APValue::UninitStruct(), NB, NF);
536
537 for (unsigned I = 0; I < NF; ++I) {
538 const Record::Field *FD = Record->getField(I);
539 QualType FieldTy = FD->Decl->getType();
540 const Pointer &FP = Ptr.atField(FD->Offset);
541 APValue &Value = R.getStructField(I);
542
543 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
544 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
545 } else {
546 Ok &= Composite(FieldTy, FP, Value);
547 }
548 }
549
550 for (unsigned I = 0; I < NB; ++I) {
551 const Record::Base *BD = Record->getBase(I);
552 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
553 const Pointer &BP = Ptr.atField(BD->Offset);
554 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
555 }
556
557 for (unsigned I = 0; I < NV; ++I) {
558 const Record::Base *VD = Record->getVirtualBase(I);
559 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
560 const Pointer &VP = Ptr.atField(VD->Offset);
561 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
562 }
563 }
564 return Ok;
565 }
566
567 if (Ty->isIncompleteArrayType()) {
568 R = APValue(APValue::UninitArray(), 0, 0);
569 return true;
570 }
571
572 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
573 const size_t NumElems = Ptr.getNumElems();
574 QualType ElemTy = AT->getElementType();
575 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
576
577 bool Ok = true;
578 for (unsigned I = 0; I < NumElems; ++I) {
579 APValue &Slot = R.getArrayInitializedElt(I);
580 const Pointer &EP = Ptr.atIndex(I);
581 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
582 TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
583 } else {
584 Ok &= Composite(ElemTy, EP.narrow(), Slot);
585 }
586 }
587 return Ok;
588 }
589
590 // Complex types.
591 if (const auto *CT = Ty->getAs<ComplexType>()) {
592 QualType ElemTy = CT->getElementType();
593
594 if (ElemTy->isIntegerType()) {
595 std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
596 assert(ElemT);
597 INT_TYPE_SWITCH(*ElemT, {
598 auto V1 = Ptr.atIndex(0).deref<T>();
599 auto V2 = Ptr.atIndex(1).deref<T>();
600 R = APValue(V1.toAPSInt(), V2.toAPSInt());
601 return true;
602 });
603 } else if (ElemTy->isFloatingType()) {
604 R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
605 Ptr.atIndex(1).deref<Floating>().getAPFloat());
606 return true;
607 }
608 return false;
609 }
610
611 // Vector types.
612 if (const auto *VT = Ty->getAs<VectorType>()) {
613 assert(Ptr.getFieldDesc()->isPrimitiveArray());
614 QualType ElemTy = VT->getElementType();
615 PrimType ElemT = *Ctx.classify(ElemTy);
616
618 Values.reserve(VT->getNumElements());
619 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
620 TYPE_SWITCH(ElemT, {
621 Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
622 });
623 }
624
625 assert(Values.size() == VT->getNumElements());
626 R = APValue(Values.data(), Values.size());
627 return true;
628 }
629
630 llvm_unreachable("invalid value to return");
631 };
632
633 // Invalid to read from.
634 if (isDummy() || !isLive() || isPastEnd())
635 return std::nullopt;
636
637 // We can return these as rvalues, but we can't deref() them.
638 if (isZero() || isIntegralPointer())
639 return toAPValue(ASTCtx);
640
641 // Just load primitive types.
642 if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
643 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
644 }
645
646 // Return the composite type.
648 if (!Composite(ResultType, *this, Result))
649 return std::nullopt;
650 return Result;
651}
652
654 unsigned Offset) const {
655 if (!this->Desc)
656 return *this;
657 const Record *R = this->Desc->ElemRecord;
658 if (!R)
659 return *this;
660
661 const Record::Field *F = nullptr;
662 for (auto &It : R->fields()) {
663 if (It.Offset == Offset) {
664 F = &It;
665 break;
666 }
667 }
668 if (!F)
669 return *this;
670
671 const FieldDecl *FD = F->Decl;
672 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
673 unsigned FieldIndex = FD->getFieldIndex();
674 uint64_t FieldOffset =
675 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
676 .getQuantity();
677 return IntPointer{F->Desc, this->Value + FieldOffset};
678}
679
681 unsigned BaseOffset) const {
682 const Record *R = Desc->ElemRecord;
683 const Descriptor *BaseDesc = nullptr;
684
685 // This iterates over bases and checks for the proper offset. That's
686 // potentially slow but this case really shouldn't happen a lot.
687 for (const Record::Base &B : R->bases()) {
688 if (B.Offset == BaseOffset) {
689 BaseDesc = B.Desc;
690 break;
691 }
692 }
693 assert(BaseDesc);
694
695 // Adjust the offset value based on the information from the record layout.
696 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
697 CharUnits BaseLayoutOffset =
698 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
699
700 return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
701}
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:175
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:153
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD)
#define bool
Definition: amdgpuintrin.h:20
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:206
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition: APValue.h:214
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
APValue & getArrayInitializedElt(unsigned I)
Definition: APValue.h:552
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:188
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:3145
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:3033
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition: Decl.cpp:4654
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition: Decl.h:3250
A (possibly-)qualified type.
Definition: Type.h:929
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:996
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: Type.h:6072
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: Type.h:8550
bool isFloatingType() const
Definition: Type.cpp:2283
Represents a GCC generic vector type.
Definition: Type.h:4034
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:80
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition: InterpBlock.h:68
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
Definition: InterpBlock.h:104
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:62
std::optional< PrimType > classify(QualType T) const
Classifies a type.
Definition: Context.cpp:135
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:83
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:444
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:185
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:440
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:320
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:491
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition: Pointer.h:506
bool inUnion() const
Definition: Pointer.h:404
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:151
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:544
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition: Pointer.cpp:276
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:589
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:533
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:170
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:642
DeclTy getSource() const
Returns the expression or declaration the pointer has been created for.
Definition: Pointer.h:297
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:580
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:318
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:417
void activate() const
Activats a field.
Definition: Pointer.cpp:404
void operator=(const Pointer &P)
Definition: Pointer.cpp:69
bool isIntegralPointer() const
Definition: Pointer.h:468
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:339
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:423
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:394
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:270
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition: Pointer.cpp:475
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:309
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:310
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:261
const IntPointer & asIntPointer() const
Definition: Pointer.h:458
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:439
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:284
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition: Pointer.cpp:463
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:607
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:469
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition: Pointer.h:622
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:227
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:630
bool isBlockPointer() const
Definition: Pointer.h:467
BlockPointer BS
Definition: Pointer.h:746
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition: Pointer.cpp:486
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:462
const Block * block() const
Definition: Pointer.h:586
bool isFunctionPointer() const
Definition: Pointer.h:469
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:329
bool isVirtualBaseClass() const
Definition: Pointer.h:540
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:454
void initialize() const
Initializes a field.
Definition: Pointer.cpp:356
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:276
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:472
Structure/Class descriptor.
Definition: Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition: Record.h:53
unsigned getNumBases() const
Definition: Record.h:92
const Field * getField(const FieldDecl *FD) const
Returns a field.
Definition: Record.cpp:40
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:88
const Base * getVirtualBase(const RecordDecl *RD) const
Returns a virtual base descriptor.
Definition: Record.cpp:60
unsigned getNumFields() const
Definition: Record.h:84
unsigned getNumVirtualBases() const
Definition: Record.h:103
llvm::iterator_range< const_field_iter > fields() const
Definition: Record.h:80
const Base * getBase(const RecordDecl *FD) const
Returns a base descriptor.
Definition: Record.cpp:46
std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr
Definition: Descriptor.h:30
llvm::APInt APInt
Definition: FixedPoint.h:19
PrimType
Enumeration of the primitive types of the VM.
Definition: PrimType.h:34
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.
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:116
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:243
QualType getElemQualType() const
Definition: Descriptor.cpp:408
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:208
const Decl * asDecl() const
Definition: Descriptor.h:204
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:160
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:248
const FieldDecl * asFieldDecl() const
Definition: Descriptor.h:216
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:146
bool isUnion() const
Checks if the descriptor is of a union.
Definition: Descriptor.cpp:446
const Expr * asExpr() const
Definition: Descriptor.h:205
bool isArray() const
Checks if the descriptor is of an array.
Definition: Descriptor.h:260
Descriptor used for global variables.
Definition: Descriptor.h:59
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition: Descriptor.h:92
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition: Descriptor.h:83
IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const
Definition: Pointer.cpp:680
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:653
const Descriptor * Desc
Definition: Pointer.h:45