Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Pointer.cpp
213799 views
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 "Context.h"
12
#include "Floating.h"
13
#include "Function.h"
14
#include "Integral.h"
15
#include "InterpBlock.h"
16
#include "MemberPointer.h"
17
#include "PrimType.h"
18
#include "Record.h"
19
#include "clang/AST/ExprCXX.h"
20
#include "clang/AST/RecordLayout.h"
21
22
using namespace clang;
23
using namespace clang::interp;
24
25
Pointer::Pointer(Block *Pointee)
26
: Pointer(Pointee, Pointee->getDescriptor()->getMetadataSize(),
27
Pointee->getDescriptor()->getMetadataSize()) {}
28
29
Pointer::Pointer(Block *Pointee, uint64_t BaseAndOffset)
30
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
31
32
Pointer::Pointer(const Pointer &P)
33
: Offset(P.Offset), StorageKind(P.StorageKind),
34
PointeeStorage(P.PointeeStorage) {
35
36
if (isBlockPointer() && PointeeStorage.BS.Pointee)
37
PointeeStorage.BS.Pointee->addPointer(this);
38
}
39
40
Pointer::Pointer(Block *Pointee, unsigned Base, uint64_t Offset)
41
: Offset(Offset), StorageKind(Storage::Block) {
42
assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
43
44
PointeeStorage.BS = {Pointee, Base};
45
46
if (Pointee)
47
Pointee->addPointer(this);
48
}
49
50
Pointer::Pointer(Pointer &&P)
51
: Offset(P.Offset), StorageKind(P.StorageKind),
52
PointeeStorage(P.PointeeStorage) {
53
54
if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
55
PointeeStorage.BS.Pointee->replacePointer(&P, this);
56
}
57
58
Pointer::~Pointer() {
59
if (!isBlockPointer())
60
return;
61
62
if (Block *Pointee = PointeeStorage.BS.Pointee) {
63
Pointee->removePointer(this);
64
PointeeStorage.BS.Pointee = nullptr;
65
Pointee->cleanup();
66
}
67
}
68
69
void Pointer::operator=(const Pointer &P) {
70
// If the current storage type is Block, we need to remove
71
// this pointer from the block.
72
if (isBlockPointer()) {
73
if (P.isBlockPointer() && this->block() == P.block()) {
74
Offset = P.Offset;
75
PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
76
return;
77
}
78
79
if (Block *Pointee = PointeeStorage.BS.Pointee) {
80
Pointee->removePointer(this);
81
PointeeStorage.BS.Pointee = nullptr;
82
Pointee->cleanup();
83
}
84
}
85
86
StorageKind = P.StorageKind;
87
Offset = P.Offset;
88
89
if (P.isBlockPointer()) {
90
PointeeStorage.BS = P.PointeeStorage.BS;
91
PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
92
93
if (PointeeStorage.BS.Pointee)
94
PointeeStorage.BS.Pointee->addPointer(this);
95
} else if (P.isIntegralPointer()) {
96
PointeeStorage.Int = P.PointeeStorage.Int;
97
} else if (P.isFunctionPointer()) {
98
PointeeStorage.Fn = P.PointeeStorage.Fn;
99
} else if (P.isTypeidPointer()) {
100
PointeeStorage.Typeid = P.PointeeStorage.Typeid;
101
} else {
102
assert(false && "Unhandled storage kind");
103
}
104
}
105
106
void Pointer::operator=(Pointer &&P) {
107
// If the current storage type is Block, we need to remove
108
// this pointer from the block.
109
if (isBlockPointer()) {
110
if (P.isBlockPointer() && this->block() == P.block()) {
111
Offset = P.Offset;
112
PointeeStorage.BS.Base = P.PointeeStorage.BS.Base;
113
return;
114
}
115
116
if (Block *Pointee = PointeeStorage.BS.Pointee) {
117
Pointee->removePointer(this);
118
PointeeStorage.BS.Pointee = nullptr;
119
Pointee->cleanup();
120
}
121
}
122
123
StorageKind = P.StorageKind;
124
Offset = P.Offset;
125
126
if (P.isBlockPointer()) {
127
PointeeStorage.BS = P.PointeeStorage.BS;
128
PointeeStorage.BS.Pointee = P.PointeeStorage.BS.Pointee;
129
130
if (PointeeStorage.BS.Pointee)
131
PointeeStorage.BS.Pointee->addPointer(this);
132
} else if (P.isIntegralPointer()) {
133
PointeeStorage.Int = P.PointeeStorage.Int;
134
} else if (P.isFunctionPointer()) {
135
PointeeStorage.Fn = P.PointeeStorage.Fn;
136
} else if (P.isTypeidPointer()) {
137
PointeeStorage.Typeid = P.PointeeStorage.Typeid;
138
} else {
139
assert(false && "Unhandled storage kind");
140
}
141
}
142
143
APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
144
llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
145
146
if (isZero())
147
return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
148
/*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
149
if (isIntegralPointer())
150
return APValue(static_cast<const Expr *>(nullptr),
151
CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
152
Path,
153
/*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
154
if (isFunctionPointer()) {
155
const FunctionPointer &FP = asFunctionPointer();
156
if (const FunctionDecl *FD = FP.getFunction()->getDecl())
157
return APValue(FD, CharUnits::fromQuantity(Offset), {},
158
/*OnePastTheEnd=*/false, /*IsNull=*/false);
159
return APValue(FP.getFunction()->getExpr(), CharUnits::fromQuantity(Offset),
160
{},
161
/*OnePastTheEnd=*/false, /*IsNull=*/false);
162
}
163
164
if (isTypeidPointer()) {
165
TypeInfoLValue TypeInfo(PointeeStorage.Typeid.TypePtr);
166
return APValue(
167
APValue::LValueBase::getTypeInfo(
168
TypeInfo, QualType(PointeeStorage.Typeid.TypeInfoType, 0)),
169
CharUnits::Zero(), {},
170
/*OnePastTheEnd=*/false, /*IsNull=*/false);
171
}
172
173
// Build the lvalue base from the block.
174
const Descriptor *Desc = getDeclDesc();
175
APValue::LValueBase Base;
176
if (const auto *VD = Desc->asValueDecl())
177
Base = VD;
178
else if (const auto *E = Desc->asExpr()) {
179
if (block()->isDynamic()) {
180
QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
181
// FIXME: Suboptimal counting of dynamic allocations. Move this to Context
182
// or InterpState?
183
static int ReportedDynamicAllocs = 0;
184
DynamicAllocLValue DA(ReportedDynamicAllocs++);
185
Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
186
} else {
187
Base = E;
188
}
189
} else
190
llvm_unreachable("Invalid allocation type");
191
192
if (isUnknownSizeArray())
193
return APValue(Base, CharUnits::Zero(), Path,
194
/*IsOnePastEnd=*/isOnePastEnd(), /*IsNullPtr=*/false);
195
196
CharUnits Offset = CharUnits::Zero();
197
198
auto getFieldOffset = [&](const FieldDecl *FD) -> CharUnits {
199
// This shouldn't happen, but if it does, don't crash inside
200
// getASTRecordLayout.
201
if (FD->getParent()->isInvalidDecl())
202
return CharUnits::Zero();
203
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
204
unsigned FieldIndex = FD->getFieldIndex();
205
return ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex));
206
};
207
208
bool UsePath = true;
209
if (const ValueDecl *VD = getDeclDesc()->asValueDecl();
210
VD && VD->getType()->isReferenceType())
211
UsePath = false;
212
213
// Build the path into the object.
214
bool OnePastEnd = isOnePastEnd();
215
Pointer Ptr = *this;
216
while (Ptr.isField() || Ptr.isArrayElement()) {
217
218
if (Ptr.isArrayRoot()) {
219
// An array root may still be an array element itself.
220
if (Ptr.isArrayElement()) {
221
Ptr = Ptr.expand();
222
const Descriptor *Desc = Ptr.getFieldDesc();
223
unsigned Index = Ptr.getIndex();
224
QualType ElemType = Desc->getElemQualType();
225
Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
226
if (Ptr.getArray().getType()->isArrayType())
227
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
228
Ptr = Ptr.getArray();
229
} else {
230
const Descriptor *Desc = Ptr.getFieldDesc();
231
const auto *Dcl = Desc->asDecl();
232
Path.push_back(APValue::LValuePathEntry({Dcl, /*IsVirtual=*/false}));
233
234
if (const auto *FD = dyn_cast_if_present<FieldDecl>(Dcl))
235
Offset += getFieldOffset(FD);
236
237
Ptr = Ptr.getBase();
238
}
239
} else if (Ptr.isArrayElement()) {
240
Ptr = Ptr.expand();
241
const Descriptor *Desc = Ptr.getFieldDesc();
242
unsigned Index;
243
if (Ptr.isOnePastEnd()) {
244
Index = Ptr.getArray().getNumElems();
245
OnePastEnd = false;
246
} else
247
Index = Ptr.getIndex();
248
249
QualType ElemType = Desc->getElemQualType();
250
if (const auto *RD = ElemType->getAsRecordDecl();
251
RD && !RD->getDefinition()) {
252
// Ignore this for the offset.
253
} else {
254
Offset += (Index * ASTCtx.getTypeSizeInChars(ElemType));
255
}
256
if (Ptr.getArray().getType()->isArrayType())
257
Path.push_back(APValue::LValuePathEntry::ArrayIndex(Index));
258
Ptr = Ptr.getArray();
259
} else {
260
const Descriptor *Desc = Ptr.getFieldDesc();
261
bool IsVirtual = false;
262
263
// Create a path entry for the field.
264
if (const auto *BaseOrMember = Desc->asDecl()) {
265
if (const auto *FD = dyn_cast<FieldDecl>(BaseOrMember)) {
266
Ptr = Ptr.getBase();
267
Offset += getFieldOffset(FD);
268
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) {
269
IsVirtual = Ptr.isVirtualBaseClass();
270
Ptr = Ptr.getBase();
271
const Record *BaseRecord = Ptr.getRecord();
272
273
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(
274
cast<CXXRecordDecl>(BaseRecord->getDecl()));
275
if (IsVirtual)
276
Offset += Layout.getVBaseClassOffset(RD);
277
else
278
Offset += Layout.getBaseClassOffset(RD);
279
280
} else {
281
Ptr = Ptr.getBase();
282
}
283
Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
284
continue;
285
}
286
llvm_unreachable("Invalid field type");
287
}
288
}
289
290
// We assemble the LValuePath starting from the innermost pointer to the
291
// outermost one. SO in a.b.c, the first element in Path will refer to
292
// the field 'c', while later code expects it to refer to 'a'.
293
// Just invert the order of the elements.
294
std::reverse(Path.begin(), Path.end());
295
296
if (UsePath)
297
return APValue(Base, Offset, Path, OnePastEnd);
298
299
return APValue(Base, Offset, APValue::NoLValuePath());
300
}
301
302
void Pointer::print(llvm::raw_ostream &OS) const {
303
switch (StorageKind) {
304
case Storage::Block: {
305
const Block *B = PointeeStorage.BS.Pointee;
306
OS << "(Block) " << B << " {";
307
308
if (isRoot())
309
OS << "rootptr(" << PointeeStorage.BS.Base << "), ";
310
else
311
OS << PointeeStorage.BS.Base << ", ";
312
313
if (isElementPastEnd())
314
OS << "pastend, ";
315
else
316
OS << Offset << ", ";
317
318
if (B)
319
OS << B->getSize();
320
else
321
OS << "nullptr";
322
OS << "}";
323
} break;
324
case Storage::Int:
325
OS << "(Int) {";
326
OS << PointeeStorage.Int.Value << " + " << Offset << ", "
327
<< PointeeStorage.Int.Desc;
328
OS << "}";
329
break;
330
case Storage::Fn:
331
OS << "(Fn) { " << asFunctionPointer().getFunction() << " + " << Offset
332
<< " }";
333
break;
334
case Storage::Typeid:
335
OS << "(Typeid) { " << (const void *)asTypeidPointer().TypePtr << ", "
336
<< (const void *)asTypeidPointer().TypeInfoType << " + " << Offset
337
<< "}";
338
}
339
}
340
341
size_t Pointer::computeOffsetForComparison() const {
342
if (isIntegralPointer())
343
return asIntPointer().Value + Offset;
344
if (isTypeidPointer())
345
return reinterpret_cast<uintptr_t>(asTypeidPointer().TypePtr) + Offset;
346
347
if (!isBlockPointer())
348
return Offset;
349
350
size_t Result = 0;
351
Pointer P = *this;
352
while (true) {
353
354
if (P.isVirtualBaseClass()) {
355
Result += getInlineDesc()->Offset;
356
P = P.getBase();
357
continue;
358
}
359
360
if (P.isBaseClass()) {
361
if (P.getRecord()->getNumVirtualBases() > 0)
362
Result += P.getInlineDesc()->Offset;
363
P = P.getBase();
364
continue;
365
}
366
if (P.isArrayElement()) {
367
P = P.expand();
368
Result += (P.getIndex() * P.elemSize());
369
P = P.getArray();
370
continue;
371
}
372
373
if (P.isRoot()) {
374
if (P.isOnePastEnd())
375
++Result;
376
break;
377
}
378
379
if (const Record *R = P.getBase().getRecord(); R && R->isUnion()) {
380
// Direct child of a union - all have offset 0.
381
P = P.getBase();
382
continue;
383
}
384
385
// Fields, etc.
386
Result += P.getInlineDesc()->Offset;
387
if (P.isOnePastEnd())
388
++Result;
389
390
P = P.getBase();
391
if (P.isRoot())
392
break;
393
}
394
395
return Result;
396
}
397
398
std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
399
if (isZero())
400
return "nullptr";
401
402
if (isIntegralPointer())
403
return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
404
405
if (isFunctionPointer())
406
return asFunctionPointer().toDiagnosticString(Ctx);
407
408
return toAPValue(Ctx).getAsString(Ctx, getType());
409
}
410
411
bool Pointer::isInitialized() const {
412
if (!isBlockPointer())
413
return true;
414
415
if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
416
const GlobalInlineDescriptor &GD =
417
*reinterpret_cast<const GlobalInlineDescriptor *>(block()->rawData());
418
return GD.InitState == GlobalInitState::Initialized;
419
}
420
421
assert(PointeeStorage.BS.Pointee &&
422
"Cannot check if null pointer was initialized");
423
const Descriptor *Desc = getFieldDesc();
424
assert(Desc);
425
if (Desc->isPrimitiveArray()) {
426
if (isStatic() && PointeeStorage.BS.Base == 0)
427
return true;
428
429
InitMapPtr &IM = getInitMap();
430
431
if (!IM)
432
return false;
433
434
if (IM->first)
435
return true;
436
437
return IM->second->isElementInitialized(getIndex());
438
}
439
440
if (asBlockPointer().Base == 0)
441
return true;
442
443
// Field has its bit in an inline descriptor.
444
return getInlineDesc()->IsInitialized;
445
}
446
447
void Pointer::initialize() const {
448
if (!isBlockPointer())
449
return;
450
451
assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
452
453
if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor)) {
454
GlobalInlineDescriptor &GD = *reinterpret_cast<GlobalInlineDescriptor *>(
455
asBlockPointer().Pointee->rawData());
456
GD.InitState = GlobalInitState::Initialized;
457
return;
458
}
459
460
const Descriptor *Desc = getFieldDesc();
461
assert(Desc);
462
if (Desc->isPrimitiveArray()) {
463
// Primitive global arrays don't have an initmap.
464
if (isStatic() && PointeeStorage.BS.Base == 0)
465
return;
466
467
// Nothing to do for these.
468
if (Desc->getNumElems() == 0)
469
return;
470
471
InitMapPtr &IM = getInitMap();
472
if (!IM)
473
IM =
474
std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
475
476
assert(IM);
477
478
// All initialized.
479
if (IM->first)
480
return;
481
482
if (IM->second->initializeElement(getIndex())) {
483
IM->first = true;
484
IM->second.reset();
485
}
486
return;
487
}
488
489
// Field has its bit in an inline descriptor.
490
assert(PointeeStorage.BS.Base != 0 &&
491
"Only composite fields can be initialised");
492
getInlineDesc()->IsInitialized = true;
493
}
494
495
void Pointer::activate() const {
496
// Field has its bit in an inline descriptor.
497
assert(PointeeStorage.BS.Base != 0 &&
498
"Only composite fields can be activated");
499
500
if (isRoot() && PointeeStorage.BS.Base == sizeof(GlobalInlineDescriptor))
501
return;
502
if (!getInlineDesc()->InUnion)
503
return;
504
505
auto activate = [](Pointer &P) -> void {
506
P.getInlineDesc()->IsActive = true;
507
};
508
509
std::function<void(Pointer &)> deactivate;
510
deactivate = [&deactivate](Pointer &P) -> void {
511
P.getInlineDesc()->IsActive = false;
512
513
if (const Record *R = P.getRecord()) {
514
for (const Record::Field &F : R->fields()) {
515
Pointer FieldPtr = P.atField(F.Offset);
516
if (FieldPtr.getInlineDesc()->IsActive)
517
deactivate(FieldPtr);
518
}
519
// FIXME: Bases?
520
}
521
};
522
523
Pointer B = *this;
524
while (!B.isRoot() && B.inUnion()) {
525
activate(B);
526
527
// When walking up the pointer chain, deactivate
528
// all union child pointers that aren't on our path.
529
Pointer Cur = B;
530
B = B.getBase();
531
if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
532
for (const Record::Field &F : BR->fields()) {
533
Pointer FieldPtr = B.atField(F.Offset);
534
if (FieldPtr != Cur)
535
deactivate(FieldPtr);
536
}
537
}
538
}
539
}
540
541
void Pointer::deactivate() const {
542
// TODO: this only appears in constructors, so nothing to deactivate.
543
}
544
545
bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
546
// Two null pointers always have the same base.
547
if (A.isZero() && B.isZero())
548
return true;
549
550
if (A.isIntegralPointer() && B.isIntegralPointer())
551
return true;
552
if (A.isFunctionPointer() && B.isFunctionPointer())
553
return true;
554
if (A.isTypeidPointer() && B.isTypeidPointer())
555
return true;
556
557
if (A.isIntegralPointer() || B.isIntegralPointer())
558
return A.getSource() == B.getSource();
559
560
if (A.StorageKind != B.StorageKind)
561
return false;
562
563
return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
564
}
565
566
bool Pointer::pointToSameBlock(const Pointer &A, const Pointer &B) {
567
if (!A.isBlockPointer() || !B.isBlockPointer())
568
return false;
569
return A.block() == B.block();
570
}
571
572
bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
573
return hasSameBase(A, B) &&
574
A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
575
A.getFieldDesc()->IsArray;
576
}
577
578
bool Pointer::pointsToLiteral() const {
579
if (isZero() || !isBlockPointer())
580
return false;
581
582
if (block()->isDynamic())
583
return false;
584
585
const Expr *E = block()->getDescriptor()->asExpr();
586
return E && !isa<MaterializeTemporaryExpr, StringLiteral>(E);
587
}
588
589
bool Pointer::pointsToStringLiteral() const {
590
if (isZero() || !isBlockPointer())
591
return false;
592
593
if (block()->isDynamic())
594
return false;
595
596
const Expr *E = block()->getDescriptor()->asExpr();
597
return E && isa<StringLiteral>(E);
598
}
599
600
std::optional<std::pair<Pointer, Pointer>>
601
Pointer::computeSplitPoint(const Pointer &A, const Pointer &B) {
602
if (!A.isBlockPointer() || !B.isBlockPointer())
603
return std::nullopt;
604
605
if (A.asBlockPointer().Pointee != B.asBlockPointer().Pointee)
606
return std::nullopt;
607
if (A.isRoot() && B.isRoot())
608
return std::nullopt;
609
610
if (A == B)
611
return std::make_pair(A, B);
612
613
auto getBase = [](const Pointer &P) -> Pointer {
614
if (P.isArrayElement())
615
return P.expand().getArray();
616
return P.getBase();
617
};
618
619
Pointer IterA = A;
620
Pointer IterB = B;
621
Pointer CurA = IterA;
622
Pointer CurB = IterB;
623
for (;;) {
624
if (IterA.asBlockPointer().Base > IterB.asBlockPointer().Base) {
625
CurA = IterA;
626
IterA = getBase(IterA);
627
} else {
628
CurB = IterB;
629
IterB = getBase(IterB);
630
}
631
632
if (IterA == IterB)
633
return std::make_pair(CurA, CurB);
634
635
if (IterA.isRoot() && IterB.isRoot())
636
return std::nullopt;
637
}
638
639
llvm_unreachable("The loop above should've returned.");
640
}
641
642
std::optional<APValue> Pointer::toRValue(const Context &Ctx,
643
QualType ResultType) const {
644
const ASTContext &ASTCtx = Ctx.getASTContext();
645
assert(!ResultType.isNull());
646
// Method to recursively traverse composites.
647
std::function<bool(QualType, const Pointer &, APValue &)> Composite;
648
Composite = [&Composite, &Ctx, &ASTCtx](QualType Ty, const Pointer &Ptr,
649
APValue &R) {
650
if (const auto *AT = Ty->getAs<AtomicType>())
651
Ty = AT->getValueType();
652
653
// Invalid pointers.
654
if (Ptr.isDummy() || !Ptr.isLive() || !Ptr.isBlockPointer() ||
655
Ptr.isPastEnd())
656
return false;
657
658
// Primitive values.
659
if (std::optional<PrimType> T = Ctx.classify(Ty)) {
660
TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue(ASTCtx));
661
return true;
662
}
663
664
if (const auto *RT = Ty->getAs<RecordType>()) {
665
const auto *Record = Ptr.getRecord();
666
assert(Record && "Missing record descriptor");
667
668
bool Ok = true;
669
if (RT->getDecl()->isUnion()) {
670
const FieldDecl *ActiveField = nullptr;
671
APValue Value;
672
for (const auto &F : Record->fields()) {
673
const Pointer &FP = Ptr.atField(F.Offset);
674
QualType FieldTy = F.Decl->getType();
675
if (FP.isActive()) {
676
if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
677
TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
678
} else {
679
Ok &= Composite(FieldTy, FP, Value);
680
}
681
ActiveField = FP.getFieldDesc()->asFieldDecl();
682
break;
683
}
684
}
685
R = APValue(ActiveField, Value);
686
} else {
687
unsigned NF = Record->getNumFields();
688
unsigned NB = Record->getNumBases();
689
unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
690
691
R = APValue(APValue::UninitStruct(), NB, NF);
692
693
for (unsigned I = 0; I < NF; ++I) {
694
const Record::Field *FD = Record->getField(I);
695
QualType FieldTy = FD->Decl->getType();
696
const Pointer &FP = Ptr.atField(FD->Offset);
697
APValue &Value = R.getStructField(I);
698
699
if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
700
TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue(ASTCtx));
701
} else {
702
Ok &= Composite(FieldTy, FP, Value);
703
}
704
}
705
706
for (unsigned I = 0; I < NB; ++I) {
707
const Record::Base *BD = Record->getBase(I);
708
QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
709
const Pointer &BP = Ptr.atField(BD->Offset);
710
Ok &= Composite(BaseTy, BP, R.getStructBase(I));
711
}
712
713
for (unsigned I = 0; I < NV; ++I) {
714
const Record::Base *VD = Record->getVirtualBase(I);
715
QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
716
const Pointer &VP = Ptr.atField(VD->Offset);
717
Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
718
}
719
}
720
return Ok;
721
}
722
723
if (Ty->isIncompleteArrayType()) {
724
R = APValue(APValue::UninitArray(), 0, 0);
725
return true;
726
}
727
728
if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
729
const size_t NumElems = Ptr.getNumElems();
730
QualType ElemTy = AT->getElementType();
731
R = APValue(APValue::UninitArray{}, NumElems, NumElems);
732
733
bool Ok = true;
734
for (unsigned I = 0; I < NumElems; ++I) {
735
APValue &Slot = R.getArrayInitializedElt(I);
736
const Pointer &EP = Ptr.atIndex(I);
737
if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
738
TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue(ASTCtx));
739
} else {
740
Ok &= Composite(ElemTy, EP.narrow(), Slot);
741
}
742
}
743
return Ok;
744
}
745
746
// Complex types.
747
if (const auto *CT = Ty->getAs<ComplexType>()) {
748
QualType ElemTy = CT->getElementType();
749
750
if (ElemTy->isIntegerType()) {
751
std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
752
assert(ElemT);
753
INT_TYPE_SWITCH(*ElemT, {
754
auto V1 = Ptr.atIndex(0).deref<T>();
755
auto V2 = Ptr.atIndex(1).deref<T>();
756
R = APValue(V1.toAPSInt(), V2.toAPSInt());
757
return true;
758
});
759
} else if (ElemTy->isFloatingType()) {
760
R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
761
Ptr.atIndex(1).deref<Floating>().getAPFloat());
762
return true;
763
}
764
return false;
765
}
766
767
// Vector types.
768
if (const auto *VT = Ty->getAs<VectorType>()) {
769
assert(Ptr.getFieldDesc()->isPrimitiveArray());
770
QualType ElemTy = VT->getElementType();
771
PrimType ElemT = *Ctx.classify(ElemTy);
772
773
SmallVector<APValue> Values;
774
Values.reserve(VT->getNumElements());
775
for (unsigned I = 0; I != VT->getNumElements(); ++I) {
776
TYPE_SWITCH(ElemT, {
777
Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue(ASTCtx));
778
});
779
}
780
781
assert(Values.size() == VT->getNumElements());
782
R = APValue(Values.data(), Values.size());
783
return true;
784
}
785
786
llvm_unreachable("invalid value to return");
787
};
788
789
// Invalid to read from.
790
if (isDummy() || !isLive() || isPastEnd())
791
return std::nullopt;
792
793
// We can return these as rvalues, but we can't deref() them.
794
if (isZero() || isIntegralPointer())
795
return toAPValue(ASTCtx);
796
797
// Just load primitive types.
798
if (std::optional<PrimType> T = Ctx.classify(ResultType)) {
799
TYPE_SWITCH(*T, return this->deref<T>().toAPValue(ASTCtx));
800
}
801
802
// Return the composite type.
803
APValue Result;
804
if (!Composite(ResultType, *this, Result))
805
return std::nullopt;
806
return Result;
807
}
808
809
IntPointer IntPointer::atOffset(const ASTContext &ASTCtx,
810
unsigned Offset) const {
811
if (!this->Desc)
812
return *this;
813
const Record *R = this->Desc->ElemRecord;
814
if (!R)
815
return *this;
816
817
const Record::Field *F = nullptr;
818
for (auto &It : R->fields()) {
819
if (It.Offset == Offset) {
820
F = &It;
821
break;
822
}
823
}
824
if (!F)
825
return *this;
826
827
const FieldDecl *FD = F->Decl;
828
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(FD->getParent());
829
unsigned FieldIndex = FD->getFieldIndex();
830
uint64_t FieldOffset =
831
ASTCtx.toCharUnitsFromBits(Layout.getFieldOffset(FieldIndex))
832
.getQuantity();
833
return IntPointer{F->Desc, this->Value + FieldOffset};
834
}
835
836
IntPointer IntPointer::baseCast(const ASTContext &ASTCtx,
837
unsigned BaseOffset) const {
838
if (!Desc) {
839
assert(Value == 0);
840
return *this;
841
}
842
const Record *R = Desc->ElemRecord;
843
const Descriptor *BaseDesc = nullptr;
844
845
// This iterates over bases and checks for the proper offset. That's
846
// potentially slow but this case really shouldn't happen a lot.
847
for (const Record::Base &B : R->bases()) {
848
if (B.Offset == BaseOffset) {
849
BaseDesc = B.Desc;
850
break;
851
}
852
}
853
assert(BaseDesc);
854
855
// Adjust the offset value based on the information from the record layout.
856
const ASTRecordLayout &Layout = ASTCtx.getASTRecordLayout(R->getDecl());
857
CharUnits BaseLayoutOffset =
858
Layout.getBaseClassOffset(cast<CXXRecordDecl>(BaseDesc->asDecl()));
859
860
return {BaseDesc, Value + BaseLayoutOffset.getQuantity()};
861
}
862
863