xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Pointer.cpp (revision 5b56413d04e608379c9a306373554a8e4d321bc0)
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 
22 Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
23 
24 Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
25     : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
26 
27 Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
28 
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 
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 
42 Pointer::~Pointer() {
43   if (Pointee) {
44     Pointee->removePointer(this);
45     Pointee->cleanup();
46   }
47 }
48 
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 
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 
83 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 
153 std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
154   if (!Pointee)
155     return "nullptr";
156 
157   return toAPValue().getAsString(Ctx, getType());
158 }
159 
160 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 
183 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 
216 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 
222 void Pointer::deactivate() const {
223   // TODO: this only appears in constructors, so nothing to deactivate.
224 }
225 
226 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
227   return A.Pointee == B.Pointee;
228 }
229 
230 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
231   return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
232 }
233 
234 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