Thanks to visit codestin.com
Credit goes to clang.llvm.org

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