clang 24.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 "Char.h"
12#include "Context.h"
13#include "Floating.h"
14#include "Function.h"
15#include "InitMap.h"
16#include "Integral.h"
17#include "InterpBlock.h"
18#include "MemberPointer.h"
19#include "PrimType.h"
20#include "Record.h"
21#include "clang/AST/Expr.h"
22#include "clang/AST/ExprCXX.h"
24
25using namespace clang;
26using namespace clang::interp;
27
28// Helper to check if a Type can be passed to
29// ASTContext::getRecordLayout().
30static bool validType(QualType T) {
31 if (const RecordDecl *RD = T->getAsRecordDecl())
32 return ASTContext::hasLayout(RD);
33 return true;
34}
35
37 : Pointer(Pointee, Pointee->getMetadataSize(), Pointee->getMetadataSize()) {
38}
39
40Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
41 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
42
43Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
44 : Offset(Offset), StorageKind(Storage::Block) {
45 assert(Pointee);
46 assert(Base % alignof(void *) == 0 && "wrong base");
47 assert(Base >= Pointee->getMetadataSize());
48
49 BS = {Pointee, Base, nullptr, nullptr};
50 Pointee->addPointer(this);
51}
52
54 : Offset(P.Offset), StorageKind(P.StorageKind) {
55 switch (StorageKind) {
56 case Storage::Int:
57 Int = P.Int;
58 break;
59 case Storage::Block:
60 BS = P.BS;
61 if (BS.Pointee)
62 BS.Pointee->addPointer(this);
63 break;
64 case Storage::Fn:
65 Fn = P.Fn;
66 break;
67 case Storage::Typeid:
68 Typeid = P.Typeid;
69 break;
70 case Storage::String:
71 Str = P.Str;
72 break;
73 case Storage::Opaque:
74 Opaque = P.Opaque;
75 break;
76 }
77}
78
79Pointer::Pointer(Pointer &&P) : Offset(P.Offset), StorageKind(P.StorageKind) {
80 switch (StorageKind) {
81 case Storage::Int:
82 Int = P.Int;
83 break;
84 case Storage::Block:
85 BS = P.BS;
86 if (BS.Pointee)
87 BS.Pointee->replacePointer(&P, this);
88 break;
89 case Storage::Fn:
90 Fn = P.Fn;
91 break;
92 case Storage::Typeid:
93 Typeid = P.Typeid;
94 break;
95 case Storage::String:
96 Str = P.Str;
97 break;
98 case Storage::Opaque:
99 Opaque = P.Opaque;
100 break;
101 }
102}
103
105 if (!isBlockPointer())
106 return;
107
108 if (Block *Pointee = BS.Pointee) {
109 Pointee->removePointer(this);
110 BS.Pointee = nullptr;
111 Pointee->cleanup();
112 }
113}
114
116 // If the current storage type is Block, we need to remove
117 // this pointer from the block.
118 if (isBlockPointer()) {
119 if (P.isBlockPointer() && this->block() == P.block()) {
120 Offset = P.Offset;
121 BS.Base = P.BS.Base;
122 return *this;
123 }
124
125 if (Block *Pointee = BS.Pointee) {
126 Pointee->removePointer(this);
127 BS.Pointee = nullptr;
128 Pointee->cleanup();
129 }
130 }
131
132 StorageKind = P.StorageKind;
133 Offset = P.Offset;
134
135 switch (StorageKind) {
136 case Storage::Int:
137 Int = P.Int;
138 break;
139 case Storage::Block:
140 BS = P.BS;
141
142 if (BS.Pointee)
143 BS.Pointee->addPointer(this);
144 break;
145 case Storage::Fn:
146 Fn = P.Fn;
147 break;
148 case Storage::Typeid:
149 Typeid = P.Typeid;
150 break;
151 case Storage::String:
152 Str = P.Str;
153 break;
154 case Storage::Opaque:
155 Opaque = P.Opaque;
156 break;
157 }
158 return *this;
159}
160
162 // If the current storage type is Block, we need to remove
163 // this pointer from the block.
164 if (isBlockPointer()) {
165 if (P.isBlockPointer() && this->block() == P.block()) {
166 Offset = P.Offset;
167 BS.Base = P.BS.Base;
168 return *this;
169 }
170
171 if (Block *Pointee = BS.Pointee) {
172 Pointee->removePointer(this);
173 BS.Pointee = nullptr;
174 Pointee->cleanup();
175 }
176 }
177
178 StorageKind = P.StorageKind;
179 Offset = P.Offset;
180
181 switch (StorageKind) {
182 case Storage::Int:
183 Int = P.Int;
184 break;
185 case Storage::Block:
186 BS = P.BS;
187
188 if (BS.Pointee)
189 BS.Pointee->addPointer(this);
190 break;
191 case Storage::Fn:
192 Fn = P.Fn;
193 break;
194 case Storage::Typeid:
195 Typeid = P.Typeid;
196 break;
197 case Storage::String:
198 Str = P.Str;
199 break;
200 case Storage::Opaque:
201 Opaque = P.Opaque;
202 break;
203 }
204 return *this;
205}
206
209
210 if (isZero())
212 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
213
214 switch (StorageKind) {
215 case Storage::Int:
216 return APValue(static_cast<const Expr *>(nullptr),
218 Path,
219 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
220 case Storage::Block:
221 // See below.
222 break;
223 case Storage::Fn: {
225 if (const FunctionDecl *FD = FP.Func->getDecl())
226 return APValue(FD, CharUnits::fromQuantity(Offset), {},
227 /*OnePastTheEnd=*/false, /*IsNull=*/false);
228 return APValue(FP.Func->getExpr(), CharUnits::fromQuantity(Offset), {},
229 /*OnePastTheEnd=*/false, /*IsNull=*/false);
230 } break;
231 case Storage::Typeid: {
234 TypeInfo, QualType(Typeid.TypeInfoType, 0)),
235 CharUnits::Zero(), {},
236 /*OnePastTheEnd=*/false, /*IsNull=*/false);
237 } break;
238 case Storage::String:
239 if (Offset != 0 || Str.Decayed)
240 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Offset));
241
242 return APValue(APValue::LValueBase(Str.Base),
243 CharUnits::fromQuantity(Offset * elemSize()), Path,
244 /*OnePastTheEnd=*/false, /*IsNull=*/false);
245 case Storage::Opaque:
247 /*IsOnePastEnd=*/Opaque.isOnePastEnd(), /*IsNullPtr=*/false);
248 }
249
250 assert(isBlockPointer());
251 // Build the lvalue base from the block.
252 const Descriptor *Desc = getDeclDesc();
254 if (const auto *VD = Desc->asValueDecl())
255 Base = VD;
256 else if (const auto *E = Desc->asExpr()) {
257 if (block()->isDynamic()) {
258 QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
259 DynamicAllocLValue DA(*block()->DynAllocId);
260 Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
261 } else {
262 Base = E;
263 }
264 } else
265 llvm_unreachable("Invalid allocation type");
266
267 CharUnits Offset = CharUnits::Zero();
268
269 auto getFieldOffset = [&](const FieldDecl *FD) -> std::optional<CharUnits> {
270 if (!ASTContext::hasLayout(FD->getParent()))
271 return std::nullopt;
272 // This shouldn't happen, but if it does, don't crash inside
273 // getASTRecordLayout.
274 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
275 unsigned FieldIndex = FD->getFieldIndex();
276 return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
277 };
278
279 // Build the path into the object.
280 bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
281
282 PtrView Ptr = view();
283 while (Ptr.isField() || Ptr.isArrayElement()) {
284
285 if (Ptr.isArrayRoot()) {
286 // An array root may still be an array element itself.
287 if (Ptr.isArrayElement()) {
288 Ptr = Ptr.expand();
289 const Descriptor *Desc = Ptr.getFieldDesc();
290 unsigned Index = Ptr.getIndex();
291 QualType ElemType = Desc->getElemQualType();
292 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
293 if (Ptr.getArray().getFieldDesc()->IsArray)
294 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
295 Ptr = Ptr.getArray();
296 } else {
297 const Descriptor *Desc = Ptr.getFieldDesc();
298 const auto *Dcl = Desc->asDecl();
299 Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
300
301 if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl)) {
302 if (std::optional<CharUnits> FieldOffset = getFieldOffset(FD))
303 Offset += *FieldOffset;
304 else
305 return APValue();
306 }
307
308 Ptr = Ptr.getBase();
309 }
310 } else if (Ptr.isArrayElement()) {
311 Ptr = Ptr.expand();
312 const Descriptor *Desc = Ptr.getFieldDesc();
313 unsigned Index;
314 if (Ptr.isOnePastEnd()) {
315 Index = Ptr.getArray().getNumElems();
316 OnePastEnd = false;
317 } else
318 Index = Ptr.getIndex();
319
320 QualType ElemType = Desc->getElemQualType();
321 if (const auto *RD = ElemType->getAsRecordDecl();
322 RD && !RD->getDefinition()) {
323 // Ignore this for the offset.
324 } else {
325 Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
326 }
327 if (Ptr.getArray().getFieldDesc()->IsArray)
328 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
329 Ptr = Ptr.getArray();
330 } else {
331 const Descriptor *Desc = Ptr.getFieldDesc();
332
333 // Create a path entry for the field.
334 if (const auto *BaseOrMember = Desc->asDecl()) {
335 bool IsVirtual = false;
336 if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
337 Ptr = Ptr.getBase();
338 if (std::optional<CharUnits> FieldOffset = getFieldOffset(FD))
339 Offset += *FieldOffset;
340 else
341 return APValue();
342 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
343 IsVirtual = Ptr.isVirtualBaseClass();
344 Ptr = Ptr.getBase();
345 const Record *BaseRecord = Ptr.getRecord();
346
347 if (!ASTContext::hasLayout(BaseRecord->getDecl()))
348 return APValue();
349
350 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
351 cast<CXXRecordDecl>(BaseRecord->getDecl()));
352 if (IsVirtual)
353 Offset += Layout.getVBaseClassOffset(RD);
354 else
355 Offset += Layout.getBaseClassOffset(RD);
356
357 } else {
358 Ptr = Ptr.getBase();
359 }
360 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
361 continue;
362 }
363 llvm_unreachable("Invalid field type");
364 }
365 }
366
367 // We assemble the LValuePath starting from the innermost pointer to the
368 // outermost one. SO in a.b.c, the first element in Path will refer to
369 // the field 'c', while later code expects it to refer to 'a'.
370 // Just invert the order of the elements.
371 std::reverse(Path.begin(), Path.end());
372
373 auto Result = APValue(Base, Offset, Path, OnePastEnd);
374 Result.setConstexprUnknown(isConstexprUnknown());
375 return Result;
376}
377
378void Pointer::print(llvm::raw_ostream &OS) const {
379 switch (StorageKind) {
380 case Storage::Block: {
381 const Block *B = BS.Pointee;
382 OS << "(Block) " << B << " {";
383
384 if (isRoot())
385 OS << "rootptr(" << BS.Base << "), ";
386 else
387 OS << BS.Base << ", ";
388
389 if (isElementPastEnd())
390 OS << "pastend, ";
391 else
392 OS << Offset << ", ";
393
394 if (B)
395 OS << B->getSize();
396 else
397 OS << "nullptr";
398 OS << "}";
399 } break;
400 case Storage::Int:
401 OS << "(Int) {" << Int.Value << " + " << Offset << ", " << Int.Ty << "}";
402 break;
403 case Storage::Fn:
404 OS << "(Fn) { " << Fn.Func << " + " << Offset << " }";
405 break;
406 case Storage::Typeid:
407 OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
408 << (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
409 << "}";
410 break;
411 case Storage::String:
412 OS << "(String) { " << (const void *)Str.getLiteral() << ' ';
413 Str.getLiteral()->outputString(OS);
414 OS << ". ID: " << Str.ID << " + " << Offset << "}";
415 break;
416 case Storage::Opaque:
417 OS << "(Opaque) { Base: " << Opaque.Base << ", "
418 << Opaque.FieldType.getPointer() << " Length: " << Opaque.PathLength
419 << ". PastEnd: " << Opaque.isOnePastEnd();
420 OS << "} + " << Offset;
421 break;
422 }
423}
424
425/// Compute an offset that can be used to compare the pointer to another one
426/// with the same base. To get accurate results, we basically _have to_ compute
427/// the lvalue offset using the ASTRecordLayout.
428///
429/// This function will fail if we're trying to get the type size of a forward
430/// declaration.
431///
432// FIXME: We're still mixing values from the record layout with our internal
433// offsets, which will inevitably lead to cryptic errors.
434std::optional<size_t>
436 switch (StorageKind) {
437 case Storage::Int:
438 return Int.Value + Offset;
439 case Storage::Block:
440 // See below.
441 break;
442 case Storage::Fn:
444 case Storage::Typeid:
445 return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
446 case Storage::String:
447 return reinterpret_cast<uintptr_t>(Str.getLiteral()) + Offset;
448 case Storage::Opaque:
449 return reinterpret_cast<uintptr_t>(asOpaquePointer().Base) + Offset;
450 }
451
452 auto getTypeSize = [&](QualType T) -> std::optional<size_t> {
453 if (!validType(T))
454 return std::nullopt;
455 return ASTCtx.getTypeSizeInChars(T).getQuantity();
456 };
457
458 size_t Result = 0;
459 PtrView P = view();
460 while (true) {
461 if (P.isVirtualBaseClass()) {
462 Result += getInlineDesc()->Offset;
463 P = P.getBase();
464 continue;
465 }
466
467 if (P.isBaseClass()) {
469 P = P.getBase();
470 continue;
471 }
472 if (P.isArrayElement()) {
473 P = P.expand();
474 Result += (P.getIndex() * P.elemSize());
475 P = P.getArray();
476 continue;
477 }
478
479 if (P.isRoot()) {
480 if (P.isOnePastEnd()) {
481 if (auto Size = getTypeSize(P.getDeclDesc()->getType()))
482 Result += *Size;
483 else
484 return std::nullopt;
485 }
486 break;
487 }
488
489 assert(P.getField());
490 const Record *R = P.getBase().getRecord();
491 assert(R);
492
493 if (!ASTContext::hasLayout(R->getDecl()))
494 return std::nullopt;
495 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
496 Result += ASTCtx
499 .getQuantity();
500
501 if (P.isOnePastEnd()) {
502 if (auto Size = getTypeSize(P.getField()->getType()))
503 Result += *Size;
504 else
505 return std::nullopt;
506 }
507
508 P = P.getBase();
509 if (P.isRoot())
510 break;
511 }
512 return Result;
513}
514
515std::optional<size_t>
517 switch (StorageKind) {
518 case Storage::Int:
519 return Int.Value + Offset;
520 case Storage::Block:
521 // See below.
522 break;
523 case Storage::Fn:
525 case Storage::Typeid:
526 return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
527 case Storage::String:
528 return Offset * Str.getLiteral()->getCharByteWidth();
529 case Storage::Opaque:
530 return Opaque.computeLayoutOffset(ASTCtx);
531 }
532
533 auto getTypeSize = [&](QualType T) -> std::optional<size_t> {
534 if (!validType(T))
535 return std::nullopt;
536 return ASTCtx.getTypeSizeInChars(T).getQuantity();
537 };
538
539 auto getRecordDecl = [&](PtrView P) -> const CXXRecordDecl * {
540 if (const Record *R = P.getRecord())
541 return cast<CXXRecordDecl>(R->getDecl());
542 return cast<CXXRecordDecl>(P.getFieldDesc()->asDecl());
543 };
544
545 auto getRecordSize = [&](const RecordDecl *RD) -> unsigned {
546 CanQualType RecordTy = ASTCtx.getCanonicalTagType(RD);
547 return ASTCtx.getTypeSizeInChars(RecordTy).getQuantity();
548 };
549
550 size_t Result = 0;
551 PtrView P = view();
552 while (true) {
553 if (P.isBaseClass()) {
554 const CXXRecordDecl *BaseRD = getRecordDecl(P.getBase());
555 if (!ASTContext::hasLayout(BaseRD))
556 return std::nullopt;
557 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(BaseRD);
558 const CXXRecordDecl *RD = getRecordDecl(P);
559 if (P.isVirtualBaseClass())
560 Result += Layout.getVBaseClassOffset(RD).getQuantity();
561 else
562 Result += Layout.getBaseClassOffset(RD).getQuantity();
563
564 if (P.isOnePastEnd())
565 Result += getRecordSize(RD);
566
567 P = P.getBase();
568 continue;
569 }
570
571 if (P.isArrayElement()) {
572 P = P.expand();
573 assert(P.getFieldDesc()->isArray());
574 if (std::optional<size_t> ElemSize =
575 getTypeSize(P.getFieldDesc()->getElemQualType()))
576 Result += *ElemSize * P.getIndex();
577 else
578 return std::nullopt;
579
580 P = P.getArray();
581 continue;
582 }
583
584 if (P.isRoot()) {
585 if (P.isPastEnd() || P.isOnePastEnd()) {
586 if (std::optional<size_t> Size =
587 getTypeSize(P.getDeclDesc()->getType()))
588 Result += *Size * P.getIndex();
589 else
590 return std::nullopt;
591 }
592 break;
593 }
594
595 assert(P.getField());
596 const FieldDecl *F = P.getField();
598 return std::nullopt;
599 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(F->getParent());
600 Result +=
602 .getQuantity();
603
604 if (P.isPastEnd() || P.isOnePastEnd()) {
605 if (std::optional<size_t> Size = getTypeSize(F->getType()))
606 Result += *Size * P.getIndex();
607 else
608 return std::nullopt;
609 }
610
611 P = P.getBase();
612 if (P.isRoot())
613 break;
614 }
615 return Result;
616}
617
618std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
619 if (isZero())
620 return "nullptr";
621
622 if (isIntegralPointer())
623 return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
624
625 QualType Ty = getType();
626 if (Ty->isLValueReferenceType())
627 Ty = Ty->getPointeeType();
628 return toAPValue(Ctx).getAsString(Ctx, Ty);
629}
630
632 if (!isBlockPointer())
633 return true;
634
635 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
636 Offset == BS.Base) {
637 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
639 }
640
641 assert(BS.Pointee && "Cannot check if null pointer was initialized");
642 const Descriptor *Desc = getFieldDesc();
643 assert(Desc);
644 if (Desc->isPrimitiveArray())
646
647 if (asBlockPointer().Base == 0)
648 return true;
649 // Field has its bit in an inline descriptor.
650 return getInlineDesc()->IsInitialized;
651}
652
653bool PtrView::isElementInitialized(unsigned Index) const {
654 const Descriptor *Desc = getFieldDesc();
655 assert(Desc);
656
657 if (Pointee->isStatic() && Base == 0)
658 return true;
659
660 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
661 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
663 }
664
665 if (Desc->isPrimitiveArray()) {
666 InitMapPtr IM = getInitMap();
667
668 if (IM.allInitialized())
669 return true;
670
671 if (!IM.hasInitMap())
672 return false;
673 return IM->isElementInitialized(Index);
674 }
675 return isInitialized();
676}
677
678bool Pointer::isElementAlive(unsigned Index) const {
679 assert(getFieldDesc()->isPrimitiveArray());
680
681 InitMapPtr &IM = getInitMap();
682 if (!IM.hasInitMap())
683 return true;
684
685 if (IM.allInitialized())
686 return true;
687
688 return IM->isElementAlive(Index);
689}
690
692 if (Base < sizeof(InlineDescriptor))
693 return Lifetime::Started;
694
695 if (inArray() && !isArrayRoot()) {
696 InitMapPtr &IM = getInitMap();
697
698 if (!IM.hasInitMap()) {
699 if (IM.allInitialized())
700 return Lifetime::Started;
701 return getArray().getLifetime();
702 }
703
705 }
706
707 return getInlineDesc()->LifeState;
708}
709
711 if (Base < sizeof(InlineDescriptor))
712 return;
713
714 if (inArray() && !isArrayRoot()) {
715 assert(L == Lifetime::Started || L == Lifetime::Ended);
716 const Descriptor *Desc = getFieldDesc();
717 InitMapPtr &IM = getInitMap();
718 if (!IM.hasInitMap())
719 IM.setInitMap(new InitMap(Desc->getNumElems(), IM.allInitialized()));
720
721 if (L == Lifetime::Ended)
723 else if (L == Lifetime::Started)
725 assert(isArrayRoot() || (this->getLifetime() == L));
726 return;
727 }
728
730}
731
733 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
734 auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
736 return;
737 }
738
739 const Descriptor *Desc = getFieldDesc();
740 assert(Desc);
741 if (Desc->isPrimitiveArray()) {
742 if (Desc->getNumElems() != 0)
744 return;
745 }
746
747 // Field has its bit in an inline descriptor.
748 assert(Base != 0 && "Only composite fields can be initialised");
751}
752
753void PtrView::initializeElement(unsigned Index) const {
754 // Primitive global arrays don't have an initmap.
755 if (Pointee->isStatic() && Base == 0)
756 return;
757
758 assert(Index < getFieldDesc()->getNumElems());
759
760 InitMapPtr &IM = getInitMap();
761 if (IM.allInitialized())
762 return;
763
764 if (!IM.hasInitMap()) {
765 const Descriptor *Desc = getFieldDesc();
766 IM.setInitMap(new InitMap(Desc->getNumElems()));
767 }
768 assert(IM.hasInitMap());
769
770 if (IM->initializeElement(Index))
772}
773
775 assert(getFieldDesc()->isPrimitiveArray());
776 assert(isArrayRoot());
777
778 getInitMap().noteAllInitialized();
779}
780
782 assert(getFieldDesc()->isPrimitiveArray());
783 assert(isArrayRoot());
784
785 if (Pointee->isStatic() && Base == 0)
786 return true;
787
788 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
789 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
791 }
792
793 InitMapPtr IM = getInitMap();
794 return IM.allInitialized();
795}
796
798 assert(getFieldDesc()->isPrimitiveArray());
799 assert(isArrayRoot());
800
801 if (isStatic() && BS.Base == 0)
802 return true;
803
804 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
805 Offset == BS.Base) {
806 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
808 }
809
810 InitMapPtr &IM = getInitMap();
811 return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive());
812}
813
814void PtrView::activate() const {
815 // Field has its bit in an inline descriptor.
816 assert(Base != 0 && "Only composite fields can be activated");
817
818 if (isRoot() && Base == sizeof(GlobalInlineDescriptor))
819 return;
820 if (!getInlineDesc()->InUnion)
821 return;
822
824 activate = [&activate](PtrView P) -> void {
825 P.getInlineDesc()->IsActive = true;
826 P.startLifetime();
827 if (const Record *R = P.getRecord(); R && !R->isUnion()) {
828 for (const Record::Field &F : R->fields()) {
829 PtrView FieldPtr = P.atField(F.Offset);
830 if (!FieldPtr.getInlineDesc()->IsActive)
831 activate(FieldPtr);
832 }
833 // FIXME: Bases?
834 }
835 };
836
837 std::function<void(PtrView &)> deactivate;
838 deactivate = [&deactivate](PtrView &P) -> void {
839 P.getInlineDesc()->IsActive = false;
840
841 if (const Record *R = P.getRecord()) {
842 for (const Record::Field &F : R->fields()) {
843 PtrView FieldPtr = P.atField(F.Offset);
844 if (FieldPtr.getInlineDesc()->IsActive)
845 deactivate(FieldPtr);
846 }
847 // FIXME: Bases?
848 }
849 };
850
851 PtrView B = *this;
852 // Primitive array elements can't be activated individually, so
853 // look at the array root instead.
855 B = B.getArray();
856
857 while (!B.isRoot() && B.inUnion()) {
858 activate(B);
859
860 // When walking up the pointer chain, deactivate
861 // all union child pointers that aren't on our path.
862 PtrView Cur = B;
863 B = B.getBase();
864 if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
865 for (const Record::Field &F : BR->fields()) {
866 PtrView FieldPtr = B.atField(F.Offset);
867 if (FieldPtr != Cur)
868 deactivate(FieldPtr);
869 }
870 }
871 }
872}
873
874bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
875 // Two null pointers always have the same base.
876 if (A.isZero() && B.isZero())
877 return true;
878
880 return true;
882 return true;
883 if (A.isTypeidPointer() && B.isTypeidPointer())
885 if (A.isStringPointer() && B.isStringPointer())
886 return A.Str.ID == B.Str.ID && A.Str.getLiteral() == B.Str.getLiteral();
887
888 if (A.StorageKind != B.StorageKind)
889 return false;
890
892}
893
894bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
895 if (!A.isBlockPointer() || !B.isBlockPointer())
896 return false;
897 return A.block() == B.block();
898}
899
900bool Pointer::elemsOfSameArray(const Pointer &A, const Pointer &B) {
901 assert(hasSameBase(A, B));
902 assert(A.isBlockPointer());
903 assert(B.isBlockPointer());
904
905 if (A.BS.Base == B.BS.Base)
906 return true;
907
908 if (A.isBaseClass() || B.isBaseClass())
909 return false;
910
911 if (A.getField() || B.getField())
912 return false;
913
914 auto closestArray = [](const Pointer &P) -> PtrView {
915 if (P.isArrayRoot())
916 return P.view();
917
918 PtrView V = P.view();
919 if (V.isArrayElement() || V.isOnePastEnd())
920 V = V.expand().getArray();
921
922 if (P.isRoot())
923 return P.view();
924
925 while (!V.isRoot() && !V.getFieldDesc()->IsArray) {
926 if (V.isArrayElement()) {
927 V = V.expand().getArray();
928 break;
929 }
930 V = V.getBase();
931 }
932 return V;
933 };
934
935 if (closestArray(A) != closestArray(B))
936 return false;
937
938 return true;
939}
940
942 if (isZero() || !isBlockPointer())
943 return false;
944
945 if (block()->isDynamic())
946 return false;
947
948 const Expr *E = block()->getDescriptor()->asExpr();
950}
951
953 if (isZero() || !isBlockPointer())
954 return false;
955
956 if (const Expr *E = BS.Pointee->getDescriptor()->asExpr())
957 return isa<AddrLabelExpr>(E);
958 return false;
959}
960
961std::optional<std::pair<PtrView, PtrView>>
963 if (!A.isBlockPointer() || !B.isBlockPointer())
964 return std::nullopt;
965
967 return std::nullopt;
968 if (A.isRoot() && B.isRoot())
969 return std::nullopt;
970
971 if (A == B)
972 return std::make_pair(A.view(), B.view());
973
974 auto getBase = [](PtrView P) -> PtrView {
975 if (P.isArrayElement())
976 return P.expand().getArray();
977 return P.getBase();
978 };
979
980 PtrView IterA = A.view();
981 PtrView IterB = B.view();
982 PtrView CurA = IterA;
983 PtrView CurB = IterB;
984 for (;;) {
985 if (IterA.Base > IterB.Base) {
986 CurA = IterA;
987 IterA = getBase(IterA);
988 } else {
989 CurB = IterB;
990 IterB = getBase(IterB);
991 }
992
993 if (IterA == IterB) {
994 // If the Iter is an array, CurA and CurB are both elements of the same
995 // array. That is fine, so return nullopt.
996 if (IterA.getFieldDesc()->isArray())
997 return std::nullopt;
998 return std::make_pair(CurA, CurB);
999 }
1000
1001 if (IterA.isRoot() && IterB.isRoot())
1002 return std::nullopt;
1003 }
1004
1005 llvm_unreachable("The loop above should've returned.");
1006}
1007
1008/// Convert a pointer to a composite value to an rvalue.
1009static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R) {
1010 const ASTContext &ASTCtx = Ctx.getASTContext();
1011 if (const auto *AT = Ty->getAs<AtomicType>())
1012 Ty = AT->getValueType();
1013
1014 // Invalid pointers.
1015 if (Ptr.isDummy() || !Ptr.isLive() || Ptr.isPastEnd())
1016 return false;
1017
1018 // Primitives should never end up here.
1019 assert(!Ctx.canClassify(Ty));
1020 const Descriptor *FieldDesc = Ptr.getFieldDesc();
1021 assert(FieldDesc);
1022
1023 if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
1024 if (!FieldDesc->isRecord())
1025 return false;
1026 const auto *Record = Ptr.getRecord();
1027 assert(Record && "Missing record descriptor");
1028
1029 bool Ok = true;
1030 if (RT->getDecl()->isUnion()) {
1031 const FieldDecl *ActiveField = nullptr;
1032 APValue Value;
1033 for (const auto &F : Record->fields()) {
1034 PtrView FP = Ptr.atField(F.Offset);
1035 if (FP.isActive()) {
1036 const Descriptor *Desc = F.Desc;
1037 if (Desc->isPrimitive()) {
1038 TYPE_SWITCH(Desc->getPrimType(),
1039 Value = FP.deref<T>().toAPValue(ASTCtx));
1040 } else {
1041 QualType FieldTy = F.Decl->getType();
1042 Ok &= toRValue(Ctx, FieldTy, FP, Value);
1043 }
1044 ActiveField = FP.getFieldDesc()->asFieldDecl();
1045 break;
1046 }
1047 }
1048 R = APValue(ActiveField, Value);
1049 } else {
1050 unsigned NF = Record->getNumFields();
1051 unsigned NB = Record->getNumBases();
1052 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
1053
1054 R = APValue(APValue::UninitStruct(), NB, NF, NV);
1055
1056 for (unsigned I = 0; I != NF; ++I) {
1057 const Record::Field *FD = Record->getField(I);
1058 const Descriptor *Desc = FD->Desc;
1059 PtrView FP = Ptr.atField(FD->Offset);
1060 APValue &Value = R.getStructField(I);
1061 if (Desc->isPrimitive()) {
1062 TYPE_SWITCH(Desc->getPrimType(),
1063 Value = FP.deref<T>().toAPValue(ASTCtx));
1064 } else {
1065 QualType FieldTy = FD->Decl->getType();
1066 Ok &= toRValue(Ctx, FieldTy, FP, Value);
1067 }
1068 }
1069
1070 for (unsigned I = 0; I != NB; ++I) {
1071 const Record::Base *BD = Record->getBase(I);
1072 QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
1073 PtrView BP = Ptr.atField(BD->Offset);
1074 Ok &= toRValue(Ctx, BaseTy, BP, R.getStructBase(I));
1075 }
1076
1077 for (unsigned I = 0; I != NV; ++I) {
1078 const Record::Base *VD = Record->getVirtualBase(I);
1079 assert(VD);
1080 QualType VirtBaseTy = Ctx.getASTContext().getCanonicalTagType(VD->Decl);
1081 PtrView VP = Ptr.atField(VD->Offset);
1082 Ok &= toRValue(Ctx, VirtBaseTy, VP, R.getStructVirtualBase(I));
1083 }
1084 }
1085 return Ok;
1086 }
1087
1088 if (Ty->isIncompleteArrayType()) {
1089 R = APValue(APValue::UninitArray(), 0, 0);
1090 return true;
1091 }
1092
1093 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
1094 if (!FieldDesc->isArray())
1095 return false;
1096 const size_t NumElems = Ptr.getNumElems();
1097 QualType ElemTy = AT->getElementType();
1098 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
1099
1100 bool Ok = true;
1101 OptPrimType ElemT = Ctx.classify(ElemTy);
1102 for (unsigned I = 0; I != NumElems; ++I) {
1103 APValue &Slot = R.getArrayInitializedElt(I);
1104 if (ElemT) {
1105 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
1106 } else {
1107 Ok &= toRValue(Ctx, ElemTy, Ptr.atIndex(I).narrow(), Slot);
1108 }
1109 }
1110 return Ok;
1111 }
1112
1113 // Complex types.
1114 if (Ty->isAnyComplexType()) {
1115 // Can happen via C casts.
1116 if (!FieldDesc->getType()->isAnyComplexType())
1117 return false;
1118
1119 PrimType ElemT = FieldDesc->getPrimType();
1120 if (isIntegerOrBoolType(ElemT)) {
1121 INT_TYPE_SWITCH(ElemT, {
1122 auto V1 = Ptr.elem<T>(0);
1123 auto V2 = Ptr.elem<T>(1);
1124 R = APValue(V1.toAPSInt(), V2.toAPSInt());
1125 return true;
1126 });
1127 } else if (ElemT == PT_Float) {
1128 R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
1129 Ptr.elem<Floating>(1).getAPFloat());
1130 return true;
1131 }
1132 return false;
1133 }
1134
1135 // Vector types.
1136 if (const auto *VT = Ty->getAs<VectorType>()) {
1137 if (!FieldDesc->isPrimitiveArray())
1138 return false;
1139
1140 PrimType ElemT = FieldDesc->getPrimType();
1141 SmallVector<APValue> Values;
1142 Values.reserve(VT->getNumElements());
1143 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
1144 TYPE_SWITCH(ElemT,
1145 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1146 }
1147
1148 assert(Values.size() == VT->getNumElements());
1149 R = APValue(Values.data(), Values.size());
1150 return true;
1151 }
1152
1153 // Constant Matrix types.
1154 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
1155 if (!FieldDesc->isPrimitiveArray())
1156 return false;
1157 PrimType ElemT = FieldDesc->getPrimType();
1158 unsigned NumElems = MT->getNumElementsFlattened();
1159
1160 SmallVector<APValue> Values;
1161 Values.reserve(NumElems);
1162 for (unsigned I = 0; I != NumElems; ++I) {
1163 TYPE_SWITCH(ElemT,
1164 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1165 }
1166
1167 R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
1168 return true;
1169 }
1170
1171 llvm_unreachable("invalid value to return");
1172}
1173
1174std::optional<APValue> Pointer::toRValue(const Context &Ctx,
1175 QualType ResultType) const {
1176 const ASTContext &ASTCtx = Ctx.getASTContext();
1177 assert(!ResultType.isNull());
1178
1179 // Can't return functions as rvalues.
1180 if (ResultType->isFunctionType())
1181 return std::nullopt;
1182
1183 // Invalid to read from.
1184 if (isDummy() || !isLive() || isPastEnd() ||
1185 (isOnePastEnd() && !isZeroSizeArray()))
1186 return std::nullopt;
1187
1188 // We can return these as rvalues, but we can't deref() them.
1189 if (isZero() || isIntegralPointer())
1190 return toAPValue(ASTCtx);
1191
1192 // Just load primitive types.
1193 if (OptPrimType T = Ctx.classify(ResultType)) {
1194 if (!canDeref(*T))
1195 return std::nullopt;
1196 TYPE_SWITCH(*T, return this->load<T>().toAPValue(ASTCtx));
1197 }
1198
1199 if (!isBlockPointer())
1200 return std::nullopt;
1201
1202 // Return the composite type.
1204 if (!::toRValue(Ctx, ResultType, view(), Result))
1205 return std::nullopt;
1206 return Result;
1207}
1208
1210 if (isBlockPointer())
1211 return getDeclDesc()->asVarDecl();
1212 if (isOpaquePointer())
1213 return dyn_cast<VarDecl>(Opaque.Base);
1214 return nullptr;
1215}
1216
1218 if (isBlockPointer())
1219 return getDeclDesc()->asExpr();
1220 if (isStringPointer())
1221 return Str.getLiteral();
1222 return nullptr;
1223}
1224
1225std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx,
1226 unsigned Offset) const {
1227 QualType CurType = getPointeeType();
1228 if (CurType.isNull() || !CurType->isRecordType())
1229 return std::nullopt;
1230
1231 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1232 if (!R)
1233 return *this;
1234
1235 const Record::Field *F = R->findField(Offset);
1236 if (!F)
1237 return *this;
1238
1239 const FieldDecl *FD = F->Decl;
1240 if (FD->getParent()->isInvalidDecl())
1241 return std::nullopt;
1242
1243 const ASTContext &ASTCtx = Ctx.getASTContext();
1244 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
1245 unsigned FieldIndex = FD->getFieldIndex();
1246 uint64_t FieldOffset =
1247 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
1248 .getQuantity();
1249
1250 return IntPointer{FD->getType().getTypePtr(), this->Value + FieldOffset};
1251}
1252
1254 unsigned BaseOffset) const {
1255 if (!Ty)
1256 return *this;
1257
1258 QualType CurType = getPointeeType();
1259 if (CurType.isNull() || !CurType->isRecordType())
1260 return *this;
1261
1262 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1263
1264 // This iterates over bases and checks for the proper offset. That's
1265 // potentially slow but this case really shouldn't happen a lot.
1266 const Record::Base *B = R->findBase(BaseOffset);
1267 if (!B)
1268 return *this;
1269
1270 const Descriptor *BaseDesc = B->Desc;
1271 // Adjust the offset value based on the information from the record layout.
1272 const ASTContext &ASTCtx = Ctx.getASTContext();
1273 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
1274 CharUnits BaseLayoutOffset =
1275 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
1276
1277 const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
1279 std::nullopt, RD, false);
1280 return {T.getTypePtr(), Value + BaseLayoutOffset.getQuantity()};
1281}
1282
1283std::optional<size_t>
1285 size_t Offset = 0;
1286 QualType CurType = getObjectType();
1287 for (const PointerPathEntry &Entry : path()) {
1288 switch (Entry.Kind) {
1290 const RecordDecl *RD = CurType->getAsRecordDecl();
1291 if (!ASTContext::hasLayout(RD))
1292 return std::nullopt;
1293
1294 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
1295 Offset += Layout.getBaseClassOffset(Entry.RD.getPointer()).getQuantity();
1296
1297 CurType = ASTCtx.getCanonicalTagType(Entry.RD.getPointer());
1298 } break;
1299
1301 const FieldDecl *FD = Entry.FD;
1302 const RecordDecl *RD = FD->getParent();
1303 if (!ASTContext::hasLayout(RD))
1304 return std::nullopt;
1305
1306 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
1307 Offset +=
1309 .getQuantity();
1310
1311 CurType = FD->getType();
1312 } break;
1315 bool Add = (Entry.Kind == PointerPathEntry::Array);
1316 uint64_t Index = Entry.Index;
1317 if (!CurType->isArrayType()) {
1318 if (Add)
1319 Offset += Index * ASTCtx.getTypeSizeInChars(CurType).getQuantity();
1320 else
1321 Offset -= Index * ASTCtx.getTypeSizeInChars(CurType).getQuantity();
1322 continue;
1323 }
1324 const ArrayType *AT = CurType->getAsArrayTypeUnsafe();
1325 assert(AT);
1326 QualType ElemTy = AT->getElementType();
1327 if (!validType(ElemTy) || isa<VariableArrayType>(AT))
1328 return std::nullopt;
1329 if (Add)
1330 Offset += Index * ASTCtx.getTypeSizeInChars(ElemTy).getQuantity();
1331 else
1332 Offset -= Index * ASTCtx.getTypeSizeInChars(ElemTy).getQuantity();
1333 CurType = AT->getElementType();
1334 } break;
1335 }
1336 }
1337
1338 return Offset;
1339}
1340
1342 if (PathLength == 0)
1343 return getObjectType();
1344 if (Path[PathLength - 1].Kind != PointerPathEntry::Array)
1345 return getFieldType();
1346
1347 assert(Path[PathLength - 1].Kind == PointerPathEntry::Array);
1348 assert(isArrayElement());
1349
1350 QualType CurType = getObjectType();
1351 for (const PointerPathEntry &Entry : path().drop_back(1)) {
1352 switch (Entry.Kind) {
1354 CurType = Entry.RD.getPointer()->getASTContext().getCanonicalTagType(
1355 Entry.RD.getPointer());
1356 break;
1358 CurType = Entry.FD->getType();
1359 break;
1362 if (!CurType->isArrayType())
1363 break;
1364 CurType = CurType->getAsArrayTypeUnsafe()->getElementType();
1365 }
1366 }
1367 return CurType;
1368}
1369
1370/// Check if the pointer has offset 0.
1371// As an optimization, don't actually compute the offset.
1373 QualType CurType = getObjectType();
1374 for (const PointerPathEntry &Entry : path()) {
1375 switch (Entry.Kind) {
1377 if (Entry.RD.getInt())
1378 return false;
1379 CurType = Entry.RD.getPointer()->getASTContext().getCanonicalTagType(
1380 Entry.RD.getPointer());
1381 break;
1383 if (!Entry.FD->getParent()->isUnion() && Entry.FD->getFieldIndex() != 0)
1384 return false;
1385 CurType = Entry.FD->getType();
1386 break;
1388 if (Entry.Index != 0)
1389 return false;
1390 if (!CurType->isArrayType())
1391 continue;
1392 CurType = CurType->getAsArrayTypeUnsafe()->getElementType();
1393 break;
1395 return false;
1396 }
1397 }
1398 return true;
1399}
1400
1403
1404 if (isArrayElement())
1406
1407 bool Result = false;
1408 // If the field type is an IncompleteArrayType, we still need to check the
1409 // base to see if this array is a flexible array member _and_ has actually
1410 // been initialized by data we know the size of.
1412 const VarDecl *Base = cast<VarDecl>(this->Base);
1413 if (!Base || !Base->getType()->isRecordType() || !Base->hasInit())
1414 Result = true;
1415 else
1416 Result = !Base->hasFlexibleArrayInit(Base->getASTContext());
1418 Result = true;
1419
1420 return Result;
1421}
1422
1423/// This is used in Pointer::isOnePastEnd(). We cannot read from such pointers.
1424/// We can of course never read from opaque pointers anyway but we diagnose
1425/// one-past-the-end pointers differently.
1426///
1427/// In contrast, OpaquePointer::isOnePastEnd() only uses the past-end bit. That
1428/// is used for the APValue conversion.
1430 if (isOnePastEnd())
1431 return true;
1432
1433 if (PathLength == 0)
1434 return false;
1435
1436 if (Path[PathLength - 1].Kind != PointerPathEntry::Array)
1437 return false;
1438
1439 QualType ArrTy = getSurroundingArray();
1440 if (!ArrTy->isArrayType())
1441 return false;
1442 // FIXME: Flexible array members?
1443 if (const auto *CAT =
1444 dyn_cast<ConstantArrayType>(ArrTy->getAsArrayTypeUnsafe())) {
1445 if (Path[PathLength - 1].Index >= CAT->getZExtSize())
1446 return true;
1447 }
1448
1449 return false;
1450}
#define V(N, I)
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R)
Convert a pointer to a composite value to an rvalue.
Definition Pointer.cpp:1009
#define INT_TYPE_SWITCH(Expr, B)
Definition PrimType.h:256
#define TYPE_SWITCH(Expr, B)
Definition PrimType.h:235
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD)
static const RecordDecl * getRecordDecl(QualType QT)
Checks that the passed in QualType either is of RecordType or points to RecordType.
static bool hasLayout(const RecordDecl *D)
Whether layout (offset and size) information can be queried for D.
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:208
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition APValue.h:216
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
std::string getAsString(const ASTContext &Ctx, QualType Ty) const
Definition APValue.cpp:991
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:223
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
static bool hasLayout(const RecordDecl *D)
Whether layout (offset and size) information can be queried for D.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
QualType getTagType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TagDecl *TD, bool OwnsTag) const
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.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition TypeBase.h:3836
QualType getElementType() const
Definition TypeBase.h:3848
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
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
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4501
Decl()=delete
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
bool isInvalidDecl() const
Definition DeclBase.h:596
Symbolic representation of a dynamic allocation.
Definition APValue.h:65
This represents one expression.
Definition Expr.h:113
Represents a member of a struct/union/class.
Definition Decl.h:3295
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3380
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3531
Represents a function declaration or definition.
Definition Decl.h:2059
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8501
Represents a struct/union/class.
Definition Decl.h:4460
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition Decl.h:4644
Symbolic representation of typeid(T) for some type T.
Definition APValue.h:44
bool isIncompleteArrayType() const
Definition TypeBase.h:8845
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isArrayType() const
Definition TypeBase.h:8837
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:789
bool isLValueReferenceType() const
Definition TypeBase.h:8766
bool isAnyComplexType() const
Definition TypeBase.h:8873
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9390
bool isFunctionType() const
Definition TypeBase.h:8734
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2998
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9337
bool isRecordType() const
Definition TypeBase.h:8865
QualType getType() const
Definition Decl.h:724
Represents a variable declaration or definition.
Definition Decl.h:933
Represents a GCC generic vector type.
Definition TypeBase.h:4289
unsigned getSize() const
Returns the size of the block, including metadata.
Definition InterpBlock.h:91
const Descriptor * getDescriptor() const
Returns the block's descriptor.
Definition InterpBlock.h:77
unsigned getMetadataSize() const
Returns the size of the metadata.
Definition InterpBlock.h:93
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:47
const Record * getRecord(const RecordDecl *D) const
Definition Context.cpp:817
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:107
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:506
bool canClassify(QualType T) const
Definition Context.h:129
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 BlockExpr * getExpr() const
Definition Function.h:136
const FunctionDecl * getDecl() const
Returns the original FunctionDecl.
Definition Function.h:133
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition Pointer.cpp:874
OpaquePointer Opaque
Definition Pointer.h:1349
const Expr * getRootExpr() const
Definition Pointer.cpp:1217
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:631
bool pointsToLabel() const
Whether this points to a block created for an AddrLabelExpr.
Definition Pointer.cpp:952
bool isStatic() const
Checks if the storage is static.
Definition Pointer.h:886
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition Pointer.h:901
const VarDecl * getRootVarDecl() const
Definition Pointer.cpp:1209
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:1056
FunctionPointer Fn
Definition Pointer.h:1346
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:942
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition Pointer.cpp:378
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:1017
bool isOpaquePointer() const
Definition Pointer.h:862
bool isStringPointer() const
Definition Pointer.h:861
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
Definition Pointer.h:1067
const TypeidPointer & asTypeidPointer() const
Definition Pointer.h:844
bool isIntegralPointer() const
Definition Pointer.h:858
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:724
void initializeAllElements() const
Initialize all elements of a primitive array at once.
Definition Pointer.cpp:774
std::optional< size_t > computeOffsetForComparison(const ASTContext &ASTCtx) const
Compute an integer that can be used to compare this pointer to another one.
Definition Pointer.cpp:435
bool isArrayRoot() const
Whether this array refers to an array, but not to the first element.
Definition Pointer.h:777
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:672
static bool elemsOfSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition Pointer.cpp:900
bool isElementAlive(unsigned Index) const
Definition Pointer.cpp:678
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition Pointer.cpp:941
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Compute the pointer offset as given by the ASTRecordLayout.
Definition Pointer.cpp:516
bool allElementsAlive() const
Definition Pointer.cpp:797
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:709
bool isTypeidPointer() const
Definition Pointer.h:860
std::string toDiagnosticString(const ASTContext &Ctx) const
Converts the pointer to a string usable in diagnostics.
Definition Pointer.cpp:618
bool isZero() const
Checks if the pointer is null.
Definition Pointer.h:656
Pointer & operator=(const Pointer &P)
Definition Pointer.cpp:115
bool isConstexprUnknown() const
Definition Pointer.h:1166
const IntPointer & asIntPointer() const
Definition Pointer.h:836
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:815
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:686
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition Pointer.cpp:894
const OpaquePointer & asOpaquePointer() const
Definition Pointer.h:852
APValue toAPValue(const ASTContext &ASTCtx) const
Converts the pointer to an APValue.
Definition Pointer.cpp:207
bool isOnePastEnd() const
Checks if the index is one past end.
Definition Pointer.h:1027
uint64_t getIntegerRepresentation() const
Definition Pointer.h:595
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition Pointer.h:1043
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:873
friend class Block
Definition Pointer.h:1308
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:1053
bool isBlockPointer() const
Definition Pointer.h:857
TypeidPointer Typeid
Definition Pointer.h:1347
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition Pointer.cpp:1174
StringPointer Str
Definition Pointer.h:1348
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:840
const Block * block() const
Definition Pointer.h:1002
bool isFunctionPointer() const
Definition Pointer.h:859
Pointer getDeclPtr() const
Definition Pointer.h:750
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:714
PtrView view() const
Definition Pointer.h:603
bool isBaseClass() const
Checks if a structure is a base class.
Definition Pointer.h:938
size_t elemSize() const
Returns the element size of the innermost field.
Definition Pointer.h:753
const BlockPointer & asBlockPointer() const
Definition Pointer.h:832
static std::optional< std::pair< PtrView, PtrView > > computeSplitPoint(const Pointer &A, const Pointer &B)
Definition Pointer.cpp:962
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition Pointer.h:1210
Structure/Class descriptor.
Definition Record.h:25
const RecordDecl * getDecl() const
Returns the underlying declaration.
Definition Record.h:70
bool isUnion() const
Checks if the record is a union.
Definition Record.h:74
const Field * getField(unsigned I) const
Definition Record.h:100
unsigned getNumBases() const
Definition Record.h:114
const Base * getBase(unsigned I) const
Definition Record.h:115
const Base * getVirtualBase(unsigned I) const
Definition Record.h:132
unsigned getNumFields() const
Definition Record.h:99
unsigned getNumVirtualBases() const
Definition Record.h:131
llvm::iterator_range< const_field_iter > fields() const
Definition Record.h:95
constexpr bool isIntegerOrBoolType(PrimType T)
Definition PrimType.h:52
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
bool Add(InterpState &S, CodePtr OpPC)
Definition Interp.h:418
static bool validType(QualType T)
Definition Interp.cpp:3285
Top level wrappers for InstallAPI frontend operations.
CanQual< Type > CanQualType
Represents a canonical, potentially-qualified type.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ Result
The result type of a method or function.
Definition TypeBase.h:906
const FunctionProtoType * T
U cast(CodeGen::Address addr)
Definition Address.h:327
@ None
No keyword precedes the qualified type name.
Definition TypeBase.h:6040
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:345
Block * Pointee
The block the pointer is pointing to.
Definition Pointer.h:343
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:246
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:260
QualType getElemQualType() const
const ValueDecl * asValueDecl() const
Definition Descriptor.h:205
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:201
QualType getDataType(const ASTContext &Ctx) const
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:251
const FieldDecl * asFieldDecl() const
Definition Descriptor.h:213
const VarDecl * asVarDecl() const
Definition Descriptor.h:209
PrimType getPrimType() const
Definition Descriptor.h:231
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:265
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:146
const Expr * asExpr() const
Definition Descriptor.h:202
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:263
Descriptor used for global variables.
Definition Descriptor.h:49
A pointer-sized struct we use to allocate into data storage.
Definition InitMap.h:79
bool hasInitMap() const
Definition InitMap.h:88
bool allInitialized() const
Are all elements in the array already initialized?
Definition InitMap.h:92
void setInitMap(const InitMap *IM)
Definition InitMap.h:94
Bitfield tracking the initialisation status of elements of primitive arrays.
Definition InitMap.h:22
void startElementLifetime(unsigned I)
Definition InitMap.cpp:32
void endElementLifetime(unsigned I)
Definition InitMap.cpp:45
bool allElementsAlive() const
Definition InitMap.h:58
bool isElementInitialized(unsigned I) const
Checks if an element was initialized.
Definition InitMap.cpp:23
bool initializeElement(unsigned I)
Initializes an element. Returns true when object if fully initialized.
Definition InitMap.cpp:13
bool isElementAlive(unsigned I) const
Definition InitMap.h:52
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:67
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition Descriptor.h:89
unsigned Offset
Offset inside the structure/array.
Definition Descriptor.h:69
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition Descriptor.h:80
QualType getPointeeType() const
Definition Pointer.h:359
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
Definition Pointer.cpp:1253
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1225
const ValueDecl * Base
Definition Pointer.h:433
llvm::PointerIntPair< const Type *, 2, unsigned > FieldType
Definition Pointer.h:435
QualType getObjectType() const
Definition Pointer.h:469
bool isRoot() const
Check if the pointer has offset 0.
Definition Pointer.cpp:1372
QualType getSurroundingArray() const
If this is pointing to an array element, return the array.
Definition Pointer.cpp:1341
bool isOnePastEndOrElementPastEnd() const
This is used in Pointer::isOnePastEnd().
Definition Pointer.cpp:1429
const PointerPathEntry * Path
Definition Pointer.h:436
ArrayRef< PointerPathEntry > path() const
Definition Pointer.h:439
bool isArrayElement() const
Definition Pointer.h:482
QualType getFieldType() const
Definition Pointer.h:476
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Definition Pointer.cpp:1284
const Descriptor * getDeclDesc() const
Definition Pointer.h:85
bool allElementsInitialized() const
Definition Pointer.cpp:781
PtrView atField(unsigned Offset) const
Definition Pointer.h:273
size_t elemSize() const
Definition Pointer.h:87
const Record * getRecord() const
Definition Pointer.h:153
const Descriptor * getFieldDesc() const
Definition Pointer.h:79
const FieldDecl * getField() const
Definition Pointer.h:158
bool isElementInitialized(unsigned Index) const
Definition Pointer.cpp:653
bool isBaseClass() const
Definition Pointer.h:164
void activate() const
Definition Pointer.cpp:814
bool inArray() const
Definition Pointer.h:54
void startLifetime() const
Definition Pointer.h:330
bool isInitialized() const
Definition Pointer.h:301
bool isArrayElement() const
Definition Pointer.h:232
bool isPastEnd() const
Definition Pointer.h:172
PtrView getArray() const
Definition Pointer.h:148
unsigned getNumElems() const
Definition Pointer.h:230
InitMapPtr & getInitMap() const
Definition Pointer.h:322
InlineDescriptor * getInlineDesc() const
Definition Pointer.h:66
bool inUnion() const
Definition Pointer.h:53
void initializeElement(unsigned Index) const
Definition Pointer.cpp:753
void initialize() const
Definition Pointer.cpp:732
bool isOnePastEnd() const
Definition Pointer.h:188
bool isRoot() const
Definition Pointer.h:60
void setLifeState(Lifetime L) const
Definition Pointer.cpp:710
Lifetime getLifetime() const
Definition Pointer.cpp:691
PtrView getBase() const
Definition Pointer.h:268
bool isActive() const
Definition Pointer.h:46
PtrView expand() const
Definition Pointer.h:113
bool isVirtualBaseClass() const
Definition Pointer.h:165
bool isArrayRoot() const
Definition Pointer.h:47
T & deref() const
Definition Pointer.h:244
int64_t getIndex() const
Definition Pointer.h:218
const StringLiteral * getLiteral() const
Definition Pointer.h:388