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