clang 22.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/Expr.h"
20#include "clang/AST/ExprCXX.h"
22
23using namespace clang;
24using namespace clang::interp;
25
27 : Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
28 Pointee->getDescriptor()->getMetadataSize()) {}
29
30Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
31 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
32
33Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
34 : Offset(Offset), StorageKind(Storage::Block) {
35 assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
36
37 BS = {Pointee, Base, nullptr, nullptr};
38
39 if (Pointee)
40 Pointee->addPointer(this);
41}
42
44 : Offset(P.Offset), StorageKind(P.StorageKind) {
45 switch (StorageKind) {
46 case Storage::Int:
47 Int = P.Int;
48 break;
49 case Storage::Block:
50 BS = P.BS;
51 if (BS.Pointee)
52 BS.Pointee->addPointer(this);
53 break;
54 case Storage::Fn:
55 Fn = P.Fn;
56 break;
57 case Storage::Typeid:
58 Typeid = P.Typeid;
59 break;
60 }
61}
62
63Pointer::Pointer(Pointer &&P) : Offset(P.Offset), StorageKind(P.StorageKind) {
64 switch (StorageKind) {
65 case Storage::Int:
66 Int = P.Int;
67 break;
68 case Storage::Block:
69 BS = P.BS;
70 if (BS.Pointee)
71 BS.Pointee->replacePointer(&P, this);
72 break;
73 case Storage::Fn:
74 Fn = P.Fn;
75 break;
76 case Storage::Typeid:
77 Typeid = P.Typeid;
78 break;
79 }
80}
81
83 if (!isBlockPointer())
84 return;
85
86 if (Block *Pointee = BS.Pointee) {
87 Pointee->removePointer(this);
88 BS.Pointee = nullptr;
89 Pointee->cleanup();
90 }
91}
92
94 // If the current storage type is Block, we need to remove
95 // this pointer from the block.
96 if (isBlockPointer()) {
97 if (P.isBlockPointer() && this->block() == P.block()) {
98 Offset = P.Offset;
99 BS.Base = P.BS.Base;
100 return *this;
101 }
102
103 if (Block *Pointee = BS.Pointee) {
104 Pointee->removePointer(this);
105 BS.Pointee = nullptr;
106 Pointee->cleanup();
107 }
108 }
109
110 StorageKind = P.StorageKind;
111 Offset = P.Offset;
112
113 if (P.isBlockPointer()) {
114 BS = P.BS;
115
116 if (BS.Pointee)
117 BS.Pointee->addPointer(this);
118 } else if (P.isIntegralPointer()) {
119 Int = P.Int;
120 } else if (P.isFunctionPointer()) {
121 Fn = P.Fn;
122 } else if (P.isTypeidPointer()) {
123 Typeid = P.Typeid;
124 } else {
125 assert(false && "Unhandled storage kind");
126 }
127 return *this;
128}
129
131 // If the current storage type is Block, we need to remove
132 // this pointer from the block.
133 if (isBlockPointer()) {
134 if (P.isBlockPointer() && this->block() == P.block()) {
135 Offset = P.Offset;
136 BS.Base = P.BS.Base;
137 return *this;
138 }
139
140 if (Block *Pointee = BS.Pointee) {
141 Pointee->removePointer(this);
142 BS.Pointee = nullptr;
143 Pointee->cleanup();
144 }
145 }
146
147 StorageKind = P.StorageKind;
148 Offset = P.Offset;
149
150 if (P.isBlockPointer()) {
151 BS = P.BS;
152
153 if (BS.Pointee)
154 BS.Pointee->addPointer(this);
155 } else if (P.isIntegralPointer()) {
156 Int = P.Int;
157 } else if (P.isFunctionPointer()) {
158 Fn = P.Fn;
159 } else if (P.isTypeidPointer()) {
160 Typeid = P.Typeid;
161 } else {
162 assert(false && "Unhandled storage kind");
163 }
164 return *this;
165}
166
169
170 if (isZero())
171 return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
172 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
173 if (isIntegralPointer())
174 return APValue(static_cast<const Expr *>(nullptr),
176 Path,
177 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
178 if (isFunctionPointer()) {
180 if (const FunctionDecl *FD = FP.getFunction()->getDecl())
181 return APValue(FD, CharUnits::fromQuantity(Offset), {},
182 /*OnePastTheEnd=*/false, /*IsNull=*/false);
183 return APValue(FP.getFunction()->getExpr(), CharUnits::fromQuantity(Offset),
184 {},
185 /*OnePastTheEnd=*/false, /*IsNull=*/false);
186 }
187
188 if (isTypeidPointer()) {
192 CharUnits::Zero(), {},
193 /*OnePastTheEnd=*/false, /*IsNull=*/false);
194 }
195
196 // Build the lvalue base from the block.
197 const Descriptor *Desc = getDeclDesc();
199 if (const auto *VD = Desc->asValueDecl())
200 Base = VD;
201 else if (const auto *E = Desc->asExpr()) {
202 if (block()->isDynamic()) {
203 QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
204 DynamicAllocLValue DA(*block()->DynAllocId);
205 Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
206 } else {
207 Base = E;
208 }
209 } else
210 llvm_unreachable("Invalid allocation type");
211
212 if (isUnknownSizeArray())
213 return APValue(Base, CharUnits::Zero(), Path,
214 /*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
215
216 CharUnits Offset = CharUnits::Zero();
217
218 auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
219 // This shouldn't happen, but if it does, don't crash inside
220 // getASTRecordLayout.
221 if (FD->getParent()->isInvalidDecl())
222 return CharUnits::Zero();
223 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
224 unsigned FieldIndex = FD->getFieldIndex();
225 return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
226 };
227
228 bool UsePath = true;
229 if (const ValueDecl *VD = getDeclDesc()->asValueDecl();
230 VD && VD->getType()->isReferenceType())
231 UsePath = false;
232
233 // Build the path into the object.
234 bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
235 Pointer Ptr = *this;
236 while (Ptr.isField() || Ptr.isArrayElement()) {
237
238 if (Ptr.isArrayRoot()) {
239 // An array root may still be an array element itself.
240 if (Ptr.isArrayElement()) {
241 Ptr = Ptr.expand();
242 const Descriptor *Desc = Ptr.getFieldDesc();
243 unsigned Index = Ptr.getIndex();
244 QualType ElemType = Desc->getElemQualType();
245 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
246 if (Ptr.getArray().getType()->isArrayType())
248 Ptr = Ptr.getArray();
249 } else {
250 const Descriptor *Desc = Ptr.getFieldDesc();
251 const auto *Dcl = Desc->asDecl();
252 Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
253
254 if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl))
255 Offset += getFieldOffset(FD);
256
257 Ptr = Ptr.getBase();
258 }
259 } else if (Ptr.isArrayElement()) {
260 Ptr = Ptr.expand();
261 const Descriptor *Desc = Ptr.getFieldDesc();
262 unsigned Index;
263 if (Ptr.isOnePastEnd()) {
264 Index = Ptr.getArray().getNumElems();
265 OnePastEnd = false;
266 } else
267 Index = Ptr.getIndex();
268
269 QualType ElemType = Desc->getElemQualType();
270 if (const auto *RD = ElemType->getAsRecordDecl();
271 RD && !RD->getDefinition()) {
272 // Ignore this for the offset.
273 } else {
274 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
275 }
276 if (Ptr.getArray().getType()->isArrayType())
278 Ptr = Ptr.getArray();
279 } else {
280 const Descriptor *Desc = Ptr.getFieldDesc();
281
282 // Create a path entry for the field.
283 if (const auto *BaseOrMember = Desc->asDecl()) {
284 bool IsVirtual = false;
285 if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
286 Ptr = Ptr.getBase();
287 Offset += getFieldOffset(FD);
288 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
289 IsVirtual = Ptr.isVirtualBaseClass();
290 Ptr = Ptr.getBase();
291 const Record *BaseRecord = Ptr.getRecord();
292
293 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
294 cast<CXXRecordDecl>(BaseRecord->getDecl()));
295 if (IsVirtual)
296 Offset += Layout.getVBaseClassOffset(RD);
297 else
298 Offset += Layout.getBaseClassOffset(RD);
299
300 } else {
301 Ptr = Ptr.getBase();
302 }
303 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
304 continue;
305 }
306 llvm_unreachable("Invalid field type");
307 }
308 }
309
310 // We assemble the LValuePath starting from the innermost pointer to the
311 // outermost one. SO in a.b.c, the first element in Path will refer to
312 // the field 'c', while later code expects it to refer to 'a'.
313 // Just invert the order of the elements.
314 std::reverse(Path.begin(), Path.end());
315
316 if (UsePath)
317 return APValue(Base, Offset, Path, OnePastEnd);
318
319 return APValue(Base, Offset, APValue::NoLValuePath());
320}
321
322void Pointer::print(llvm::raw_ostream &OS) const {
323 switch (StorageKind) {
324 case Storage::Block: {
325 const Block *B = BS.Pointee;
326 OS << "(Block) " << B << " {";
327
328 if (isRoot())
329 OS << "rootptr(" << BS.Base << "), ";
330 else
331 OS << BS.Base << ", ";
332
333 if (isElementPastEnd())
334 OS << "pastend, ";
335 else
336 OS << Offset << ", ";
337
338 if (B)
339 OS << B->getSize();
340 else
341 OS << "nullptr";
342 OS << "}";
343 } break;
344 case Storage::Int:
345 OS << "(Int) {";
346 OS << Int.Value << " + " << Offset << ", " << Int.Desc;
347 OS << "}";
348 break;
349 case Storage::Fn:
350 OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
351 << " }";
352 break;
353 case Storage::Typeid:
354 OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
355 << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
356 << "}";
357 }
358}
359
361 if (isIntegralPointer())
362 return asIntPointer().Value + Offset;
363 if (isTypeidPointer())
364 return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
365
366 if (!isBlockPointer())
367 return Offset;
368
369 size_t Result = 0;
370 Pointer P = *this;
371 while (true) {
372
373 if (P.isVirtualBaseClass()) {
374 Result += getInlineDesc()->Offset;
375 P = P.getBase();
376 continue;
377 }
378
379 if (P.isBaseClass()) {
380 if (P.getRecord()->getNumVirtualBases() > 0)
381 Result += P.getInlineDesc()->Offset;
382 P = P.getBase();
383 continue;
384 }
385 if (P.isArrayElement()) {
386 P = P.expand();
387 Result += (P.getIndex() * P.elemSize());
388 P = P.getArray();
389 continue;
390 }
391
392 if (P.isRoot()) {
393 if (P.isOnePastEnd())
394 ++Result;
395 break;
396 }
397
398 if (const Record *R = P.getBase().getRecord(); R && R->isUnion()) {
399 if (P.isOnePastEnd())
400 ++Result;
401 // Direct child of a union - all have offset 0.
402 P = P.getBase();
403 continue;
404 }
405
406 // Fields, etc.
407 Result += P.getInlineDesc()->Offset;
408 if (P.isOnePastEnd())
409 ++Result;
410
411 P = P.getBase();
412 if (P.isRoot())
413 break;
414 }
415
416 return Result;
417}
418
419std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
420 if (isZero())
421 return "nullptr";
422
423 if (isIntegralPointer())
424 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
425
426 if (isFunctionPointer())
428
429 return toAPValue(Ctx).getAsString(Ctx, getType());
430}
431
433 if (!isBlockPointer())
434 return true;
435
436 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
437 const GlobalInlineDescriptor &GD =
438 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
440 }
441
442 assert(BS.Pointee && "Cannot check if null pointer was initialized");
443 const Descriptor *Desc = getFieldDesc();
444 assert(Desc);
445 if (Desc->isPrimitiveArray())
447
448 if (asBlockPointer().Base == 0)
449 return true;
450 // Field has its bit in an inline descriptor.
451 return getInlineDesc()->IsInitialized;
452}
453
454bool Pointer::isElementInitialized(unsigned Index) const {
455 if (!isBlockPointer())
456 return true;
457
458 const Descriptor *Desc = getFieldDesc();
459 assert(Desc);
460
461 if (isStatic() && BS.Base == 0)
462 return true;
463
464 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
465 const GlobalInlineDescriptor &GD =
466 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
468 }
469
470 if (Desc->isPrimitiveArray()) {
471 InitMapPtr &IM = getInitMap();
472 if (!IM)
473 return false;
474
475 if (IM->first)
476 return true;
477
478 return IM->second->isElementInitialized(Index);
479 }
480 return isInitialized();
481}
482
484 if (!isBlockPointer())
485 return;
486
487 assert(BS.Pointee && "Cannot initialize null pointer");
488
489 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
490 GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
493 return;
494 }
495
496 const Descriptor *Desc = getFieldDesc();
497 assert(Desc);
498 if (Desc->isPrimitiveArray()) {
499 // Primitive global arrays don't have an initmap.
500 if (isStatic() && BS.Base == 0)
501 return;
502
503 // Nothing to do for these.
504 if (Desc->getNumElems() == 0)
505 return;
506
507 InitMapPtr &IM = getInitMap();
508 if (!IM)
509 IM =
510 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
511
512 assert(IM);
513
514 // All initialized.
515 if (IM->first)
516 return;
517
518 if (IM->second->initializeElement(getIndex())) {
519 IM->first = true;
520 IM->second.reset();
521 }
522 return;
523 }
524
525 // Field has its bit in an inline descriptor.
526 assert(BS.Base != 0 && "Only composite fields can be initialised");
527 getInlineDesc()->IsInitialized = true;
528}
529
531 assert(getFieldDesc()->isPrimitiveArray());
532 assert(isArrayRoot());
533
534 InitMapPtr &IM = getInitMap();
535 if (!IM) {
536 IM = std::make_pair(true, nullptr);
537 } else {
538 IM->first = true;
539 IM->second.reset();
540 }
541}
542
544 assert(getFieldDesc()->isPrimitiveArray());
545 assert(isArrayRoot());
546
547 if (isStatic() && BS.Base == 0)
548 return true;
549
550 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor)) {
551 const GlobalInlineDescriptor &GD =
552 *reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
554 }
555
556 InitMapPtr &IM = getInitMap();
557 return IM && IM->first;
558}
559
560void Pointer::activate() const {
561 // Field has its bit in an inline descriptor.
562 assert(BS.Base != 0 && "Only composite fields can be activated");
563
564 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor))
565 return;
566 if (!getInlineDesc()->InUnion)
567 return;
568
570 activate = [&activate](Pointer &P) -> void {
571 P.getInlineDesc()->IsActive = true;
572 if (const Record *R = P.getRecord(); R && !R->isUnion()) {
573 for (const Record::Field &F : R->fields()) {
574 Pointer FieldPtr = P.atField(F.Offset);
575 if (!FieldPtr.getInlineDesc()->IsActive)
576 activate(FieldPtr);
577 }
578 // FIXME: Bases?
579 }
580 };
581
583 deactivate = [&deactivate](Pointer &P) -> void {
584 P.getInlineDesc()->IsActive = false;
585
586 if (const Record *R = P.getRecord()) {
587 for (const Record::Field &F : R->fields()) {
588 Pointer FieldPtr = P.atField(F.Offset);
589 if (FieldPtr.getInlineDesc()->IsActive)
590 deactivate(FieldPtr);
591 }
592 // FIXME: Bases?
593 }
594 };
595
596 Pointer B = *this;
597 while (!B.isRoot() && B.inUnion()) {
598 activate(B);
599
600 // When walking up the pointer chain, deactivate
601 // all union child pointers that aren't on our path.
602 Pointer Cur = B;
603 B = B.getBase();
604 if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
605 for (const Record::Field &F : BR->fields()) {
606 Pointer FieldPtr = B.atField(F.Offset);
607 if (FieldPtr != Cur)
608 deactivate(FieldPtr);
609 }
610 }
611 }
612}
613
615 // TODO: this only appears in constructors, so nothing to deactivate.
616}
617
618bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
619 // Two null pointers always have the same base.
620 if (A.isZero() && B.isZero())
621 return true;
622
624 return true;
626 return true;
627 if (A.isTypeidPointer() && B.isTypeidPointer())
628 return true;
629
630 if (A.StorageKind != B.StorageKind)
631 return false;
632
634}
635
636bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
637 if (!A.isBlockPointer() || !B.isBlockPointer())
638 return false;
639 return A.block() == B.block();
640}
641
642bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
643 return hasSameBase(A, B) && A.BS.Base == B.BS.Base &&
645}
646
648 if (isZero() || !isBlockPointer())
649 return false;
650
651 if (block()->isDynamic())
652 return false;
653
654 const Expr *E = block()->getDescriptor()->asExpr();
655 return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
656}
657
659 if (isZero() || !isBlockPointer())
660 return false;
661
662 if (block()->isDynamic())
663 return false;
664
665 const Expr *E = block()->getDescriptor()->asExpr();
666 return isa_and_nonnull<StringLiteral>(E);
667}
668
669std::optional<std::pair<Pointer, Pointer>>
671 if (!A.isBlockPointer() || !B.isBlockPointer())
672 return std::nullopt;
673
675 return std::nullopt;
676 if (A.isRoot() && B.isRoot())
677 return std::nullopt;
678
679 if (A == B)
680 return std::make_pair(A, B);
681
682 auto getBase = [](const Pointer &P) -> Pointer {
683 if (P.isArrayElement())
684 return P.expand().getArray();
685 return P.getBase();
686 };
687
688 Pointer IterA = A;
689 Pointer IterB = B;
690 Pointer CurA = IterA;
691 Pointer CurB = IterB;
692 for (;;) {
693 if (IterA.asBlockPointer().Base > IterB.asBlockPointer().Base) {
694 CurA = IterA;
695 IterA = getBase(IterA);
696 } else {
697 CurB = IterB;
698 IterB = getBase(IterB);
699 }
700
701 if (IterA == IterB)
702 return std::make_pair(CurA, CurB);
703
704 if (IterA.isRoot() && IterB.isRoot())
705 return std::nullopt;
706 }
707
708 llvm_unreachable("The loop above should've returned.");
709}
710
711std::optional<APValue> Pointer::toRValue(const Context &Ctx,
712 QualType ResultType) const {
713 const ASTContext &ASTCtx = Ctx.getASTContext();
714 assert(!ResultType.isNull());
715 // Method to recursively traverse composites.
716 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
717 Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
718 APValue &R) {
719 if (const auto *AT = Ty->getAs<AtomicType>())
720 Ty = AT->getValueType();
721
722 // Invalid pointers.
723 if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
724 Ptr.isPastEnd())
725 return false;
726
727 // Primitive values.
728 if (OptPrimType T = Ctx.classify(Ty)) {
729 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
730 return true;
731 }
732
733 if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
734 const auto *Record = Ptr.getRecord();
735 assert(Record && "Missing record descriptor");
736
737 bool Ok = true;
738 if (RT->getOriginalDecl()->isUnion()) {
739 const FieldDecl *ActiveField = nullptr;
741 for (const auto &F : Record->fields()) {
742 const Pointer &FP = Ptr.atField(F.Offset);
743 QualType FieldTy = F.Decl->getType();
744 if (FP.isActive()) {
745 if (OptPrimType T = Ctx.classify(FieldTy)) {
746 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
747 } else {
748 Ok &= Composite(FieldTy, FP, Value);
749 }
750 ActiveField = FP.getFieldDesc()->asFieldDecl();
751 break;
752 }
753 }
754 R = APValue(ActiveField, Value);
755 } else {
756 unsigned NF = Record->getNumFields();
757 unsigned NB = Record->getNumBases();
758 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
759
760 R = APValue(APValue::UninitStruct(), NB, NF);
761
762 for (unsigned I = 0; I < NF; ++I) {
763 const Record::Field *FD = Record->getField(I);
764 QualType FieldTy = FD->Decl->getType();
765 const Pointer &FP = Ptr.atField(FD->Offset);
766 APValue &Value = R.getStructField(I);
767
768 if (OptPrimType T = Ctx.classify(FieldTy)) {
769 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
770 } else {
771 Ok &= Composite(FieldTy, FP, Value);
772 }
773 }
774
775 for (unsigned I = 0; I < NB; ++I) {
776 const Record::Base *BD = Record->getBase(I);
777 QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
778 const Pointer &BP = Ptr.atField(BD->Offset);
779 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
780 }
781
782 for (unsigned I = 0; I < NV; ++I) {
783 const Record::Base *VD = Record->getVirtualBase(I);
784 QualType VirtBaseTy =
785 Ctx.getASTContext().getCanonicalTagType(VD->Decl);
786 const Pointer &VP = Ptr.atField(VD->Offset);
787 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
788 }
789 }
790 return Ok;
791 }
792
793 if (Ty->isIncompleteArrayType()) {
794 R = APValue(APValue::UninitArray(), 0, 0);
795 return true;
796 }
797
798 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
799 const size_t NumElems = Ptr.getNumElems();
800 QualType ElemTy = AT->getElementType();
801 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
802
803 bool Ok = true;
804 OptPrimType ElemT = Ctx.classify(ElemTy);
805 for (unsigned I = 0; I != NumElems; ++I) {
806 APValue &Slot = R.getArrayInitializedElt(I);
807 if (ElemT) {
808 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
809 } else {
810 Ok &= Composite(ElemTy, Ptr.atIndex(I).narrow(), Slot);
811 }
812 }
813 return Ok;
814 }
815
816 // Complex types.
817 if (const auto *CT = Ty->getAs<ComplexType>()) {
818 // Can happen via C casts.
819 if (!Ptr.getFieldDesc()->isPrimitiveArray())
820 return false;
821
822 QualType ElemTy = CT->getElementType();
823 if (ElemTy->isIntegerType()) {
824 OptPrimType ElemT = Ctx.classify(ElemTy);
825 assert(ElemT);
826 INT_TYPE_SWITCH(*ElemT, {
827 auto V1 = Ptr.elem<T>(0);
828 auto V2 = Ptr.elem<T>(1);
829 R = APValue(V1.toAPSInt(), V2.toAPSInt());
830 return true;
831 });
832 } else if (ElemTy->isFloatingType()) {
833 R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
834 Ptr.elem<Floating>(1).getAPFloat());
835 return true;
836 }
837 return false;
838 }
839
840 // Vector types.
841 if (const auto *VT = Ty->getAs<VectorType>()) {
842 assert(Ptr.getFieldDesc()->isPrimitiveArray());
843 QualType ElemTy = VT->getElementType();
844 PrimType ElemT = *Ctx.classify(ElemTy);
845
847 Values.reserve(VT->getNumElements());
848 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
849 TYPE_SWITCH(ElemT,
850 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
851 }
852
853 assert(Values.size() == VT->getNumElements());
854 R = APValue(Values.data(), Values.size());
855 return true;
856 }
857
858 llvm_unreachable("invalid value to return");
859 };
860
861 // Invalid to read from.
862 if (isDummy() || !isLive() || isPastEnd())
863 return std::nullopt;
864
865 // We can return these as rvalues, but we can't deref() them.
866 if (isZero() || isIntegralPointer())
867 return toAPValue(ASTCtx);
868
869 // Just load primitive types.
870 if (OptPrimType T = Ctx.classify(ResultType)) {
871 TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
872 }
873
874 // Return the composite type.
876 if (!Composite(ResultType, *this, Result))
877 return std::nullopt;
878 return Result;
879}
880
882 unsigned Offset) const {
883 if (!this->Desc)
884 return *this;
885 const Record *R = this->Desc->ElemRecord;
886 if (!R)
887 return *this;
888
889 const Record::Field *F = nullptr;
890 for (auto &It : R->fields()) {
891 if (It.Offset == Offset) {
892 F = &It;
893 break;
894 }
895 }
896 if (!F)
897 return *this;
898
899 const FieldDecl *FD = F->Decl;
900 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
901 unsigned FieldIndex = FD->getFieldIndex();
902 uint64_t FieldOffset =
903 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
904 .getQuantity();
905 return IntPointer{F->Desc, this->Value + FieldOffset};
906}
907
909 unsigned BaseOffset) const {
910 if (!Desc) {
911 assert(Value == 0);
912 return *this;
913 }
914 const Record *R = Desc->ElemRecord;
915 const Descriptor *BaseDesc = nullptr;
916
917 // This iterates over bases and checks for the proper offset. That's
918 // potentially slow but this case really shouldn't happen a lot.
919 for (const Record::Base &B : R->bases()) {
920 if (B.Offset == BaseOffset) {
921 BaseDesc = B.Desc;
922 break;
923 }
924 }
925 assert(BaseDesc);
926
927 // Adjust the offset value based on the information from the record layout.
928 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
929 CharUnits BaseLayoutOffset =
930 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
931
932 return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
933}
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:228
#define TYPE_SWITCH(Expr, B)
Definition: PrimType.h:207
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD)
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:207
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition: APValue.h:215
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
APValue & getArrayInitializedElt(unsigned I)
Definition: APValue.h:576
std::string getAsString(const ASTContext &Ctx, QualType Ty) const
Definition: APValue.cpp:956
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:188
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.
CanQualType getCanonicalTagType(const TagDecl *TD) const
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:201
CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const
getBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:250
CharUnits getVBaseClassOffset(const CXXRecordDecl *VBase) const
getVBaseClassOffset - Get the offset, in chars, for the given base class.
Definition: RecordLayout.h:260
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: TypeBase.h:3293
Decl()=delete
Symbolic representation of a dynamic allocation.
Definition: APValue.h:65
This represents one expression.
Definition: Expr.h:112
Represents a member of a struct/union/class.
Definition: Decl.h:3157
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition: Decl.h:3242
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition: Decl.h:3393
Represents a function declaration or definition.
Definition: Decl.h:1999
A (possibly-)qualified type.
Definition: TypeBase.h:937
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: TypeBase.h:1004
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition: Decl.h:4493
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
Definition: TypeBase.h:6502
Symbolic representation of typeid(T) for some type T.
Definition: APValue.h:44
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition: Type.h:41
bool isArrayType() const
Definition: TypeBase.h:8679
bool isIntegerType() const
isIntegerType() does not include complex integers (a GCC extension).
Definition: TypeBase.h:8980
bool isReferenceType() const
Definition: TypeBase.h:8604
bool isFloatingType() const
Definition: Type.cpp:2308
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:711
QualType getType() const
Definition: Decl.h:722
Represents a GCC generic vector type.
Definition: TypeBase.h:4191
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:44
unsigned getSize() const
Returns the size of the block.
Definition: InterpBlock.h:87
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition: InterpBlock.h:73
std::byte * rawData()
Returns a pointer to the raw data, including metadata.
Definition: InterpBlock.h:111
Holds all information required to evaluate constexpr code in a module.
Definition: Context.h:41
If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.
Definition: Floating.h:35
APFloat getAPFloat() const
Definition: Floating.h:63
const Function * getFunction() const
std::string toDiagnosticString(const ASTContext &Ctx) const
const BlockExpr * getExpr() const
Definition: Function.h:112
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition: Function.h:109
A pointer to a memory block, live or dead.
Definition: Pointer.h:90
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:618
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:614
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:432
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:490
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition: Pointer.h:505
bool inUnion() const
Definition: Pointer.h:398
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition: Pointer.h:650
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition: Pointer.cpp:454
FunctionPointer Fn
Definition: Pointer.h:820
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition: Pointer.h:543
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition: Pointer.cpp:322
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:608
bool isActive() const
Checks if the object is active.
Definition: Pointer.h:532
Pointer atField(unsigned Off) const
Creates a pointer to a field.
Definition: Pointer.h:172
T & deref() const
Dereferences the pointer, if it's live.
Definition: Pointer.h:659
unsigned getNumElems() const
Returns the number of elements.
Definition: Pointer.h:592
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:312
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:411
void activate() const
Activats a field.
Definition: Pointer.cpp:560
static std::optional< std::pair< Pointer, Pointer > > computeSplitPoint(const Pointer &A, const Pointer &B)
Definition: Pointer.cpp:670
const TypeidPointer & asTypeidPointer() const
Definition: Pointer.h:459
bool isIntegralPointer() const
Definition: Pointer.h:465
QualType getType() const
Returns the type of the innermost field.
Definition: Pointer.h:332
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:417
void initializeAllElements() const
Initialize all elements of a primitive array at once.
Definition: Pointer.cpp:530
bool pointsToStringLiteral() const
Definition: Pointer.cpp:658
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition: Pointer.h:390
bool isLive() const
Checks if the pointer is live.
Definition: Pointer.h:264
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition: Pointer.cpp:647
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:303
bool isTypeidPointer() const
Definition: Pointer.h:467
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition: Pointer.cpp:419
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:253
Pointer & operator=(const Pointer &P)
Definition: Pointer.cpp:93
const IntPointer & asIntPointer() const
Definition: Pointer.h:451
bool isRoot() const
Pointer points directly to a block.
Definition: Pointer.h:433
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:278
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition: Pointer.cpp:636
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
Definition: Pointer.cpp:167
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:625
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:642
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition: Pointer.h:639
Pointer expand() const
Expands a pointer to the containing array, undoing narrowing.
Definition: Pointer.h:220
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition: Pointer.h:647
bool isBlockPointer() const
Definition: Pointer.h:464
BlockPointer BS
Definition: Pointer.h:819
TypeidPointer Typeid
Definition: Pointer.h:821
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition: Pointer.cpp:711
const FunctionPointer & asFunctionPointer() const
Definition: Pointer.h:455
bool allElementsInitialized() const
Definition: Pointer.cpp:543
const Block * block() const
Definition: Pointer.h:598
bool isFunctionPointer() const
Definition: Pointer.h:466
Pointer getDeclPtr() const
Definition: Pointer.h:351
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:322
bool isVirtualBaseClass() const
Definition: Pointer.h:539
size_t computeOffsetForComparison() const
Compute an integer that can be used to compare this pointer to another one.
Definition: Pointer.cpp:360
const BlockPointer & asBlockPointer() const
Definition: Pointer.h:447
void initialize() const
Initializes a field.
Definition: Pointer.cpp:483
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:270
const Record * getRecord() const
Returns the record descriptor of a class.
Definition: Pointer.h:470
Structure/Class descriptor.
Definition: Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition: Record.h:53
bool isUnion() const
Checks if the record is a union.
Definition: Record.h:57
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:58
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
#define bool
Definition: gpuintrin.h:32
std::optional< std::pair< bool, std::shared_ptr< InitMap > > > InitMapPtr
Definition: Descriptor.h:30
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
int const char * function
Definition: c++config.h:31
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...
unsigned Base
Start of the current subfield.
Definition: Pointer.h:39
Block * Pointee
The block the pointer is pointing to.
Definition: Pointer.h:37
Describes a memory block created by an allocation site.
Definition: Descriptor.h:122
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:249
QualType getElemQualType() const
Definition: Descriptor.cpp:390
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:214
const Decl * asDecl() const
Definition: Descriptor.h:210
QualType getDataType(const ASTContext &Ctx) const
Definition: Descriptor.cpp:414
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:168
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:254
const FieldDecl * asFieldDecl() const
Definition: Descriptor.h:222
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition: Descriptor.h:153
const Expr * asExpr() const
Definition: Descriptor.h:211
Descriptor used for global variables.
Definition: Descriptor.h:51
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition: Descriptor.h:89
unsigned Offset
Offset inside the structure/array.
Definition: Descriptor.h:69
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition: Descriptor.h:80
IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const
Definition: Pointer.cpp:908
IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const
Definition: Pointer.cpp:881
const Descriptor * Desc
Definition: Pointer.h:47
const Type * TypeInfoType
Definition: Pointer.h:56