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 if (P.isTypeidPointer()) {
100 PointeeStorage.Typeid = P.PointeeStorage.Typeid;
101 } else {
102 assert(false && "Unhandled storage kind");
103 }
104}
105
107 // If the current storage type is Block, we need to remove
108 // this pointer from the block.
109 if (isBlockPointer()) {
110 if (P.isBlockPointer() && this->block() == P.block()) {
111 Offset = P.Offset;
112 PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
113 return;
114 }
115
116 if (Block *Pointee = PointeeStorage.BS.Pointee) {
117 assert(P.block() != this->block());
118 Pointee->removePointer(this);
119 PointeeStorage.BS.Pointee = nullptr;
120 Pointee->cleanup();
121 }
122 }
123
124 StorageKind = P.StorageKind;
125 Offset = P.Offset;
126
127 if (P.isBlockPointer()) {
128 PointeeStorage.BS = P.PointeeStorage.BS;
129 PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
130
131 if (PointeeStorage.BS.Pointee)
132 PointeeStorage.BS.Pointee->addPointer(this);
133 } else if (P.isIntegralPointer()) {
134 PointeeStorage.Int = P.PointeeStorage.Int;
135 } else if (P.isFunctionPointer()) {
136 PointeeStorage.Fn = P.PointeeStorage.Fn;
137 } else if (P.isTypeidPointer()) {
138 PointeeStorage.Typeid = P.PointeeStorage.Typeid;
139 } else {
140 assert(false && "Unhandled storage kind");
141 }
142}
143
146
147 if (isZero())
148 return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
149 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
150 if (isIntegralPointer())
151 return APValue(static_cast<const Expr *>(nullptr),
153 Path,
154 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
155 if (isFunctionPointer())
156 return asFunctionPointer().toAPValue(ASTCtx);
157
158 if (isTypeidPointer()) {
159 TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr);
160 return APValue(
162 TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)),
164 }
165
166 // Build the lvalue base from the block.
167 const Descriptor *Desc = getDeclDesc();
169 if (const auto *VD = Desc->asValueDecl())
170 Base = VD;
171 else if (const auto *E = Desc->asExpr()) {
172 // Create a DynamicAlloc base of the right type.
173 if (const auto *NewExpr = dyn_cast<CXXNewExpr>(E)) {
174 QualType AllocatedType;
175 if (NewExpr->isArray()) {
176 assert(Desc->isArray());
177 APInt ArraySize(64, static_cast<uint64_t>(Desc->getNumElems()),
178 /*IsSigned=*/false);
179 AllocatedType =
180 ASTCtx.getConstantArrayType(NewExpr->getAllocatedType(), ArraySize,
181 nullptr, ArraySizeModifier::Normal, 0);
182 } else {
183 AllocatedType = NewExpr->getAllocatedType();
184 }
185 // FIXME: Suboptimal counting of dynamic allocations. Move this to Context
186 // or InterpState?
187 static int ReportedDynamicAllocs = 0;
188 DynamicAllocLValue DA(ReportedDynamicAllocs++);
189 Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
190 } else {
191 Base = E;
192 }
193 } else
194 llvm_unreachable("Invalid allocation type");
195
196 if (isUnknownSizeArray())
197 return APValue(Base, CharUnits::Zero(), Path,
198 /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
199
200 CharUnits Offset = CharUnits::Zero();
201
202 auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
203 // This shouldn't happen, but if it does, don't crash inside
204 // getASTRecordLayout.
205 if (FD->getParent()->isInvalidDecl())
206 return CharUnits::Zero();
207 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
208 unsigned FieldIndex = FD->getFieldIndex();
209 return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
210 };
211
212 // Build the path into the object.
213 Pointer Ptr = *this;
214 while (Ptr.isField() || Ptr.isArrayElement()) {
215
216 if (Ptr.isArrayRoot()) {
217 // An array root may still be an array element itself.
218 if (Ptr.isArrayElement()) {
219 Ptr = Ptr.expand();
220 unsigned Index = Ptr.getIndex();
222 QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
223 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
224 Ptr = Ptr.getArray();
225 } else {
227 {Ptr.getFieldDesc()->asDecl(), /*IsVirtual=*/false}));
228
229 if (const auto *FD =
230 dyn_cast_if_present<FieldDecl>(Ptr.getFieldDesc()->asDecl()))
231 Offset += getFieldOffset(FD);
232
233 Ptr = Ptr.getBase();
234 }
235 } else if (Ptr.isArrayElement()) {
236 Ptr = Ptr.expand();
237 unsigned Index;
238 if (Ptr.isOnePastEnd())
239 Index = Ptr.getArray().getNumElems();
240 else
241 Index = Ptr.getIndex();
242
243 QualType ElemType = Ptr.getFieldDesc()->getElemQualType();
244 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
246 Ptr = Ptr.getArray();
247 } else {
248 bool IsVirtual = false;
249
250 // Create a path entry for the field.
251 const Descriptor *Desc = Ptr.getFieldDesc();
252 if (const auto *BaseOrMember = Desc->asDecl()) {
253 if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
254 Ptr = Ptr.getBase();
255 Offset += getFieldOffset(FD);
256 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
257 IsVirtual = Ptr.isVirtualBaseClass();
258 Ptr = Ptr.getBase();
259 const Record *BaseRecord = Ptr.getRecord();
260
261 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
262 cast<CXXRecordDecl>(BaseRecord->getDecl()));
263 if (IsVirtual)
264 Offset += Layout.getVBaseClassOffset(RD);
265 else
266 Offset += Layout.getBaseClassOffset(RD);
267
268 } else {
269 Ptr = Ptr.getBase();
270 }
271 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
272 continue;
273 }
274 llvm_unreachable("Invalid field type");
275 }
276 }
277
278 // We assemble the LValuePath starting from the innermost pointer to the
279 // outermost one. SO in a.b.c, the first element in Path will refer to
280 // the field 'c', while later code expects it to refer to 'a'.
281 // Just invert the order of the elements.
282 std::reverse(Path.begin(), Path.end());
283
284 return APValue(Base, Offset, Path, /*IsOnePastEnd=*/isOnePastEnd(),
285 /*IsNullPtr=*/false);
286}
287
288void Pointer::print(llvm::raw_ostream &OS) const {
289 switch (StorageKind) {
290 case Storage::Block: {
291 const Block *B = PointeeStorage.BS.Pointee;
292 OS << "(Block) " << B << " {";
293
294 if (isRoot())
295 OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
296 else
297 OS << PointeeStorage.BS.Base << ", ";
298
299 if (isElementPastEnd())
300 OS << "pastend, ";
301 else
302 OS << Offset << ", ";
303
304 if (B)
305 OS << B->getSize();
306 else
307 OS << "nullptr";
308 OS << "}";
309 } break;
310 case Storage::Int:
311 OS << "(Int) {";
312 OS << PointeeStorage.Int.Value << " + " << Offset << ", "
313 << PointeeStorage.Int.Desc;
314 OS << "}";
315 break;
316 case Storage::Fn:
317 OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
318 << " }";
319 break;
320 case Storage::Typeid:
321 OS << "(Typeid)";
322 }
323}
324
325std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
326 if (isZero())
327 return "nullptr";
328
329 if (isIntegralPointer())
330 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
331
332 return toAPValue(Ctx).getAsString(Ctx, getType());
333}
334
336 if (!isBlockPointer())
337 return true;
338
339 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
340 const GlobalInlineDescriptor &GD =
341 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
343 }
344
345 assert(PointeeStorage.BS.Pointee &&
346 "Cannot check if null pointer was initialized");
347 const Descriptor *Desc = getFieldDesc();
348 assert(Desc);
349 if (Desc->isPrimitiveArray()) {
350 if (isStatic() && PointeeStorage.BS.Base == 0)
351 return true;
352
353 InitMapPtr &IM = getInitMap();
354
355 if (!IM)
356 return false;
357
358 if (IM->first)
359 return true;
360
361 return IM->second->isElementInitialized(getIndex());
362 }
363
364 if (asBlockPointer().Base == 0)
365 return true;
366
367 // Field has its bit in an inline descriptor.
368 return getInlineDesc()->IsInitialized;
369}
370
372 if (!isBlockPointer())
373 return;
374
375 assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
376 const Descriptor *Desc = getFieldDesc();
377
378 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
379 GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
382 return;
383 }
384
385 assert(Desc);
386 if (Desc->isPrimitiveArray()) {
387 // Primitive global arrays don't have an initmap.
388 if (isStatic() && PointeeStorage.BS.Base == 0)
389 return;
390
391 // Nothing to do for these.
392 if (Desc->getNumElems() == 0)
393 return;
394
395 InitMapPtr &IM = getInitMap();
396 if (!IM)
397 IM =
398 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
399
400 assert(IM);
401
402 // All initialized.
403 if (IM->first)
404 return;
405
406 if (IM->second->initializeElement(getIndex())) {
407 IM->first = true;
408 IM->second.reset();
409 }
410 return;
411 }
412
413 // Field has its bit in an inline descriptor.
414 assert(PointeeStorage.BS.Base != 0 &&
415 "Only composite fields can be initialised");
416 getInlineDesc()->IsInitialized = true;
417}
418
419void Pointer::activate() const {
420 // Field has its bit in an inline descriptor.
421 assert(PointeeStorage.BS.Base != 0 &&
422 "Only composite fields can be activated");
423
424 if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
425 return;
426 if (!getInlineDesc()->InUnion)
427 return;
428
429 getInlineDesc()->IsActive = true;
430
431 // Get the union, iterate over its fields and DEactivate all others.
432 Pointer UnionPtr = getBase();
433 while (!UnionPtr.getFieldDesc()->isUnion())
434 UnionPtr = UnionPtr.getBase();
435
436 const Record *UnionRecord = UnionPtr.getRecord();
437 for (const Record::Field &F : UnionRecord->fields()) {
438 Pointer FieldPtr = UnionPtr.atField(F.Offset);
439 if (FieldPtr == *this) {
440 } else {
441 FieldPtr.getInlineDesc()->IsActive = false;
442 // FIXME: Recurse.
443 }
444 }
445
446 Pointer B = getBase();
447 while (!B.isRoot() && B.inUnion()) {
448 // FIXME: Need to de-activate other fields of parent records.
449 B.getInlineDesc()->IsActive = true;
450 assert(B.isActive());
451 B = B.getBase();
452 }
453}
454
456 // TODO: this only appears in constructors, so nothing to deactivate.
457}
458
459bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
460 // Two null pointers always have the same base.
461 if (A.isZero() && B.isZero())
462 return true;
463
465 return true;
467 return true;
468 if (A.isTypeidPointer() && B.isTypeidPointer())
469 return true;
470
472 return A.getSource() == B.getSource();
473
474 if (A.StorageKind != B.StorageKind)
475 return false;
476
478}
479
480bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
481 if (!A.isBlockPointer() || !B.isBlockPointer())
482 return false;
483 return A.block() == B.block();
484}
485
486bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
487 return hasSameBase(A, B) &&
488 A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
490}
491
493 if (isZero() || !isBlockPointer())
494 return false;
495
496 if (block()->isDynamic())
497 return false;
498
499 const Expr *E = block()->getDescriptor()->asExpr();
500 return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
501}
502
503std::optional<APValue> Pointer::toRValue(const Context &Ctx,
504 QualType ResultType) const {
505 const ASTContext &ASTCtx = Ctx.getASTContext();
506 assert(!ResultType.isNull());
507 // Method to recursively traverse composites.
508 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
509 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
510 APValue &R) {
511 if (const auto *AT = Ty->getAs<AtomicType>())
512 Ty = AT->getValueType();
513
514 // Invalid pointers.
515 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
516 Ptr.isPastEnd())
517 return false;
518
519 // Primitive values.
520 if (std::optional<PrimType> T = Ctx.classify(Ty)) {
521 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
522 return true;
523 }
524
525 if (const auto *RT = Ty->getAs<RecordType>()) {
526 const auto *Record = Ptr.getRecord();
527 assert(Record && "Missing record descriptor");
528
529 bool Ok = true;
530 if (RT->getDecl()->isUnion()) {
531 const FieldDecl *ActiveField = nullptr;
533 for (const auto &F : Record->fields()) {
534 const Pointer &FP = Ptr.atField(F.Offset);
535 QualType FieldTy = F.Decl->getType();
536 if (FP.isActive()) {
537 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
538 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
539 } else {
540 Ok &= Composite(FieldTy, FP, Value);
541 }
542 ActiveField = FP.getFieldDesc()->asFieldDecl();
543 break;
544 }
545 }
546 R = APValue(ActiveField, Value);
547 } else {
548 unsigned NF = Record->getNumFields();
549 unsigned NB = Record->getNumBases();
550 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
551
552 R = APValue(APValue::UninitStruct(), NB, NF);
553
554 for (unsigned I = 0; I < NF; ++I) {
555 const Record::Field *FD = Record->getField(I);
556 QualType FieldTy = FD->Decl->getType();
557 const Pointer &FP = Ptr.atField(FD->Offset);
558 APValue &Value = R.getStructField(I);
559
560 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
561 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
562 } else {
563 Ok &= Composite(FieldTy, FP, Value);
564 }
565 }
566
567 for (unsigned I = 0; I < NB; ++I) {
568 const Record::Base *BD = Record->getBase(I);
569 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
570 const Pointer &BP = Ptr.atField(BD->Offset);
571 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
572 }
573
574 for (unsigned I = 0; I < NV; ++I) {
575 const Record::Base *VD = Record->getVirtualBase(I);
576 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
577 const Pointer &VP = Ptr.atField(VD->Offset);
578 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
579 }
580 }
581 return Ok;
582 }
583
584 if (Ty->isIncompleteArrayType()) {
585 R = APValue(APValue::UninitArray(), 0, 0);
586 return true;
587 }
588
589 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
590 const size_t NumElems = Ptr.getNumElems();
591 QualType ElemTy = AT->getElementType();
592 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
593
594 bool Ok = true;
595 for (unsigned I = 0; I < NumElems; ++I) {
596 APValue &Slot = R.getArrayInitializedElt(I);
597 const Pointer &EP = Ptr.atIndex(I);
598 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
599 TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
600 } else {
601 Ok &= Composite(ElemTy, EP.narrow(), Slot);
602 }
603 }
604 return Ok;
605 }
606
607 // Complex types.
608 if (const auto *CT = Ty->getAs<ComplexType>()) {
609 QualType ElemTy = CT->getElementType();
610
611 if (ElemTy->isIntegerType()) {
612 std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
613 assert(ElemT);
614 INT_TYPE_SWITCH(*ElemT, {
615 auto V1 = Ptr.atIndex(0).deref<T>();
616 auto V2 = Ptr.atIndex(1).deref<T>();
617 R = APValue(V1.toAPSInt(), V2.toAPSInt());
618 return true;
619 });
620 } else if (ElemTy->isFloatingType()) {
621 R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
622 Ptr.atIndex(1).deref<Floating>().getAPFloat());
623 return true;
624 }
625 return false;
626 }
627
628 // Vector types.
629 if (const auto *VT = Ty->getAs<VectorType>()) {
630 assert(Ptr.getFieldDesc()->isPrimitiveArray());
631 QualType ElemTy = VT->getElementType();
632 PrimType ElemT = *Ctx.classify(ElemTy);
633
635 Values.reserve(VT->getNumElements());
636 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
637 TYPE_SWITCH(ElemT, {
638 Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
639 });
640 }
641
642 assert(Values.size() == VT->getNumElements());
643 R = APValue(Values.data(), Values.size());
644 return true;
645 }
646
647 llvm_unreachable("invalid value to return");
648 };
649
650 // Invalid to read from.
651 if (isDummy() || !isLive() || isPastEnd())
652 return std::nullopt;
653
654 // We can return these as rvalues, but we can't deref() them.
655 if (isZero() || isIntegralPointer())
656 return toAPValue(ASTCtx);
657
658 // Just load primitive types.
659 if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
660 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
661 }
662
663 // Return the composite type.
665 if (!Composite(ResultType, *this, Result))
666 return std::nullopt;
667 return Result;
668}
669
671 unsigned Offset) const {
672 if (!this->Desc)
673 return *this;
674 const Record *R = this->Desc->ElemRecord;
675 if (!R)
676 return *this;
677
678 const Record::Field *F = nullptr;
679 for (auto &It : R->fields()) {
680 if (It.Offset == Offset) {
681 F = &It;
682 break;
683 }
684 }
685 if (!F)
686 return *this;
687
688 const FieldDecl *FD = F->Decl;
689 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
690 unsigned FieldIndex = FD->getFieldIndex();
691 uint64_t FieldOffset =
692 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
693 .getQuantity();
694 return IntPointer{F->Desc, this->Value + FieldOffset};
695}
696
698 unsigned BaseOffset) const {
699 const Record *R = Desc->ElemRecord;
700 const Descriptor *BaseDesc = nullptr;
701
702 // This iterates over bases and checks for the proper offset. That's
703 // potentially slow but this case really shouldn't happen a lot.
704 for (const Record::Base &B : R->bases()) {
705 if (B.Offset == BaseOffset) {
706 BaseDesc = B.Desc;
707 break;
708 }
709 }
710 assert(BaseDesc);
711
712 // Adjust the offset value based on the information from the record layout.
713 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
714 CharUnits BaseLayoutOffset =
715 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
716
717 return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
718}
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 getTypeInfo(TypeInfoLValue LV, QualType TypeInfo)
Definition: APValue.cpp:55
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
Symbolic representation of typeid(T) for some type T.
Definition: APValue.h:44
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:88
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:459
Pointer narrow() const
Restricts the scope of an array element pointer.
Definition: Pointer.h:195
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:455
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:335
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:507
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition: Pointer.h:522
bool inUnion() const
Definition: Pointer.h:419
Pointer atIndex(uint64_t Idx) const
Offsets a pointer inside an array.
Definition: Pointer.h:161
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:560
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition: Pointer.cpp:288
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:605
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:549
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:180
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:658
DeclTy getSource() const
Returns the expression or declaration the pointer has been created for.
Definition: Pointer.h:309
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:596
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:330
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:432
void activate() const
Activats a field.
Definition: Pointer.cpp:419
void operator=(const Pointer &P)
Definition: Pointer.cpp:69
bool isIntegralPointer() const
Definition: Pointer.h:483
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:351
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:438
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:409
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:282
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition: Pointer.cpp:492
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:321
bool isTypeidPointer() const
Definition: Pointer.h:485
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:325
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:271
const IntPointer & asIntPointer() const
Definition: Pointer.h:473
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:454
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:296
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition: Pointer.cpp:480
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
Definition: Pointer.cpp:144
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:623
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:486
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition: Pointer.h:638
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:237
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:646
bool isBlockPointer() const
Definition: Pointer.h:482
BlockPointer BS
Definition: Pointer.h:762
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition: Pointer.cpp:503
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:477
const Block * block() const
Definition: Pointer.h:602
bool isFunctionPointer() const
Definition: Pointer.h:484
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:341
bool isVirtualBaseClass() const
Definition: Pointer.h:556
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:469
void initialize() const
Initializes a field.
Definition: Pointer.cpp:371
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:288
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:488
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:697
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:670
const Descriptor * Desc
Definition: Pointer.h:45