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