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"
23#include "clang/AST/RecordLayout.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(D: RD);
33 return !T->isDependentType() && !T->isUndeducedAutoType() &&
34 !T->isSpecificBuiltinType(K: BuiltinType::UnknownAny) &&
35 !T->isIncompleteType();
36}
37
38Pointer::Pointer(Block *Pointee)
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: Pointee, .Base: Base, .Prev: nullptr, .Next: nullptr};
52 Pointee->addPointer(P: this);
53}
54
55Pointer::Pointer(const Pointer &P)
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(P: 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(Old: &P, New: 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
106Pointer::~Pointer() {
107 if (!isBlockPointer())
108 return;
109
110 if (Block *Pointee = BS.Pointee) {
111 Pointee->removePointer(P: this);
112 BS.Pointee = nullptr;
113 Pointee->cleanup();
114 }
115}
116
117Pointer &Pointer::operator=(const Pointer &P) {
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(P: 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(P: 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
163Pointer &Pointer::operator=(Pointer &&P) {
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(P: 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(P: 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) {
234 case PointerPathEntry::Base:
235 if (Opaque.Path[I].RD != P.Opaque.Path[I].RD)
236 return false;
237 break;
238 case PointerPathEntry::Array:
239 case PointerPathEntry::NegativeArray:
240 if (Opaque.Path[I].Index != P.Opaque.Path[I].Index)
241 return false;
242 break;
243 case PointerPathEntry::Field:
244 if (Opaque.Path[I].FD != P.Opaque.Path[I].FD)
245 return false;
246 break;
247 }
248 }
249 }
250 return true;
251}
252
253APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
254
255 if (isZero())
256 return APValue(APValue::LValueBase(), CharUnits::Zero(), {},
257 /*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
258
259 switch (StorageKind) {
260 case Storage::Int:
261 return APValue(static_cast<const Expr *>(nullptr),
262 CharUnits::fromQuantity(Quantity: asIntPointer().Value + this->Offset),
263 {},
264 /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
265 case Storage::Block:
266 // See below.
267 break;
268 case Storage::Fn: {
269 const FunctionPointer &FP = asFunctionPointer();
270 if (const FunctionDecl *FD = FP.Func->getDecl())
271 return APValue(FD, CharUnits::fromQuantity(Quantity: Offset), {},
272 /*OnePastTheEnd=*/false, /*IsNull=*/false);
273 return APValue(FP.Func->getExpr(), CharUnits::fromQuantity(Quantity: Offset), {},
274 /*OnePastTheEnd=*/false, /*IsNull=*/false);
275 } break;
276 case Storage::Typeid: {
277 TypeInfoLValue TypeInfo(Typeid.TypePtr);
278 return APValue(APValue::LValueBase::getTypeInfo(
279 LV: TypeInfo, TypeInfo: QualType(Typeid.TypeInfoType, 0)),
280 CharUnits::Zero(), {},
281 /*OnePastTheEnd=*/false, /*IsNull=*/false);
282 } break;
283 case Storage::String: {
284 llvm::SmallVector<APValue::LValuePathEntry, 1> Path;
285 if (Offset != 0 || Str.Decayed)
286 Path.push_back(Elt: APValue::LValuePathEntry::ArrayIndex(Index: Offset));
287
288 return APValue(APValue::LValueBase(Str.Base),
289 CharUnits::fromQuantity(Quantity: 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(u: 0);
296 size_t ElemSize = 0;
297 if (validType(T: Opaque.getFieldType()))
298 ElemSize = ASTCtx.getTypeSizeInChars(T: Opaque.getFieldType()).getQuantity();
299
300 auto LValueOffset =
301 CharUnits::fromQuantity(Quantity: LayoutOffset + (this->Offset * ElemSize));
302 APValue::LValueBase Base;
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.
309 APValue Result;
310 if (ValidBase) {
311 llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
312 for (const PointerPathEntry &Entry : Opaque.path()) {
313 switch (Entry.Kind) {
314 case PointerPathEntry::Field:
315 Path.push_back(Elt: APValue::LValuePathEntry({Entry.FD, false}));
316 break;
317 case PointerPathEntry::Base:
318 Path.push_back(Elt: APValue::LValuePathEntry(
319 {Entry.RD.getPointer(), Entry.RD.getInt()}));
320 break;
321 case PointerPathEntry::Array:
322 Path.push_back(Elt: APValue::LValuePathEntry::ArrayIndex(Index: Entry.Index));
323 break;
324 case PointerPathEntry::NegativeArray:
325 Path.push_back(Elt: APValue::LValuePathEntry::ArrayIndex(Index: -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();
344 APValue::LValueBase Base;
345 if (const auto *VD = Desc->asValueDecl())
346 Base = VD;
347 else if (const auto *E = Desc->asExpr()) {
348 if (block()->isDynamic()) {
349 DynamicAllocLValue DA(*block()->DynAllocId, Desc->getDynAllocKind());
350 Base =
351 APValue::LValueBase::getDynamicAlloc(LV: DA, Type: Desc->getDataType(Ctx: ASTCtx));
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(D: 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(D: FD->getParent());
366 unsigned FieldIndex = FD->getFieldIndex();
367 return ASTCtx.toCharUnitsFromBits(BitSize: Layout.getFieldOffset(FieldNo: FieldIndex));
368 };
369
370 // Build the path into the object.
371 bool OnePastEnd = isOnePastEnd() && !isZeroSizeArray();
372
373 llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
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(T: ElemType));
385 if (Ptr.getArray().getFieldDesc()->IsArray)
386 Path.push_back(Elt: 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(Elt: APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
392
393 if (const auto *FD = dyn_cast_if_present<FieldDecl>(Val: 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(T: ElemType));
418 }
419 if (Ptr.getArray().getFieldDesc()->IsArray)
420 Path.push_back(Elt: 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>(Val: 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>(Val: BaseOrMember)) {
435 IsVirtual = Ptr.isVirtualBaseClass();
436 Ptr = Ptr.getBase();
437 const Record *BaseRecord = Ptr.getRecord();
438
439 if (!ASTContext::hasLayout(D: BaseRecord->getDecl()))
440 return APValue();
441
442 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
443 D: cast<CXXRecordDecl>(Val: BaseRecord->getDecl()));
444 if (IsVirtual)
445 Offset += Layout.getVBaseClassOffset(VBase: RD);
446 else
447 Offset += Layout.getBaseClassOffset(Base: RD);
448
449 } else {
450 Ptr = Ptr.getBase();
451 }
452 Path.push_back(Elt: 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(first: Path.begin(), last: 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>
528Pointer::computeOffsetForComparison(const ASTContext &ASTCtx) const {
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:
536 return getIntegerRepresentation();
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()) {
561 Result += P.getInlineDesc()->Offset - sizeof(InlineDescriptor);
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(D: R->getDecl()))
587 return std::nullopt;
588 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: R->getDecl());
589 Result += ASTCtx
590 .toCharUnitsFromBits(
591 BitSize: Layout.getFieldOffset(FieldNo: P.getField()->getFieldIndex()))
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>
609Pointer::computeLayoutOffset(const ASTContext &ASTCtx) const {
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:
617 return getIntegerRepresentation();
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(T: FT))
626 TypeSize = ASTCtx.getTypeSizeInChars(T: 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>(Val: R->getDecl());
641 return cast<CXXRecordDecl>(Val: P.getFieldDesc()->asDecl());
642 };
643
644 auto getRecordSize = [&](const RecordDecl *RD) -> unsigned {
645 CanQualType RecordTy = ASTCtx.getCanonicalTagType(TD: RD);
646 return ASTCtx.getTypeSizeInChars(T: 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(D: BaseRD))
655 return std::nullopt;
656 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: BaseRD);
657 const CXXRecordDecl *RD = getRecordDecl(P);
658 if (P.isVirtualBaseClass())
659 Result += Layout.getVBaseClassOffset(VBase: RD).getQuantity();
660 else
661 Result += Layout.getBaseClassOffset(Base: 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();
696 if (!ASTContext::hasLayout(D: F->getParent()))
697 return std::nullopt;
698 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: F->getParent());
699 Result +=
700 ASTCtx.toCharUnitsFromBits(BitSize: Layout.getFieldOffset(FieldNo: F->getFieldIndex()))
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(ASTCtx: Ctx).getAsString(Ctx, Ty);
728}
729
730bool PtrView::isElementInitialized(unsigned Index) const {
731 const Descriptor *Desc = getFieldDesc();
732 assert(Desc);
733
734 if (Pointee->isStatic() && Base == 0)
735 return true;
736
737 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
738 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
739 return GD.InitState == GlobalInitState::Initialized;
740 }
741
742 if (Desc->isPrimitiveArray()) {
743 InitMapPtr IM = getInitMap();
744
745 if (IM.allInitialized())
746 return true;
747
748 if (!IM.hasInitMap())
749 return false;
750 return IM->isElementInitialized(I: Index);
751 }
752 return isInitialized();
753}
754
755bool Pointer::isElementAlive(unsigned Index) const {
756 assert(getFieldDesc()->isPrimitiveArray());
757
758 InitMapPtr &IM = getInitMap();
759 if (!IM.hasInitMap())
760 return true;
761
762 if (IM.allInitialized())
763 return true;
764
765 return IM->isElementAlive(I: Index);
766}
767
768Lifetime PtrView::getLifetime() const {
769 if (Base < sizeof(InlineDescriptor))
770 return Lifetime::Started;
771
772 if (inArray() && !isArrayRoot()) {
773 InitMapPtr &IM = getInitMap();
774
775 if (!IM.hasInitMap()) {
776 if (IM.allInitialized())
777 return Lifetime::Started;
778 return getArray().getLifetime();
779 }
780
781 return IM->isElementAlive(I: getIndex()) ? Lifetime::Started : Lifetime::Ended;
782 }
783
784 return getInlineDesc()->LifeState;
785}
786
787void PtrView::setLifeState(Lifetime L) const {
788 if (Base < sizeof(InlineDescriptor))
789 return;
790
791 if (inArray() && !isArrayRoot()) {
792 assert(L == Lifetime::Started || L == Lifetime::Ended);
793 const Descriptor *Desc = getFieldDesc();
794 InitMapPtr &IM = getInitMap();
795 if (!IM.hasInitMap())
796 IM.setInitMap(new InitMap(Desc->getNumElems(), IM.allInitialized()));
797
798 if (L == Lifetime::Ended)
799 IM->endElementLifetime(I: getIndex());
800 else if (L == Lifetime::Started)
801 IM->startElementLifetime(I: getIndex());
802 assert(isArrayRoot() || (this->getLifetime() == L));
803 return;
804 }
805
806 getInlineDesc()->LifeState = L;
807}
808
809void PtrView::initialize() const {
810 // FIXME: This happens when the control flow jumps right into a scope, e.g. in
811 // switch_into_init_stmt in constant-expression-cxx2a.cpp. I.e. we have never
812 // initialized the scope via an InitScope op.
813 if (LLVM_UNLIKELY(!Pointee->isInitialized()))
814 Pointee->invokeCtor();
815
816 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
817 auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
818 GD.InitState = GlobalInitState::Initialized;
819 return;
820 }
821
822 const Descriptor *Desc = getFieldDesc();
823 assert(Desc);
824 if (Desc->isPrimitiveArray()) {
825 if (Desc->getNumElems() != 0)
826 initializeElement(Index: getIndex());
827 return;
828 }
829
830 // Field has its bit in an inline descriptor.
831 assert(Base != 0 && "Only composite fields can be initialised");
832 getInlineDesc()->IsInitialized = true;
833 getInlineDesc()->LifeState = Lifetime::Started;
834}
835
836void PtrView::initializeElement(unsigned Index) const {
837 // Primitive global arrays don't have an initmap.
838 if (Pointee->isStatic() && Base == 0)
839 return;
840
841 assert(Index < getFieldDesc()->getNumElems());
842
843 // FIXME: This happens when the control flow jumps right into a scope, e.g. in
844 // switch_into_init_stmt in constant-expression-cxx2a.cpp. I.e. we have never
845 // initialized the scope via an InitScope op.
846 if (LLVM_UNLIKELY(!Pointee->isInitialized()))
847 Pointee->invokeCtor();
848
849 InitMapPtr &IM = getInitMap();
850 if (IM.allInitialized())
851 return;
852
853 if (!IM.hasInitMap()) {
854 const Descriptor *Desc = getFieldDesc();
855 IM.setInitMap(new InitMap(Desc->getNumElems()));
856 }
857 assert(IM.hasInitMap());
858
859 if (IM->initializeElement(I: Index))
860 IM.noteAllInitialized();
861}
862
863void Pointer::initializeAllElements() const {
864 assert(getFieldDesc()->isPrimitiveArray());
865 assert(isArrayRoot());
866
867 getInitMap().noteAllInitialized();
868}
869
870bool PtrView::allElementsInitialized() const {
871 assert(getFieldDesc()->isPrimitiveArray());
872 assert(isArrayRoot());
873
874 if (Pointee->isStatic() && Base == 0)
875 return true;
876
877 if (isRoot() && Base == sizeof(GlobalInlineDescriptor) && Offset == Base) {
878 const auto &GD = Pointee->getBlockDesc<GlobalInlineDescriptor>();
879 return GD.InitState == GlobalInitState::Initialized;
880 }
881
882 InitMapPtr IM = getInitMap();
883 return IM.allInitialized();
884}
885
886bool Pointer::allElementsAlive() const {
887 assert(getFieldDesc()->isPrimitiveArray());
888 assert(isArrayRoot());
889
890 if (isStatic() && BS.Base == 0)
891 return true;
892
893 if (isRoot() && BS.Base == sizeof(GlobalInlineDescriptor) &&
894 Offset == BS.Base) {
895 const auto &GD = block()->getBlockDesc<GlobalInlineDescriptor>();
896 return GD.InitState == GlobalInitState::Initialized;
897 }
898
899 InitMapPtr &IM = getInitMap();
900 return IM.allInitialized() || (IM.hasInitMap() && IM->allElementsAlive());
901}
902
903void PtrView::activate() const {
904 // Field has its bit in an inline descriptor.
905 assert(Base != 0 && "Only composite fields can be activated");
906
907 if (isRoot() && Base == sizeof(GlobalInlineDescriptor))
908 return;
909 if (!getInlineDesc()->InUnion)
910 return;
911
912 std::function<void(PtrView P)> activate;
913 activate = [&activate](PtrView P) -> void {
914 P.getInlineDesc()->IsActive = true;
915 P.startLifetime();
916 if (const Record *R = P.getRecord(); R && !R->isUnion()) {
917 for (const Record::Field &F : R->fields()) {
918 PtrView FieldPtr = P.atField(Offset: F.Offset);
919 if (!FieldPtr.getInlineDesc()->IsActive)
920 activate(FieldPtr);
921 }
922 // FIXME: Bases?
923 }
924 };
925
926 std::function<void(PtrView &)> deactivate;
927 deactivate = [&deactivate](PtrView &P) -> void {
928 P.getInlineDesc()->IsActive = false;
929
930 if (const Record *R = P.getRecord()) {
931 for (const Record::Field &F : R->fields()) {
932 PtrView FieldPtr = P.atField(Offset: F.Offset);
933 if (FieldPtr.getInlineDesc()->IsActive)
934 deactivate(FieldPtr);
935 }
936 // FIXME: Bases?
937 }
938 };
939
940 PtrView B = *this;
941 // Primitive array elements can't be activated individually, so
942 // look at the array root instead.
943 if (B.getFieldDesc()->isPrimitiveArray() && B.isArrayElement())
944 B = B.getArray();
945
946 while (!B.isRoot() && B.inUnion()) {
947 activate(B);
948
949 // When walking up the pointer chain, deactivate
950 // all union child pointers that aren't on our path.
951 PtrView Cur = B;
952 B = B.getBase();
953 if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
954 for (const Record::Field &F : BR->fields()) {
955 PtrView FieldPtr = B.atField(Offset: F.Offset);
956 if (FieldPtr != Cur)
957 deactivate(FieldPtr);
958 }
959 }
960 }
961}
962
963bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
964 // Two null pointers always have the same base.
965 if (A.isZero() && B.isZero())
966 return true;
967
968 // We allow comparisons between opaque pointers and block pointers, provided
969 // they have the same declaration as base.
970 if (A.StorageKind != B.StorageKind) {
971 if (A.isOpaquePointer() && A.Opaque.Base.isVarDecl() &&
972 B.isBlockPointer()) {
973 if (const VarDecl *BDecl = B.block()->getDescriptor()->asVarDecl())
974 return BDecl == A.Opaque.Base.asVarDecl()->getMostRecentDecl();
975 return false;
976 }
977 if (B.isOpaquePointer() && B.Opaque.Base.isVarDecl() &&
978 A.isBlockPointer()) {
979 if (const VarDecl *ADecl = A.block()->getDescriptor()->asVarDecl())
980 return ADecl == B.Opaque.Base.asVarDecl()->getMostRecentDecl();
981 return false;
982 }
983 return false;
984 }
985
986 switch (A.StorageKind) {
987 case Storage::Int:
988 return true;
989 case Storage::Block:
990 return A.BS.Pointee == B.BS.Pointee;
991 case Storage::Fn:
992 return true;
993 case Storage::Typeid:
994 return A.asTypeidPointer().TypePtr == B.asTypeidPointer().TypePtr;
995 case Storage::String:
996 return A.Str.ID == B.Str.ID && A.Str.getLiteral() == B.Str.getLiteral();
997 case Storage::Opaque:
998 if (A.Opaque.Base.isExpr())
999 return B.Opaque.Base.isExpr() && A.Opaque.Base == B.Opaque.Base;
1000 if (A.Opaque.Base.isVarDecl())
1001 return B.Opaque.Base.isVarDecl() &&
1002 A.Opaque.Base.asVarDecl()->getMostRecentDecl() ==
1003 B.Opaque.Base.asVarDecl()->getMostRecentDecl();
1004 return false;
1005 }
1006 llvm_unreachable("should have been handled by the fully covered switch");
1007}
1008
1009bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
1010 if (!A.isBlockPointer() || !B.isBlockPointer())
1011 return false;
1012 return A.block() == B.block();
1013}
1014
1015bool Pointer::elemsOfSameArray(const Pointer &A, const Pointer &B) {
1016 assert(hasSameBase(A, B));
1017 assert(A.isBlockPointer());
1018 assert(B.isBlockPointer());
1019
1020 if (A.BS.Base == B.BS.Base)
1021 return true;
1022
1023 if (A.isBaseClass() || B.isBaseClass())
1024 return false;
1025
1026 if (A.getField() || B.getField())
1027 return false;
1028
1029 auto closestArray = [](const Pointer &P) -> PtrView {
1030 if (P.isArrayRoot())
1031 return P.view();
1032
1033 PtrView V = P.view();
1034 if (V.isArrayElement() || V.isOnePastEnd())
1035 V = V.expand().getArray();
1036
1037 if (P.isRoot())
1038 return P.view();
1039
1040 while (!V.isRoot() && !V.getFieldDesc()->IsArray) {
1041 if (V.isArrayElement()) {
1042 V = V.expand().getArray();
1043 break;
1044 }
1045 V = V.getBase();
1046 }
1047 return V;
1048 };
1049
1050 if (closestArray(A) != closestArray(B))
1051 return false;
1052
1053 return true;
1054}
1055
1056// FIXME: This should return true for string pointers.
1057bool Pointer::pointsToLiteral() const {
1058 if (isZero())
1059 return false;
1060
1061 if (isDynamic())
1062 return false;
1063
1064 const Expr *E = getRootExpr();
1065 return E && !isa<MaterializeTemporaryExpr, StringLiteral>(Val: E);
1066}
1067
1068bool Pointer::pointsToLabel() const {
1069 if (isZero())
1070 return false;
1071
1072 if (isOpaquePointer())
1073 return isa_and_nonnull<AddrLabelExpr>(Val: Opaque.Base.asExpr());
1074 return false;
1075}
1076
1077std::optional<std::pair<PtrView, PtrView>>
1078Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
1079 if (!A.isBlockPointer() || !B.isBlockPointer())
1080 return std::nullopt;
1081
1082 if (A.asBlockPointer().Pointee != B.asBlockPointer().Pointee)
1083 return std::nullopt;
1084 if (A.isRoot() && B.isRoot())
1085 return std::nullopt;
1086
1087 if (A == B)
1088 return std::make_pair(x: A.view(), y: B.view());
1089
1090 auto getBase = [](PtrView P) -> PtrView {
1091 if (P.isArrayElement())
1092 return P.expand().getArray();
1093 return P.getBase();
1094 };
1095
1096 PtrView IterA = A.view();
1097 PtrView IterB = B.view();
1098 PtrView CurA = IterA;
1099 PtrView CurB = IterB;
1100 for (;;) {
1101 if (IterA.Base > IterB.Base) {
1102 CurA = IterA;
1103 IterA = getBase(IterA);
1104 } else {
1105 CurB = IterB;
1106 IterB = getBase(IterB);
1107 }
1108
1109 if (IterA == IterB) {
1110 // If the Iter is an array, CurA and CurB are both elements of the same
1111 // array. That is fine, so return nullopt.
1112 if (IterA.getFieldDesc()->isArray())
1113 return std::nullopt;
1114 return std::make_pair(x&: CurA, y&: CurB);
1115 }
1116
1117 if (IterA.isRoot() && IterB.isRoot())
1118 return std::nullopt;
1119 }
1120
1121 llvm_unreachable("The loop above should've returned.");
1122}
1123
1124/// Convert a pointer to a composite value to an rvalue.
1125static bool toRValue(const Context &Ctx, QualType Ty, PtrView Ptr, APValue &R) {
1126 const ASTContext &ASTCtx = Ctx.getASTContext();
1127 if (const auto *AT = Ty->getAs<AtomicType>())
1128 Ty = AT->getValueType();
1129
1130 // Invalid pointers.
1131 if (!Ptr.isLive() || Ptr.isPastEnd())
1132 return false;
1133
1134 // Primitives should never end up here.
1135 assert(!Ctx.canClassify(Ty));
1136 const Descriptor *FieldDesc = Ptr.getFieldDesc();
1137 assert(FieldDesc);
1138
1139 if (const auto *RT = Ty->getAsCanonical<RecordType>()) {
1140 if (!FieldDesc->isRecord())
1141 return false;
1142 const auto *Record = Ptr.getRecord();
1143 assert(Record && "Missing record descriptor");
1144
1145 bool Ok = true;
1146 if (RT->getDecl()->isUnion()) {
1147 const FieldDecl *ActiveField = nullptr;
1148 APValue Value;
1149 for (const auto &F : Record->fields()) {
1150 PtrView FP = Ptr.atField(Offset: F.Offset);
1151 if (FP.isActive()) {
1152 const Descriptor *Desc = F.Desc;
1153 if (Desc->isPrimitive()) {
1154 TYPE_SWITCH(Desc->getPrimType(),
1155 Value = FP.deref<T>().toAPValue(ASTCtx));
1156 } else {
1157 QualType FieldTy = F.Decl->getType();
1158 Ok &= toRValue(Ctx, Ty: FieldTy, Ptr: FP, R&: Value);
1159 }
1160 ActiveField = FP.getFieldDesc()->asFieldDecl();
1161 break;
1162 }
1163 }
1164 R = APValue(ActiveField, Value);
1165 } else {
1166 unsigned NF = Record->getNumFields();
1167 unsigned NB = Record->getNumBases();
1168 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
1169
1170 R = APValue(APValue::UninitStruct(), NB, NF, NV);
1171
1172 for (unsigned I = 0; I != NF; ++I) {
1173 const Record::Field *FD = Record->getField(I);
1174 const Descriptor *Desc = FD->Desc;
1175 PtrView FP = Ptr.atField(Offset: FD->Offset);
1176 APValue &Value = R.getStructField(i: I);
1177 if (Desc->isPrimitive()) {
1178 TYPE_SWITCH(Desc->getPrimType(),
1179 Value = FP.deref<T>().toAPValue(ASTCtx));
1180 } else {
1181 QualType FieldTy = FD->Decl->getType();
1182 Ok &= toRValue(Ctx, Ty: FieldTy, Ptr: FP, R&: Value);
1183 }
1184 }
1185
1186 for (unsigned I = 0; I != NB; ++I) {
1187 const Record::Base *BD = Record->getBase(I);
1188 QualType BaseTy = Ctx.getASTContext().getCanonicalTagType(TD: BD->Decl);
1189 PtrView BP = Ptr.atField(Offset: BD->Offset);
1190 Ok &= toRValue(Ctx, Ty: BaseTy, Ptr: BP, R&: R.getStructBase(i: I));
1191 }
1192
1193 for (unsigned I = 0; I != NV; ++I) {
1194 const Record::Base *VD = Record->getVirtualBase(I);
1195 assert(VD);
1196 QualType VirtBaseTy = Ctx.getASTContext().getCanonicalTagType(TD: VD->Decl);
1197 PtrView VP = Ptr.atField(Offset: VD->Offset);
1198 Ok &= toRValue(Ctx, Ty: VirtBaseTy, Ptr: VP, R&: R.getStructVirtualBase(i: I));
1199 }
1200 }
1201 return Ok;
1202 }
1203
1204 if (Ty->isIncompleteArrayType()) {
1205 R = APValue(APValue::UninitArray(), 0, 0);
1206 return true;
1207 }
1208
1209 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
1210 if (!FieldDesc->isArray())
1211 return false;
1212 const size_t NumElems = Ptr.getNumElems();
1213 QualType ElemTy = AT->getElementType();
1214 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
1215
1216 bool Ok = true;
1217 OptPrimType ElemT = Ctx.classify(T: ElemTy);
1218 for (unsigned I = 0; I != NumElems; ++I) {
1219 APValue &Slot = R.getArrayInitializedElt(I);
1220 if (ElemT) {
1221 TYPE_SWITCH(*ElemT, Slot = Ptr.elem<T>(I).toAPValue(ASTCtx));
1222 } else {
1223 Ok &= toRValue(Ctx, Ty: ElemTy, Ptr: Ptr.atIndex(Idx: I).narrow(), R&: Slot);
1224 }
1225 }
1226 return Ok;
1227 }
1228
1229 // Complex types.
1230 if (Ty->isAnyComplexType()) {
1231 // Can happen via C casts.
1232 if (!FieldDesc->getType()->isAnyComplexType())
1233 return false;
1234
1235 PrimType ElemT = FieldDesc->getPrimType();
1236 if (isIntegerOrBoolType(T: ElemT)) {
1237 INT_TYPE_SWITCH(ElemT, {
1238 auto V1 = Ptr.elem<T>(0);
1239 auto V2 = Ptr.elem<T>(1);
1240 R = APValue(V1.toAPSInt(), V2.toAPSInt());
1241 return true;
1242 });
1243 } else if (ElemT == PT_Float) {
1244 R = APValue(Ptr.elem<Floating>(I: 0).getAPFloat(),
1245 Ptr.elem<Floating>(I: 1).getAPFloat());
1246 return true;
1247 }
1248 return false;
1249 }
1250
1251 // Vector types.
1252 if (const auto *VT = Ty->getAs<VectorType>()) {
1253 if (!FieldDesc->isPrimitiveArray())
1254 return false;
1255
1256 PrimType ElemT = FieldDesc->getPrimType();
1257 SmallVector<APValue> Values;
1258 Values.reserve(N: VT->getNumElements());
1259 for (unsigned I = 0; I != VT->getNumElements(); ++I) {
1260 TYPE_SWITCH(ElemT,
1261 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1262 }
1263
1264 assert(Values.size() == VT->getNumElements());
1265 R = APValue(Values.data(), Values.size());
1266 return true;
1267 }
1268
1269 // Constant Matrix types.
1270 if (const auto *MT = Ty->getAs<ConstantMatrixType>()) {
1271 if (!FieldDesc->isPrimitiveArray())
1272 return false;
1273 PrimType ElemT = FieldDesc->getPrimType();
1274 unsigned NumElems = MT->getNumElementsFlattened();
1275
1276 SmallVector<APValue> Values;
1277 Values.reserve(N: NumElems);
1278 for (unsigned I = 0; I != NumElems; ++I) {
1279 TYPE_SWITCH(ElemT,
1280 { Values.push_back(Ptr.elem<T>(I).toAPValue(ASTCtx)); });
1281 }
1282
1283 R = APValue(Values.data(), MT->getNumRows(), MT->getNumColumns());
1284 return true;
1285 }
1286
1287 llvm_unreachable("invalid value to return");
1288}
1289
1290std::optional<APValue> Pointer::toRValue(const Context &Ctx,
1291 QualType ResultType) const {
1292 const ASTContext &ASTCtx = Ctx.getASTContext();
1293 assert(!ResultType.isNull());
1294
1295 // Can't return functions as rvalues.
1296 if (ResultType->isFunctionType())
1297 return std::nullopt;
1298
1299 // Invalid to read from.
1300 if (isDummy() || !isLive() || isPastEnd() ||
1301 (isOnePastEnd() && !isZeroSizeArray()))
1302 return std::nullopt;
1303
1304 // We can return these as rvalues, but we can't deref() them.
1305 if (isZero() || isIntegralPointer())
1306 return toAPValue(ASTCtx);
1307
1308 // Just load primitive types.
1309 if (OptPrimType T = Ctx.classify(T: ResultType)) {
1310 if (!canDeref(T: *T))
1311 return std::nullopt;
1312 TYPE_SWITCH(*T, return this->load<T>().toAPValue(ASTCtx));
1313 }
1314
1315 if (!isBlockPointer())
1316 return std::nullopt;
1317
1318 // Return the composite type.
1319 APValue Result;
1320 if (!::toRValue(Ctx, Ty: ResultType, Ptr: view(), R&: Result))
1321 return std::nullopt;
1322 return Result;
1323}
1324
1325const VarDecl *Pointer::getRootVarDecl() const {
1326 return dyn_cast_if_present<VarDecl>(Val: getRootValueDecl());
1327}
1328
1329const ValueDecl *Pointer::getRootValueDecl() const {
1330 if (isBlockPointer())
1331 return getDeclDesc()->asValueDecl();
1332 if (isOpaquePointer())
1333 return Opaque.getBaseDecl();
1334 return nullptr;
1335}
1336
1337const Expr *Pointer::getRootExpr() const {
1338 if (isBlockPointer())
1339 return getDeclDesc()->asExpr();
1340 if (isStringPointer())
1341 return Str.getLiteral();
1342 if (isOpaquePointer())
1343 return Opaque.getBaseExpr();
1344 return nullptr;
1345}
1346
1347std::optional<IntPointer> IntPointer::atOffset(const interp::Context &Ctx,
1348 unsigned Offset) const {
1349 QualType CurType = getPointeeType();
1350 if (CurType.isNull() || !CurType->isRecordType())
1351 return std::nullopt;
1352
1353 const Record *R = Ctx.getRecord(D: CurType->getAsRecordDecl());
1354 if (!R)
1355 return *this;
1356
1357 const Record::Field *F = R->findField(Offset);
1358 if (!F)
1359 return *this;
1360
1361 const FieldDecl *FD = F->Decl;
1362 if (FD->getParent()->isInvalidDecl())
1363 return std::nullopt;
1364
1365 const ASTContext &ASTCtx = Ctx.getASTContext();
1366 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: FD->getParent());
1367 unsigned FieldIndex = FD->getFieldIndex();
1368 uint64_t FieldOffset =
1369 ASTCtx.toCharUnitsFromBits(BitSize: Layout.getFieldOffset(FieldNo: FieldIndex))
1370 .getQuantity();
1371
1372 uint64_t NewValue = this->Value + FieldOffset;
1373 return IntPointer{.TypeAndIsNull: {FD->getType().getTypePtr(), NewValue == 0}, .Value: NewValue};
1374}
1375
1376IntPointer IntPointer::baseCast(const interp::Context &Ctx,
1377 unsigned BaseOffset) const {
1378 if (!getType())
1379 return *this;
1380
1381 QualType CurType = getPointeeType();
1382 if (CurType.isNull() || !CurType->isRecordType())
1383 return *this;
1384
1385 // null pointers stay null during a cast, per conv.ptr
1386 if (Value == 0)
1387 return *this;
1388
1389 const Record *R = Ctx.getRecord(D: CurType->getAsRecordDecl());
1390
1391 // This iterates over bases and checks for the proper offset. That's
1392 // potentially slow but this case really shouldn't happen a lot.
1393 const Record::Base *B = R->findBase(Offset: BaseOffset);
1394 if (!B)
1395 return *this;
1396
1397 const Descriptor *BaseDesc = B->Desc;
1398 // Adjust the offset value based on the information from the record layout.
1399 const ASTContext &ASTCtx = Ctx.getASTContext();
1400 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: R->getDecl());
1401 CharUnits BaseLayoutOffset =
1402 Layout.getBaseClassOffset(Base: cast<CXXRecordDecl>(Val: BaseDesc->asDecl()));
1403
1404 const RecordDecl *RD = BaseDesc->ElemRecord->getDecl();
1405 QualType T = RD->getASTContext().getTagType(Keyword: ElaboratedTypeKeyword::None,
1406 Qualifier: std::nullopt, TD: RD, OwnsTag: false);
1407 uint64_t NewValue = Value + BaseLayoutOffset.getQuantity();
1408 return {.TypeAndIsNull: {T.getTypePtr(), NewValue == 0}, .Value: NewValue};
1409}
1410
1411std::optional<size_t>
1412OpaquePointer::computeLayoutOffset(const ASTContext &ASTCtx) const {
1413 size_t Offset = 0;
1414 QualType CurType = getObjectType();
1415 for (const PointerPathEntry &Entry : path()) {
1416 switch (Entry.Kind) {
1417 case PointerPathEntry::Base: {
1418 const RecordDecl *RD = CurType->getAsRecordDecl();
1419 if (!ASTContext::hasLayout(D: RD))
1420 return std::nullopt;
1421
1422 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: RD);
1423 if (Entry.RD.getInt())
1424 Offset +=
1425 Layout.getVBaseClassOffset(VBase: Entry.RD.getPointer()).getQuantity();
1426 else
1427 Offset +=
1428 Layout.getBaseClassOffset(Base: Entry.RD.getPointer()).getQuantity();
1429
1430 CurType = ASTCtx.getCanonicalTagType(TD: Entry.RD.getPointer());
1431 } break;
1432
1433 case PointerPathEntry::Field: {
1434 const FieldDecl *FD = Entry.FD;
1435 const RecordDecl *RD = FD->getParent();
1436 if (!ASTContext::hasLayout(D: RD))
1437 return std::nullopt;
1438
1439 const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(D: RD);
1440 Offset +=
1441 ASTCtx.toCharUnitsFromBits(BitSize: Layout.getFieldOffset(FieldNo: FD->getFieldIndex()))
1442 .getQuantity();
1443
1444 CurType = FD->getType();
1445 } break;
1446 case PointerPathEntry::Array:
1447 case PointerPathEntry::NegativeArray: {
1448 bool Add = (Entry.Kind == PointerPathEntry::Array);
1449 uint64_t Index = Entry.Index;
1450 if (!CurType->isArrayType()) {
1451 if (Add)
1452 Offset += Index * ASTCtx.getTypeSizeInChars(T: CurType).getQuantity();
1453 else
1454 Offset -= Index * ASTCtx.getTypeSizeInChars(T: CurType).getQuantity();
1455 continue;
1456 }
1457 const ArrayType *AT = CurType->getAsArrayTypeUnsafe();
1458 assert(AT);
1459 QualType ElemTy = AT->getElementType();
1460 if (!validType(T: ElemTy) || isa<VariableArrayType>(Val: AT))
1461 return std::nullopt;
1462 if (Add)
1463 Offset += Index * ASTCtx.getTypeSizeInChars(T: ElemTy).getQuantity();
1464 else
1465 Offset -= Index * ASTCtx.getTypeSizeInChars(T: ElemTy).getQuantity();
1466 CurType = AT->getElementType();
1467 } break;
1468 }
1469 }
1470
1471 return Offset;
1472}
1473
1474QualType OpaquePointer::getSurroundingArray() const {
1475 if (PathLength == 0)
1476 return getObjectType();
1477 if (Path[PathLength - 1].Kind != PointerPathEntry::Array)
1478 return getFieldType();
1479
1480 assert(Path[PathLength - 1].Kind == PointerPathEntry::Array);
1481 assert(isArrayElement());
1482
1483 QualType CurType = getObjectType();
1484 for (const PointerPathEntry &Entry : path().drop_back(N: 1)) {
1485 switch (Entry.Kind) {
1486 case PointerPathEntry::Base:
1487 CurType = Entry.RD.getPointer()->getASTContext().getCanonicalTagType(
1488 TD: Entry.RD.getPointer());
1489 break;
1490 case PointerPathEntry::Field:
1491 CurType = Entry.FD->getType();
1492 break;
1493 case PointerPathEntry::Array:
1494 case PointerPathEntry::NegativeArray:
1495 if (!CurType->isArrayType())
1496 break;
1497 CurType = CurType->getAsArrayTypeUnsafe()->getElementType();
1498 }
1499 }
1500 return CurType;
1501}
1502
1503/// Check if the pointer has offset 0.
1504// As an optimization, don't actually compute the offset.
1505bool OpaquePointer::isRoot() const {
1506 QualType CurType = getObjectType();
1507 for (const PointerPathEntry &Entry : path()) {
1508 switch (Entry.Kind) {
1509 case PointerPathEntry::Base:
1510 if (Entry.RD.getInt())
1511 return false;
1512 CurType = Entry.RD.getPointer()->getASTContext().getCanonicalTagType(
1513 TD: Entry.RD.getPointer());
1514 break;
1515 case PointerPathEntry::Field:
1516 if (!Entry.FD->getParent()->isUnion() && Entry.FD->getFieldIndex() != 0)
1517 return false;
1518 CurType = Entry.FD->getType();
1519 break;
1520 case PointerPathEntry::Array:
1521 if (Entry.Index != 0)
1522 return false;
1523 if (!CurType->isArrayType())
1524 continue;
1525 CurType = CurType->getAsArrayTypeUnsafe()->getElementType();
1526 break;
1527 case PointerPathEntry::NegativeArray:
1528 return false;
1529 }
1530 }
1531 return true;
1532}
1533
1534bool OpaquePointer::isUnknownSizeArray() const {
1535 QualType FieldType = getFieldType();
1536
1537 if (isArrayElement())
1538 FieldType = getSurroundingArray();
1539
1540 bool Result = false;
1541 // If the field type is an IncompleteArrayType, we still need to check the
1542 // base to see if this array is a flexible array member _and_ has actually
1543 // been initialized by data we know the size of.
1544 if (isa<IncompleteArrayType>(Val: FieldType)) {
1545 const VarDecl *Base = this->Base.asVarDecl();
1546 if (!Base || !Base->getType()->isRecordType() || !Base->hasInit())
1547 Result = true;
1548 else
1549 Result = !Base->hasFlexibleArrayInit(Ctx: Base->getASTContext());
1550 } else if (isa<VariableArrayType>(Val: FieldType))
1551 Result = true;
1552
1553 return Result;
1554}
1555
1556/// This is used in Pointer::isOnePastEnd(). We cannot read from such pointers.
1557/// We can of course never read from opaque pointers anyway but we diagnose
1558/// one-past-the-end pointers differently.
1559///
1560/// In contrast, OpaquePointer::isOnePastEnd() only uses the past-end bit. That
1561/// is used for the APValue conversion.
1562bool OpaquePointer::isOnePastEndOrElementPastEnd() const {
1563 if (isOnePastEnd())
1564 return true;
1565
1566 if (PathLength == 0)
1567 return false;
1568
1569 if (Path[PathLength - 1].Kind != PointerPathEntry::Array)
1570 return false;
1571
1572 QualType ArrTy = getSurroundingArray();
1573 if (!ArrTy->isArrayType())
1574 return false;
1575 // FIXME: Flexible array members?
1576 if (const auto *CAT =
1577 dyn_cast<ConstantArrayType>(Val: ArrTy->getAsArrayTypeUnsafe())) {
1578 if (Path[PathLength - 1].Index >= CAT->getZExtSize())
1579 return true;
1580 }
1581
1582 return false;
1583}
1584
1585bool OpaquePointer::hasValidBase() const {
1586 if (const VarDecl *VD = Base.asVarDecl())
1587 return !VD->hasExternalStorage();
1588
1589 return !Base.getType()->isPointerType();
1590}
1591