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 QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
350 DynamicAllocLValue DA(*block()->DynAllocId);
351 Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
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
731 if (!isBlockPointer())
732 return true;
733
734 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
735 Offset == BS.Base) {
736 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
738 }
739
740 assert(BS.Pointee && "Cannot check if null pointer was initialized");
741 const Descriptor *Desc = getFieldDesc();
742 assert(Desc);
743 if (Desc->isPrimitiveArray())
745
746 if (asBlockPointer().Base == 0)
747 return true;
748 // Field has its bit in an inline descriptor.
749 return getInlineDesc()->IsInitialized;
750}
751
752bool PtrView::isElementInitialized(unsigned Index) const {
753 const Descriptor *Desc = getFieldDesc();
754 assert(Desc);
755
756 if (Pointee->isStatic() && Base == 0)
757 return true;
758
759 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
760 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
762 }
763
764 if (Desc->isPrimitiveArray()) {
765 InitMapPtr IM = getInitMap();
766
767 if (IM.allInitialized())
768 return true;
769
770 if (!IM.hasInitMap())
771 return false;
772 return IM->isElementInitialized(Index);
773 }
774 return isInitialized();
775}
776
777bool Pointer::isElementAlive(unsigned Index) const {
778 assert(getFieldDesc()->isPrimitiveArray());
779
780 InitMapPtr &IM = getInitMap();
781 if (!IM.hasInitMap())
782 return true;
783
784 if (IM.allInitialized())
785 return true;
786
787 return IM->isElementAlive(Index);
788}
789
791 if (Base < sizeof(InlineDescriptor))
792 return Lifetime::Started;
793
794 if (inArray() && !isArrayRoot()) {
795 InitMapPtr &IM = getInitMap();
796
797 if (!IM.hasInitMap()) {
798 if (IM.allInitialized())
799 return Lifetime::Started;
800 return getArray().getLifetime();
801 }
802
804 }
805
806 return getInlineDesc()->LifeState;
807}
808
810 if (Base < sizeof(InlineDescriptor))
811 return;
812
813 if (inArray() && !isArrayRoot()) {
814 assert(L == Lifetime::Started || L == Lifetime::Ended);
815 const Descriptor *Desc = getFieldDesc();
816 InitMapPtr &IM = getInitMap();
817 if (!IM.hasInitMap())
818 IM.setInitMap(new InitMap(Desc->getNumElems(), IM.allInitialized()));
819
820 if (L == Lifetime::Ended)
822 else if (L == Lifetime::Started)
824 assert(isArrayRoot() || (this->getLifetime() == L));
825 return;
826 }
827
829}
830
832 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
833 auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
835 return;
836 }
837
838 const Descriptor *Desc = getFieldDesc();
839 assert(Desc);
840 if (Desc->isPrimitiveArray()) {
841 if (Desc->getNumElems() != 0)
843 return;
844 }
845
846 // Field has its bit in an inline descriptor.
847 assert(Base != 0 && "Only composite fields can be initialised");
850}
851
852void PtrView::initializeElement(unsigned Index) const {
853 // Primitive global arrays don't have an initmap.
854 if (Pointee->isStatic() && Base == 0)
855 return;
856
857 assert(Index < getFieldDesc()->getNumElems());
858
859 InitMapPtr &IM = getInitMap();
860 if (IM.allInitialized())
861 return;
862
863 if (!IM.hasInitMap()) {
864 const Descriptor *Desc = getFieldDesc();
865 IM.setInitMap(new InitMap(Desc->getNumElems()));
866 }
867 assert(IM.hasInitMap());
868
869 if (IM->initializeElement(Index))
871}
872
874 assert(getFieldDesc()->isPrimitiveArray());
875 assert(isArrayRoot());
876
877 getInitMap().noteAllInitialized();
878}
879
881 assert(getFieldDesc()->isPrimitiveArray());
882 assert(isArrayRoot());
883
884 if (Pointee->isStatic() && Base == 0)
885 return true;
886
887 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
888 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
890 }
891
892 InitMapPtr IM = getInitMap();
893 return IM.allInitialized();
894}
895
897 assert(getFieldDesc()->isPrimitiveArray());
898 assert(isArrayRoot());
899
900 if (isStatic() && BS.Base == 0)
901 return true;
902
903 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
904 Offset == BS.Base) {
905 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
907 }
908
909 InitMapPtr &IM = getInitMap();
910 return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive());
911}
912
913void PtrView::activate() const {
914 // Field has its bit in an inline descriptor.
915 assert(Base != 0 && "Only composite fields can be activated");
916
917 if (isRoot() && Base == sizeof(GlobalInlineDescriptor))
918 return;
919 if (!getInlineDesc()->InUnion)
920 return;
921
923 activate = [&activate](PtrView P) -> void {
924 P.getInlineDesc()->IsActive = true;
925 P.startLifetime();
926 if (const Record *R = P.getRecord(); R && !R->isUnion()) {
927 for (const Record::Field &F : R->fields()) {
928 PtrView FieldPtr = P.atField(F.Offset);
929 if (!FieldPtr.getInlineDesc()->IsActive)
930 activate(FieldPtr);
931 }
932 // FIXME: Bases?
933 }
934 };
935
936 std::function<void(PtrView &)> deactivate;
937 deactivate = [&deactivate](PtrView &P) -> void {
938 P.getInlineDesc()->IsActive = false;
939
940 if (const Record *R = P.getRecord()) {
941 for (const Record::Field &F : R->fields()) {
942 PtrView FieldPtr = P.atField(F.Offset);
943 if (FieldPtr.getInlineDesc()->IsActive)
944 deactivate(FieldPtr);
945 }
946 // FIXME: Bases?
947 }
948 };
949
950 PtrView B = *this;
951 // Primitive array elements can't be activated individually, so
952 // look at the array root instead.
954 B = B.getArray();
955
956 while (!B.isRoot() && B.inUnion()) {
957 activate(B);
958
959 // When walking up the pointer chain, deactivate
960 // all union child pointers that aren't on our path.
961 PtrView Cur = B;
962 B = B.getBase();
963 if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
964 for (const Record::Field &F : BR->fields()) {
965 PtrView FieldPtr = B.atField(F.Offset);
966 if (FieldPtr != Cur)
967 deactivate(FieldPtr);
968 }
969 }
970 }
971}
972
973bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
974 // Two null pointers always have the same base.
975 if (A.isZero() && B.isZero())
976 return true;
977
978 // We allow comparisons between opaque pointers and block pointers, provided
979 // they have the same declaration as base.
980 if (A.StorageKind != B.StorageKind) {
981 if (A.isOpaquePointer() && A.Opaque.Base.isVarDecl() &&
982 B.isBlockPointer()) {
983 if (const VarDecl *BDecl = B.block()->getDescriptor()->asVarDecl())
984 return BDecl == A.Opaque.Base.asVarDecl()->getMostRecentDecl();
985 return false;
986 }
987 if (B.isOpaquePointer() && B.Opaque.Base.isVarDecl() &&
988 A.isBlockPointer()) {
989 if (const VarDecl *ADecl = A.block()->getDescriptor()->asVarDecl())
990 return ADecl == B.Opaque.Base.asVarDecl()->getMostRecentDecl();
991 return false;
992 }
993 return false;
994 }
995
996 switch (A.StorageKind) {
997 case Storage::Int:
998 return true;
999 case Storage::Block:
1000 return A.BS.Pointee == B.BS.Pointee;
1001 case Storage::Fn:
1002 return true;
1003 case Storage::Typeid:
1005 case Storage::String:
1006 return A.Str.ID == B.Str.ID && A.Str.getLiteral() == B.Str.getLiteral();
1007 case Storage::Opaque:
1008 if (A.Opaque.Base.isExpr())
1009 return B.Opaque.Base.isExpr() && A.Opaque.Base == B.Opaque.Base;
1010 if (A.Opaque.Base.isVarDecl())
1011 return B.Opaque.Base.isVarDecl() &&
1014 return false;
1015 }
1016 llvm_unreachable("should have been handled by the fully covered switch");
1017}
1018
1020 if (!A.isBlockPointer() || !B.isBlockPointer())
1021 return false;
1022 return A.block() == B.block();
1023}
1024
1026 assert(hasSameBase(A, B));
1027 assert(A.isBlockPointer());
1028 assert(B.isBlockPointer());
1029
1030 if (A.BS.Base == B.BS.Base)
1031 return true;
1032
1033 if (A.isBaseClass() || B.isBaseClass())
1034 return false;
1035
1036 if (A.getField() || B.getField())
1037 return false;
1038
1039 auto closestArray = [](const Pointer &P) -> PtrView {
1040 if (P.isArrayRoot())
1041 return P.view();
1042
1043 PtrView V = P.view();
1044 if (V.isArrayElement() || V.isOnePastEnd())
1045 V = V.expand().getArray();
1046
1047 if (P.isRoot())
1048 return P.view();
1049
1050 while (!V.isRoot() && !V.getFieldDesc()->IsArray) {
1051 if (V.isArrayElement()) {
1052 V = V.expand().getArray();
1053 break;
1054 }
1055 V = V.getBase();
1056 }
1057 return V;
1058 };
1059
1060 if (closestArray(A) != closestArray(B))
1061 return false;
1062
1063 return true;
1064}
1065
1066// FIXME: This should return true for string pointers.
1068 if (isZero())
1069 return false;
1070
1071 if (isDynamic())
1072 return false;
1073
1074 const Expr *E = getRootExpr();
1076}
1077
1079 if (isZero())
1080 return false;
1081
1082 if (isOpaquePointer())
1083 return isa_and_nonnull<AddrLabelExpr>(Opaque.Base.asExpr());
1084 return false;
1085}
1086
1087std::optional<std::pair<PtrView, PtrView>>
1089 if (!A.isBlockPointer() || !B.isBlockPointer())
1090 return std::nullopt;
1091
1093 return std::nullopt;
1094 if (A.isRoot() && B.isRoot())
1095 return std::nullopt;
1096
1097 if (A == B)
1098 return std::make_pair(A.view(), B.view());
1099
1100 auto getBase = [](PtrView P) -> PtrView {
1101 if (P.isArrayElement())
1102 return P.expand().getArray();
1103 return P.getBase();
1104 };
1105
1106 PtrView IterA = A.view();
1107 PtrView IterB = B.view();
1108 PtrView CurA = IterA;
1109 PtrView CurB = IterB;
1110 for (;;) {
1111 if (IterA.Base > IterB.Base) {
1112 CurA = IterA;
1113 IterA = getBase(IterA);
1114 } else {
1115 CurB = IterB;
1116 IterB = getBase(IterB);
1117 }
1118
1119 if (IterA == IterB) {
1120 // If the Iter is an array, CurA and CurB are both elements of the same
1121 // array. That is fine, so return nullopt.
1122 if (IterA.getFieldDesc()->isArray())
1123 return std::nullopt;
1124 return std::make_pair(CurA, CurB);
1125 }
1126
1127 if (IterA.isRoot() && IterB.isRoot())
1128 return std::nullopt;
1129 }
1130
1131 llvm_unreachable("The loop above should've returned.");
1132}
1133
1134/// Convert a pointer to a composite value to an rvalue.
1135static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R) {
1136 const ASTContext &ASTCtx = Ctx.getASTContext();
1137 if (const auto *AT = Ty->getAs<AtomicType>())
1138 Ty = AT->getValueType();
1139
1140 // Invalid pointers.
1141 if (!Ptr.isLive() || Ptr.isPastEnd())
1142 return false;
1143
1144 // Primitives should never end up here.
1145 assert(!Ctx.canClassify(Ty));
1146 const Descriptor *FieldDesc = Ptr.getFieldDesc();
1147 assert(FieldDesc);
1148
1149 if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
1150 if (!FieldDesc->isRecord())
1151 return false;
1152 const auto *Record = Ptr.getRecord();
1153 assert(Record && "Missing record descriptor");
1154
1155 bool Ok = true;
1156 if (RT->getDecl()->isUnion()) {
1157 const FieldDecl *ActiveField = nullptr;
1158 APValue Value;
1159 for (const auto &F : Record->fields()) {
1160 PtrView FP = Ptr.atField(F.Offset);
1161 if (FP.isActive()) {
1162 const Descriptor *Desc = F.Desc;
1163 if (Desc->isPrimitive()) {
1164 TYPE_SWITCH(Desc->getPrimType(),
1165 Value = FP.deref<T>().toAPValue(ASTCtx));
1166 } else {
1167 QualType FieldTy = F.Decl->getType();
1168 Ok &= toRValue(Ctx, FieldTy, FP, Value);
1169 }
1170 ActiveField = FP.getFieldDesc()->asFieldDecl();
1171 break;
1172 }
1173 }
1174 R = APValue(ActiveField, Value);
1175 } else {
1176 unsigned NF = Record->getNumFields();
1177 unsigned NB = Record->getNumBases();
1178 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
1179
1180 R = APValue(APValue::UninitStruct(), NB, NF, NV);
1181
1182 for (unsigned I = 0; I != NF; ++I) {
1183 const Record::Field *FD = Record->getField(I);
1184 const Descriptor *Desc = FD->Desc;
1185 PtrView FP = Ptr.atField(FD->Offset);
1186 APValue &Value = R.getStructField(I);
1187 if (Desc->isPrimitive()) {
1188 TYPE_SWITCH(Desc->getPrimType(),
1189 Value = FP.deref<T>().toAPValue(ASTCtx));
1190 } else {
1191 QualType FieldTy = FD->Decl->getType();
1192 Ok &= toRValue(Ctx, FieldTy, FP, Value);
1193 }
1194 }
1195
1196 for (unsigned I = 0; I != NB; ++I) {
1197 const Record::Base *BD = Record->getBase(I);
1198 QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(BD->Decl);
1199 PtrView BP = Ptr.atField(BD->Offset);
1200 Ok &= toRValue(Ctx, BaseTy, BP, R.getStructBase(I));
1201 }
1202
1203 for (unsigned I = 0; I != NV; ++I) {
1204 const Record::Base *VD = Record->getVirtualBase(I);
1205 assert(VD);
1206 QualType VirtBaseTy = Ctx.getASTContext().getCanonicalTagType(VD->Decl);
1207 PtrView VP = Ptr.atField(VD->Offset);
1208 Ok &= toRValue(Ctx, VirtBaseTy, VP, R.getStructVirtualBase(I));
1209 }
1210 }
1211 return Ok;
1212 }
1213
1214 if (Ty->isIncompleteArrayType()) {
1215 R = APValue(APValue::UninitArray(), 0, 0);
1216 return true;
1217 }
1218
1219 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
1220 if (!FieldDesc->isArray())
1221 return false;
1222 const size_t NumElems = Ptr.getNumElems();
1223 QualType ElemTy = AT->getElementType();
1224 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
1225
1226 bool Ok = true;
1227 OptPrimType ElemT = Ctx.classify(ElemTy);
1228 for (unsigned I = 0; I != NumElems; ++I) {
1229 APValue &Slot = R.getArrayInitializedElt(I);
1230 if (ElemT) {
1231 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
1232 } else {
1233 Ok &= toRValue(Ctx, ElemTy, Ptr.atIndex(I).narrow(), Slot);
1234 }
1235 }
1236 return Ok;
1237 }
1238
1239 // Complex types.
1240 if (Ty->isAnyComplexType()) {
1241 // Can happen via C casts.
1242 if (!FieldDesc->getType()->isAnyComplexType())
1243 return false;
1244
1245 PrimType ElemT = FieldDesc->getPrimType();
1246 if (isIntegerOrBoolType(ElemT)) {
1247 INT_TYPE_SWITCH(ElemT, {
1248 auto V1 = Ptr.elem<T>(0);
1249 auto V2 = Ptr.elem<T>(1);
1250 R = APValue(V1.toAPSInt(), V2.toAPSInt());
1251 return true;
1252 });
1253 } else if (ElemT == PT_Float) {
1254 R = APValue(Ptr.elem<Floating>(0).getAPFloat(),
1255 Ptr.elem<Floating>(1).getAPFloat());
1256 return true;
1257 }
1258 return false;
1259 }
1260
1261 // Vector types.
1262 if (const auto *VT = Ty->getAs<VectorType>()) {
1263 if (!FieldDesc->isPrimitiveArray())
1264 return false;
1265
1266 PrimType ElemT = FieldDesc->getPrimType();
1267 SmallVector<APValue> Values;
1268 Values.reserve(VT->getNumElements());
1269 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
1270 TYPE_SWITCH(ElemT,
1271 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1272 }
1273
1274 assert(Values.size() == VT->getNumElements());
1275 R = APValue(Values.data(), Values.size());
1276 return true;
1277 }
1278
1279 // Constant Matrix types.
1280 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
1281 if (!FieldDesc->isPrimitiveArray())
1282 return false;
1283 PrimType ElemT = FieldDesc->getPrimType();
1284 unsigned NumElems = MT->getNumElementsFlattened();
1285
1286 SmallVector<APValue> Values;
1287 Values.reserve(NumElems);
1288 for (unsigned I = 0; I != NumElems; ++I) {
1289 TYPE_SWITCH(ElemT,
1290 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1291 }
1292
1293 R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
1294 return true;
1295 }
1296
1297 llvm_unreachable("invalid value to return");
1298}
1299
1300std::optional<APValue> Pointer::toRValue(const Context &Ctx,
1301 QualType ResultType) const {
1302 const ASTContext &ASTCtx = Ctx.getASTContext();
1303 assert(!ResultType.isNull());
1304
1305 // Can't return functions as rvalues.
1306 if (ResultType->isFunctionType())
1307 return std::nullopt;
1308
1309 // Invalid to read from.
1310 if (isDummy() || !isLive() || isPastEnd() ||
1311 (isOnePastEnd() && !isZeroSizeArray()))
1312 return std::nullopt;
1313
1314 // We can return these as rvalues, but we can't deref() them.
1315 if (isZero() || isIntegralPointer())
1316 return toAPValue(ASTCtx);
1317
1318 // Just load primitive types.
1319 if (OptPrimType T = Ctx.classify(ResultType)) {
1320 if (!canDeref(*T))
1321 return std::nullopt;
1322 TYPE_SWITCH(*T, return this->load<T>().toAPValue(ASTCtx));
1323 }
1324
1325 if (!isBlockPointer())
1326 return std::nullopt;
1327
1328 // Return the composite type.
1330 if (!::toRValue(Ctx, ResultType, view(), Result))
1331 return std::nullopt;
1332 return Result;
1333}
1334
1336 if (isBlockPointer())
1337 return getDeclDesc()->asVarDecl();
1338 if (isOpaquePointer())
1339 return Opaque.getBaseDecl();
1340 return nullptr;
1341}
1342
1344 if (isBlockPointer())
1345 return getDeclDesc()->asExpr();
1346 if (isStringPointer())
1347 return Str.getLiteral();
1348 if (isOpaquePointer())
1349 return Opaque.getBaseExpr();
1350 return nullptr;
1351}
1352
1353std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx,
1354 unsigned Offset) const {
1355 QualType CurType = getPointeeType();
1356 if (CurType.isNull() || !CurType->isRecordType())
1357 return std::nullopt;
1358
1359 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1360 if (!R)
1361 return *this;
1362
1363 const Record::Field *F = R->findField(Offset);
1364 if (!F)
1365 return *this;
1366
1367 const FieldDecl *FD = F->Decl;
1368 if (FD->getParent()->isInvalidDecl())
1369 return std::nullopt;
1370
1371 const ASTContext &ASTCtx = Ctx.getASTContext();
1372 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
1373 unsigned FieldIndex = FD->getFieldIndex();
1374 uint64_t FieldOffset =
1375 ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
1376 .getQuantity();
1377
1378 uint64_t NewValue = this->Value + FieldOffset;
1379 return IntPointer{{FD->getType().getTypePtr(), NewValue == 0}, NewValue};
1380}
1381
1383 unsigned BaseOffset) const {
1384 if (!getType())
1385 return *this;
1386
1387 QualType CurType = getPointeeType();
1388 if (CurType.isNull() || !CurType->isRecordType())
1389 return *this;
1390
1391 // null pointers stay null during a cast, per conv.ptr
1392 if (Value == 0)
1393 return *this;
1394
1395 const Record *R = Ctx.getRecord(CurType->getAsRecordDecl());
1396
1397 // This iterates over bases and checks for the proper offset. That's
1398 // potentially slow but this case really shouldn't happen a lot.
1399 const Record::Base *B = R->findBase(BaseOffset);
1400 if (!B)
1401 return *this;
1402
1403 const Descriptor *BaseDesc = B->Desc;
1404 // Adjust the offset value based on the information from the record layout.
1405 const ASTContext &ASTCtx = Ctx.getASTContext();
1406 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
1407 CharUnits BaseLayoutOffset =
1408 Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
1409
1410 const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
1412 std::nullopt, RD, false);
1413 uint64_t NewValue = Value + BaseLayoutOffset.getQuantity();
1414 return {{T.getTypePtr(), NewValue == 0}, NewValue};
1415}
1416
1417std::optional<size_t>
1419 size_t Offset = 0;
1420 QualType CurType = getObjectType();
1421 for (const PointerPathEntry &Entry : path()) {
1422 switch (Entry.Kind) {
1424 const RecordDecl *RD = CurType->getAsRecordDecl();
1425 if (!ASTContext::hasLayout(RD))
1426 return std::nullopt;
1427
1428 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
1429 if (Entry.RD.getInt())
1430 Offset +=
1431 Layout.getVBaseClassOffset(Entry.RD.getPointer()).getQuantity();
1432 else
1433 Offset +=
1434 Layout.getBaseClassOffset(Entry.RD.getPointer()).getQuantity();
1435
1436 CurType = ASTCtx.getCanonicalTagType(Entry.RD.getPointer());
1437 } break;
1438
1440 const FieldDecl *FD = Entry.FD;
1441 const RecordDecl *RD = FD->getParent();
1442 if (!ASTContext::hasLayout(RD))
1443 return std::nullopt;
1444
1445 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(RD);
1446 Offset +=
1448 .getQuantity();
1449
1450 CurType = FD->getType();
1451 } break;
1454 bool Add = (Entry.Kind == PointerPathEntry::Array);
1455 uint64_t Index = Entry.Index;
1456 if (!CurType->isArrayType()) {
1457 if (Add)
1458 Offset += Index * ASTCtx.getTypeSizeInChars(CurType).getQuantity();
1459 else
1460 Offset -= Index * ASTCtx.getTypeSizeInChars(CurType).getQuantity();
1461 continue;
1462 }
1463 const ArrayType *AT = CurType->getAsArrayTypeUnsafe();
1464 assert(AT);
1465 QualType ElemTy = AT->getElementType();
1466 if (!validType(ElemTy) || isa<VariableArrayType>(AT))
1467 return std::nullopt;
1468 if (Add)
1469 Offset += Index * ASTCtx.getTypeSizeInChars(ElemTy).getQuantity();
1470 else
1471 Offset -= Index * ASTCtx.getTypeSizeInChars(ElemTy).getQuantity();
1472 CurType = AT->getElementType();
1473 } break;
1474 }
1475 }
1476
1477 return Offset;
1478}
1479
1481 if (PathLength == 0)
1482 return getObjectType();
1483 if (Path[PathLength - 1].Kind != PointerPathEntry::Array)
1484 return getFieldType();
1485
1486 assert(Path[PathLength - 1].Kind == PointerPathEntry::Array);
1487 assert(isArrayElement());
1488
1489 QualType CurType = getObjectType();
1490 for (const PointerPathEntry &Entry : path().drop_back(1)) {
1491 switch (Entry.Kind) {
1493 CurType = Entry.RD.getPointer()->getASTContext().getCanonicalTagType(
1494 Entry.RD.getPointer());
1495 break;
1497 CurType = Entry.FD->getType();
1498 break;
1501 if (!CurType->isArrayType())
1502 break;
1503 CurType = CurType->getAsArrayTypeUnsafe()->getElementType();
1504 }
1505 }
1506 return CurType;
1507}
1508
1509/// Check if the pointer has offset 0.
1510// As an optimization, don't actually compute the offset.
1512 QualType CurType = getObjectType();
1513 for (const PointerPathEntry &Entry : path()) {
1514 switch (Entry.Kind) {
1516 if (Entry.RD.getInt())
1517 return false;
1518 CurType = Entry.RD.getPointer()->getASTContext().getCanonicalTagType(
1519 Entry.RD.getPointer());
1520 break;
1522 if (!Entry.FD->getParent()->isUnion() && Entry.FD->getFieldIndex() != 0)
1523 return false;
1524 CurType = Entry.FD->getType();
1525 break;
1527 if (Entry.Index != 0)
1528 return false;
1529 if (!CurType->isArrayType())
1530 continue;
1531 CurType = CurType->getAsArrayTypeUnsafe()->getElementType();
1532 break;
1534 return false;
1535 }
1536 }
1537 return true;
1538}
1539
1542
1543 if (isArrayElement())
1545
1546 bool Result = false;
1547 // If the field type is an IncompleteArrayType, we still need to check the
1548 // base to see if this array is a flexible array member _and_ has actually
1549 // been initialized by data we know the size of.
1551 const VarDecl *Base = this->Base.asVarDecl();
1552 if (!Base || !Base->getType()->isRecordType() || !Base->hasInit())
1553 Result = true;
1554 else
1555 Result = !Base->hasFlexibleArrayInit(Base->getASTContext());
1557 Result = true;
1558
1559 return Result;
1560}
1561
1562/// This is used in Pointer::isOnePastEnd(). We cannot read from such pointers.
1563/// We can of course never read from opaque pointers anyway but we diagnose
1564/// one-past-the-end pointers differently.
1565///
1566/// In contrast, OpaquePointer::isOnePastEnd() only uses the past-end bit. That
1567/// is used for the APValue conversion.
1569 if (isOnePastEnd())
1570 return true;
1571
1572 if (PathLength == 0)
1573 return false;
1574
1575 if (Path[PathLength - 1].Kind != PointerPathEntry::Array)
1576 return false;
1577
1578 QualType ArrTy = getSurroundingArray();
1579 if (!ArrTy->isArrayType())
1580 return false;
1581 // FIXME: Flexible array members?
1582 if (const auto *CAT =
1583 dyn_cast<ConstantArrayType>(ArrTy->getAsArrayTypeUnsafe())) {
1584 if (Path[PathLength - 1].Index >= CAT->getZExtSize())
1585 return true;
1586 }
1587
1588 return false;
1589}
1590
1592 if (const VarDecl *VD = Base.asVarDecl())
1593 return !VD->hasExternalStorage();
1594
1595 return !Base.getType()->isPointerType();
1596}
#define V(N, I)
Defines the clang::Expr interface and subclasses for C++ expressions.
static bool validType(QualType T)
Definition Interp.cpp:54
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:1135
#define INT_TYPE_SWITCH(Expr, B)
Definition PrimType.h:256
#define TYPE_SWITCH(Expr, B)
Definition PrimType.h:235
static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD)
static const RecordDecl * getRecordDecl(QualType QT)
Checks that the passed in QualType either is of RecordType or points to RecordType.
static bool hasLayout(const RecordDecl *D)
Whether layout (offset and size) information can be queried for D.
static LValueBase getTypeInfo(TypeInfoLValue LV, QualType TypeInfo)
Definition APValue.cpp:55
static LValueBase getDynamicAlloc(DynamicAllocLValue LV, QualType Type)
Definition APValue.cpp:47
A non-discriminated union of a base, field, or array index.
Definition APValue.h:208
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition APValue.h:216
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition APValue.h:122
std::string getAsString(const ASTContext &Ctx, QualType Ty) const
Definition APValue.cpp:985
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:239
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:3813
QualType getElementType() const
Definition TypeBase.h:3825
Represents a C++ struct/union/class.
Definition DeclCXX.h:258
CharUnits - This is an opaque type for sizes expressed in character units.
Definition CharUnits.h:38
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
Definition CharUnits.h:185
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition CharUnits.h:63
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition CharUnits.h:53
Represents a concrete matrix type with constant number of rows and columns.
Definition TypeBase.h:4478
Decl()=delete
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:550
bool isInvalidDecl() const
Definition DeclBase.h:596
Symbolic representation of a dynamic allocation.
Definition APValue.h:65
This represents one expression.
Definition Expr.h:113
Represents a member of a struct/union/class.
Definition Decl.h:3295
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
Definition Decl.h:3380
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3531
Represents a function declaration or definition.
Definition Decl.h:2059
A (possibly-)qualified type.
Definition TypeBase.h:938
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1005
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8428
Represents a struct/union/class.
Definition Decl.h:4460
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
Definition Decl.h:4644
Symbolic representation of typeid(T) for some type T.
Definition APValue.h:44
bool isIncompleteArrayType() const
Definition TypeBase.h:8772
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
Definition Type.h:41
bool isArrayType() const
Definition TypeBase.h:8764
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:881
bool isLValueReferenceType() const
Definition TypeBase.h:8693
bool isAnyComplexType() const
Definition TypeBase.h:8800
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type.
Definition TypeBase.h:9317
bool isFunctionType() const
Definition TypeBase.h:8661
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
Definition TypeBase.h:2998
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9264
bool isRecordType() const
Definition TypeBase.h:8792
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:4266
unsigned getSize() const
Returns the size of the block, including metadata.
Definition InterpBlock.h:86
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:88
Holds all information required to evaluate constexpr code in a module.
Definition Context.h:48
const Record * getRecord(const RecordDecl *D) const
Definition Context.cpp:824
ASTContext & getASTContext() const
Returns the AST context.
Definition Context.h:109
OptPrimType classify(QualType T) const
Classifies a type.
Definition Context.cpp:513
bool canClassify(QualType T) const
Definition Context.h:131
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:973
OpaquePointer Opaque
Definition Pointer.h:1351
const Expr * getRootExpr() const
Definition Pointer.cpp:1343
bool isInitialized() const
Checks if an object was initialized.
Definition Pointer.cpp:730
bool pointsToLabel() const
Whether this points to a block created for an AddrLabelExpr.
Definition Pointer.cpp:1078
bool isStatic() const
Checks if the storage is static.
Definition Pointer.h:883
bool isDynamic() const
Checks if the storage has been dynamically allocated.
Definition Pointer.h:898
const VarDecl * getRootVarDecl() const
Definition Pointer.cpp:1335
bool isZeroSizeArray() const
Checks if the pointer is pointing to a zero-size array.
Definition Pointer.h:1060
FunctionPointer Fn
Definition Pointer.h:1348
bool isDummy() const
Checks if the pointer points to a dummy value.
Definition Pointer.h:945
void print(llvm::raw_ostream &OS) const
Prints the pointer.
Definition Pointer.cpp:470
int64_t getIndex() const
Returns the index into an array.
Definition Pointer.h:1016
bool isOpaquePointer() const
Definition Pointer.h:859
bool isStringPointer() const
Definition Pointer.h:858
bool canDeref(PrimType T) const
Checks whether the pointer can be dereferenced to the given PrimType.
Definition Pointer.h:1071
bool operator==(const Pointer &P) const
Definition Pointer.cpp:209
const TypeidPointer & asTypeidPointer() const
Definition Pointer.h:841
bool isIntegralPointer() const
Definition Pointer.h:855
QualType getType() const
Returns the type of the innermost field.
Definition Pointer.h:721
void initializeAllElements() const
Initialize all elements of a primitive array at once.
Definition Pointer.cpp:873
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:774
bool isLive() const
Checks if the pointer is live.
Definition Pointer.h:669
static bool elemsOfSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition Pointer.cpp:1025
bool isElementAlive(unsigned Index) const
Definition Pointer.cpp:777
bool pointsToLiteral() const
Whether this points to a block that's been created for a "literal lvalue", i.e.
Definition Pointer.cpp:1067
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:896
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition Pointer.h:706
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:653
Pointer & operator=(const Pointer &P)
Definition Pointer.cpp:117
bool isConstexprUnknown() const
Definition Pointer.h:1170
const IntPointer & asIntPointer() const
Definition Pointer.h:833
bool isRoot() const
Pointer points directly to a block.
Definition Pointer.h:812
const Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition Pointer.h:683
static bool pointToSameBlock(const Pointer &A, const Pointer &B)
Checks if both given pointers point to the same block.
Definition Pointer.cpp:1019
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:1031
uint64_t getIntegerRepresentation() const
Definition Pointer.h:592
bool isPastEnd() const
Checks if the pointer points past the end of the object.
Definition Pointer.h:1047
const FieldDecl * getField() const
Returns the field information.
Definition Pointer.h:870
friend class Block
Definition Pointer.h:1310
bool isElementPastEnd() const
Checks if the pointer is an out-of-bounds element pointer.
Definition Pointer.h:1057
bool isBlockPointer() const
Definition Pointer.h:854
TypeidPointer Typeid
Definition Pointer.h:1349
std::optional< APValue > toRValue(const Context &Ctx, QualType ResultType) const
Converts the pointer to an APValue that is an rvalue.
Definition Pointer.cpp:1300
StringPointer Str
Definition Pointer.h:1350
const FunctionPointer & asFunctionPointer() const
Definition Pointer.h:837
const Block * block() const
Definition Pointer.h:1001
Pointer getDeclPtr() const
Definition Pointer.h:747
const Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition Pointer.h:711
PtrView view() const
Definition Pointer.h:600
bool isBaseClass() const
Checks if a structure is a base class.
Definition Pointer.h:941
size_t elemSize() const
Returns the element size of the innermost field.
Definition Pointer.h:750
const BlockPointer & asBlockPointer() const
Definition Pointer.h:829
static std::optional< std::pair< PtrView, PtrView > > computeSplitPoint(const Pointer &A, const Pointer &B)
Definition Pointer.cpp:1088
bool isElementInitialized(unsigned Index) const
Like isInitialized(), but for primitive arrays.
Definition Pointer.h:1214
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:52
PrimType
Enumeration of the primitive types of the VM.
Definition PrimType.h:34
bool Add(InterpState &S, CodePtr OpPC)
Definition Interp.h:404
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:6017
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:349
Block * Pointee
The block the pointer is pointing to.
Definition Pointer.h:347
const VarDecl * asVarDecl() const
Definition DeclOrExpr.h:38
Describes a memory block created by an allocation site.
Definition Descriptor.h:122
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition Descriptor.h:246
bool isPrimitive() const
Checks if the descriptor is of a primitive.
Definition Descriptor.h:260
QualType getElemQualType() const
const ValueDecl * asValueDecl() const
Definition Descriptor.h:205
QualType getType() const
const Decl * asDecl() const
Definition Descriptor.h:201
QualType getDataType(const ASTContext &Ctx) const
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition Descriptor.h:251
const FieldDecl * asFieldDecl() const
Definition Descriptor.h:213
const VarDecl * asVarDecl() const
Definition Descriptor.h:209
PrimType getPrimType() const
Definition Descriptor.h:231
bool isRecord() const
Checks if the descriptor is of a record.
Definition Descriptor.h:265
const Record *const ElemRecord
Pointer to the record, if block contains records.
Definition Descriptor.h:146
const Expr * asExpr() const
Definition Descriptor.h:202
bool isArray() const
Checks if the descriptor is of an array.
Definition Descriptor.h:263
Descriptor used for global variables.
Definition Descriptor.h:49
A pointer-sized struct we use to allocate into data storage.
Definition InitMap.h:79
bool hasInitMap() const
Definition InitMap.h:88
bool allInitialized() const
Are all elements in the array already initialized?
Definition InitMap.h:92
void setInitMap(const InitMap *IM)
Definition InitMap.h:94
Bitfield tracking the initialisation status of elements of primitive arrays.
Definition InitMap.h:22
void startElementLifetime(unsigned I)
Definition InitMap.cpp:32
void endElementLifetime(unsigned I)
Definition InitMap.cpp:45
bool allElementsAlive() const
Definition InitMap.h:58
bool isElementInitialized(unsigned I) const
Checks if an element was initialized.
Definition InitMap.cpp:23
bool initializeElement(unsigned I)
Initializes an element. Returns true when object if fully initialized.
Definition InitMap.cpp:13
bool isElementAlive(unsigned I) const
Definition InitMap.h:52
Inline descriptor embedded in structures and arrays.
Definition Descriptor.h:67
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition Descriptor.h:89
unsigned Offset
Offset inside the structure/array.
Definition Descriptor.h:69
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition Descriptor.h:80
QualType getPointeeType() const
Definition Pointer.h:366
IntPointer baseCast(const Context &Ctx, unsigned BaseOffset) const
Definition Pointer.cpp:1382
const Type * getType() const
Definition Pointer.h:363
std::optional< IntPointer > atOffset(const Context &Ctx, unsigned Offset) const
Definition Pointer.cpp:1353
llvm::PointerIntPair< const Type *, 2, unsigned > FieldType
Definition Pointer.h:442
QualType getObjectType() const
Definition Pointer.h:480
bool isRoot() const
Check if the pointer has offset 0.
Definition Pointer.cpp:1511
QualType getSurroundingArray() const
If this is pointing to an array element, return the array.
Definition Pointer.cpp:1480
bool isOnePastEndOrElementPastEnd() const
This is used in Pointer::isOnePastEnd().
Definition Pointer.cpp:1568
const PointerPathEntry * Path
Definition Pointer.h:443
ArrayRef< PointerPathEntry > path() const
Definition Pointer.h:446
bool isArrayElement() const
Definition Pointer.h:493
QualType getFieldType() const
Definition Pointer.h:487
std::optional< size_t > computeLayoutOffset(const ASTContext &ASTCtx) const
Definition Pointer.cpp:1418
llvm::PointerIntPair< const CXXRecordDecl *, 1, bool > RD
Definition Pointer.h:407
enum clang::interp::PointerPathEntry::@133156275124227243235357227301330162015140142322 Kind
const Descriptor * getDeclDesc() const
Definition Pointer.h:89
bool allElementsInitialized() const
Definition Pointer.cpp:880
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:752
bool isBaseClass() const
Definition Pointer.h:168
void activate() const
Definition Pointer.cpp:913
bool inArray() const
Definition Pointer.h:57
void startLifetime() const
Definition Pointer.h:334
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:326
InlineDescriptor * getInlineDesc() const
Definition Pointer.h:70
bool inUnion() const
Definition Pointer.h:56
void initializeElement(unsigned Index) const
Definition Pointer.cpp:852
void initialize() const
Definition Pointer.cpp:831
bool isOnePastEnd() const
Definition Pointer.h:192
bool isRoot() const
Definition Pointer.h:64
void setLifeState(Lifetime L) const
Definition Pointer.cpp:809
Lifetime getLifetime() const
Definition Pointer.cpp:790
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:395