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