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 "PrimType.h"
17 #include "Record.h"
18
19 using namespace clang;
20 using namespace clang::interp;
21
Pointer(Block * Pointee)22 Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
23
Pointer(Block * Pointee,unsigned BaseAndOffset)24 Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
25 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
26
Pointer(const Pointer & P)27 Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
28
Pointer(Pointer && P)29 Pointer::Pointer(Pointer &&P)
30 : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
31 if (Pointee)
32 Pointee->replacePointer(&P, this);
33 }
34
Pointer(Block * Pointee,unsigned Base,unsigned Offset)35 Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
36 : Pointee(Pointee), Base(Base), Offset(Offset) {
37 assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
38 if (Pointee)
39 Pointee->addPointer(this);
40 }
41
~Pointer()42 Pointer::~Pointer() {
43 if (Pointee) {
44 Pointee->removePointer(this);
45 Pointee->cleanup();
46 }
47 }
48
operator =(const Pointer & P)49 void Pointer::operator=(const Pointer &P) {
50 Block *Old = Pointee;
51
52 if (Pointee)
53 Pointee->removePointer(this);
54
55 Offset = P.Offset;
56 Base = P.Base;
57
58 Pointee = P.Pointee;
59 if (Pointee)
60 Pointee->addPointer(this);
61
62 if (Old)
63 Old->cleanup();
64 }
65
operator =(Pointer && P)66 void Pointer::operator=(Pointer &&P) {
67 Block *Old = Pointee;
68
69 if (Pointee)
70 Pointee->removePointer(this);
71
72 Offset = P.Offset;
73 Base = P.Base;
74
75 Pointee = P.Pointee;
76 if (Pointee)
77 Pointee->replacePointer(&P, this);
78
79 if (Old)
80 Old->cleanup();
81 }
82
toAPValue() const83 APValue Pointer::toAPValue() const {
84 APValue::LValueBase Base;
85 llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
86 CharUnits Offset;
87 bool IsNullPtr;
88 bool IsOnePastEnd;
89
90 if (isZero()) {
91 Base = static_cast<const Expr *>(nullptr);
92 IsNullPtr = true;
93 IsOnePastEnd = false;
94 Offset = CharUnits::Zero();
95 } else {
96 // Build the lvalue base from the block.
97 const Descriptor *Desc = getDeclDesc();
98 if (auto *VD = Desc->asValueDecl())
99 Base = VD;
100 else if (auto *E = Desc->asExpr())
101 Base = E;
102 else
103 llvm_unreachable("Invalid allocation type");
104
105 // Not a null pointer.
106 IsNullPtr = false;
107
108 if (isUnknownSizeArray()) {
109 IsOnePastEnd = false;
110 Offset = CharUnits::Zero();
111 } else if (Desc->asExpr()) {
112 // Pointer pointing to a an expression.
113 IsOnePastEnd = false;
114 Offset = CharUnits::Zero();
115 } else {
116 // TODO: compute the offset into the object.
117 Offset = CharUnits::Zero();
118
119 // Build the path into the object.
120 Pointer Ptr = *this;
121 while (Ptr.isField() || Ptr.isArrayElement()) {
122 if (Ptr.isArrayElement()) {
123 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
124 Ptr = Ptr.getArray();
125 } else {
126 // TODO: figure out if base is virtual
127 bool IsVirtual = false;
128
129 // Create a path entry for the field.
130 const Descriptor *Desc = Ptr.getFieldDesc();
131 if (const auto *BaseOrMember = Desc->asDecl()) {
132 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
133 Ptr = Ptr.getBase();
134 continue;
135 }
136 llvm_unreachable("Invalid field type");
137 }
138 }
139
140 IsOnePastEnd = isOnePastEnd();
141 }
142 }
143
144 // We assemble the LValuePath starting from the innermost pointer to the
145 // outermost one. SO in a.b.c, the first element in Path will refer to
146 // the field 'c', while later code expects it to refer to 'a'.
147 // Just invert the order of the elements.
148 std::reverse(Path.begin(), Path.end());
149
150 return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
151 }
152
toDiagnosticString(const ASTContext & Ctx) const153 std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
154 if (!Pointee)
155 return "nullptr";
156
157 return toAPValue().getAsString(Ctx, getType());
158 }
159
isInitialized() const160 bool Pointer::isInitialized() const {
161 assert(Pointee && "Cannot check if null pointer was initialized");
162 const Descriptor *Desc = getFieldDesc();
163 assert(Desc);
164 if (Desc->isPrimitiveArray()) {
165 if (isStatic() && Base == 0)
166 return true;
167
168 InitMapPtr &IM = getInitMap();
169
170 if (!IM)
171 return false;
172
173 if (IM->first)
174 return true;
175
176 return IM->second->isElementInitialized(getIndex());
177 }
178
179 // Field has its bit in an inline descriptor.
180 return Base == 0 || getInlineDesc()->IsInitialized;
181 }
182
initialize() const183 void Pointer::initialize() const {
184 assert(Pointee && "Cannot initialize null pointer");
185 const Descriptor *Desc = getFieldDesc();
186
187 assert(Desc);
188 if (Desc->isPrimitiveArray()) {
189 // Primitive global arrays don't have an initmap.
190 if (isStatic() && Base == 0)
191 return;
192
193 InitMapPtr &IM = getInitMap();
194 if (!IM)
195 IM =
196 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
197
198 assert(IM);
199
200 // All initialized.
201 if (IM->first)
202 return;
203
204 if (IM->second->initializeElement(getIndex())) {
205 IM->first = true;
206 IM->second.reset();
207 }
208 return;
209 }
210
211 // Field has its bit in an inline descriptor.
212 assert(Base != 0 && "Only composite fields can be initialised");
213 getInlineDesc()->IsInitialized = true;
214 }
215
activate() const216 void Pointer::activate() const {
217 // Field has its bit in an inline descriptor.
218 assert(Base != 0 && "Only composite fields can be initialised");
219 getInlineDesc()->IsActive = true;
220 }
221
deactivate() const222 void Pointer::deactivate() const {
223 // TODO: this only appears in constructors, so nothing to deactivate.
224 }
225
hasSameBase(const Pointer & A,const Pointer & B)226 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
227 return A.Pointee == B.Pointee;
228 }
229
hasSameArray(const Pointer & A,const Pointer & B)230 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
231 return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
232 }
233
toRValue(const Context & Ctx) const234 std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
235 // Method to recursively traverse composites.
236 std::function<bool(QualType, const Pointer &, APValue &)> Composite;
237 Composite = [&Composite, &Ctx](QualType Ty, const Pointer &Ptr, APValue &R) {
238 if (const auto *AT = Ty->getAs<AtomicType>())
239 Ty = AT->getValueType();
240
241 // Invalid pointers.
242 if (Ptr.isDummy() || !Ptr.isLive() ||
243 (!Ptr.isUnknownSizeArray() && Ptr.isOnePastEnd()))
244 return false;
245
246 // Primitive values.
247 if (std::optional<PrimType> T = Ctx.classify(Ty)) {
248 if (T == PT_Ptr || T == PT_FnPtr) {
249 R = Ptr.toAPValue();
250 } else {
251 TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue());
252 }
253 return true;
254 }
255
256 if (const auto *RT = Ty->getAs<RecordType>()) {
257 const auto *Record = Ptr.getRecord();
258 assert(Record && "Missing record descriptor");
259
260 bool Ok = true;
261 if (RT->getDecl()->isUnion()) {
262 const FieldDecl *ActiveField = nullptr;
263 APValue Value;
264 for (const auto &F : Record->fields()) {
265 const Pointer &FP = Ptr.atField(F.Offset);
266 QualType FieldTy = F.Decl->getType();
267 if (FP.isActive()) {
268 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
269 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue());
270 } else {
271 Ok &= Composite(FieldTy, FP, Value);
272 }
273 break;
274 }
275 }
276 R = APValue(ActiveField, Value);
277 } else {
278 unsigned NF = Record->getNumFields();
279 unsigned NB = Record->getNumBases();
280 unsigned NV = Ptr.isBaseClass() ? 0 : Record->getNumVirtualBases();
281
282 R = APValue(APValue::UninitStruct(), NB, NF);
283
284 for (unsigned I = 0; I < NF; ++I) {
285 const Record::Field *FD = Record->getField(I);
286 QualType FieldTy = FD->Decl->getType();
287 const Pointer &FP = Ptr.atField(FD->Offset);
288 APValue &Value = R.getStructField(I);
289
290 if (std::optional<PrimType> T = Ctx.classify(FieldTy)) {
291 TYPE_SWITCH(*T, Value = FP.deref<T>().toAPValue());
292 } else {
293 Ok &= Composite(FieldTy, FP, Value);
294 }
295 }
296
297 for (unsigned I = 0; I < NB; ++I) {
298 const Record::Base *BD = Record->getBase(I);
299 QualType BaseTy = Ctx.getASTContext().getRecordType(BD->Decl);
300 const Pointer &BP = Ptr.atField(BD->Offset);
301 Ok &= Composite(BaseTy, BP, R.getStructBase(I));
302 }
303
304 for (unsigned I = 0; I < NV; ++I) {
305 const Record::Base *VD = Record->getVirtualBase(I);
306 QualType VirtBaseTy = Ctx.getASTContext().getRecordType(VD->Decl);
307 const Pointer &VP = Ptr.atField(VD->Offset);
308 Ok &= Composite(VirtBaseTy, VP, R.getStructBase(NB + I));
309 }
310 }
311 return Ok;
312 }
313
314 if (Ty->isIncompleteArrayType()) {
315 R = APValue(APValue::UninitArray(), 0, 0);
316 return true;
317 }
318
319 if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
320 const size_t NumElems = Ptr.getNumElems();
321 QualType ElemTy = AT->getElementType();
322 R = APValue(APValue::UninitArray{}, NumElems, NumElems);
323
324 bool Ok = true;
325 for (unsigned I = 0; I < NumElems; ++I) {
326 APValue &Slot = R.getArrayInitializedElt(I);
327 const Pointer &EP = Ptr.atIndex(I);
328 if (std::optional<PrimType> T = Ctx.classify(ElemTy)) {
329 TYPE_SWITCH(*T, Slot = EP.deref<T>().toAPValue());
330 } else {
331 Ok &= Composite(ElemTy, EP.narrow(), Slot);
332 }
333 }
334 return Ok;
335 }
336
337 // Complex types.
338 if (const auto *CT = Ty->getAs<ComplexType>()) {
339 QualType ElemTy = CT->getElementType();
340 std::optional<PrimType> ElemT = Ctx.classify(ElemTy);
341 assert(ElemT);
342
343 if (ElemTy->isIntegerType()) {
344 INT_TYPE_SWITCH(*ElemT, {
345 auto V1 = Ptr.atIndex(0).deref<T>();
346 auto V2 = Ptr.atIndex(1).deref<T>();
347 R = APValue(V1.toAPSInt(), V2.toAPSInt());
348 return true;
349 });
350 } else if (ElemTy->isFloatingType()) {
351 R = APValue(Ptr.atIndex(0).deref<Floating>().getAPFloat(),
352 Ptr.atIndex(1).deref<Floating>().getAPFloat());
353 return true;
354 }
355 return false;
356 }
357
358 llvm_unreachable("invalid value to return");
359 };
360
361 if (isZero())
362 return APValue(static_cast<Expr *>(nullptr), CharUnits::Zero(), {}, false,
363 true);
364
365 if (isDummy() || !isLive())
366 return std::nullopt;
367
368 // Return the composite type.
369 APValue Result;
370 if (!Composite(getType(), *this, Result))
371 return std::nullopt;
372 return Result;
373 }
374