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