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