xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1a7dea167SDimitry Andric //===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric //
9a7dea167SDimitry Andric // Defines the classes responsible for pointer tracking.
10a7dea167SDimitry Andric //
11a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
12a7dea167SDimitry Andric 
13a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_POINTER_H
14a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_POINTER_H
15a7dea167SDimitry Andric 
16a7dea167SDimitry Andric #include "Descriptor.h"
175ffd83dbSDimitry Andric #include "InterpBlock.h"
185ffd83dbSDimitry Andric #include "clang/AST/ComparisonCategories.h"
19a7dea167SDimitry Andric #include "clang/AST/Decl.h"
20a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h"
21a7dea167SDimitry Andric #include "clang/AST/Expr.h"
22a7dea167SDimitry Andric #include "llvm/ADT/PointerUnion.h"
23a7dea167SDimitry Andric #include "llvm/Support/raw_ostream.h"
24a7dea167SDimitry Andric 
25a7dea167SDimitry Andric namespace clang {
26a7dea167SDimitry Andric namespace interp {
27a7dea167SDimitry Andric class Block;
28a7dea167SDimitry Andric class DeadBlock;
29a7dea167SDimitry Andric class Pointer;
30a7dea167SDimitry Andric enum PrimType : unsigned;
31a7dea167SDimitry Andric 
32a7dea167SDimitry Andric /// A pointer to a memory block, live or dead.
33a7dea167SDimitry Andric ///
34a7dea167SDimitry Andric /// This object can be allocated into interpreter stack frames. If pointing to
35a7dea167SDimitry Andric /// a live block, it is a link in the chain of pointers pointing to the block.
36bdd1243dSDimitry Andric ///
37bdd1243dSDimitry Andric /// In the simplest form, a Pointer has a Block* (the pointee) and both Base
38bdd1243dSDimitry Andric /// and Offset are 0, which means it will point to raw data.
39bdd1243dSDimitry Andric ///
40bdd1243dSDimitry Andric /// The Base field is used to access metadata about the data. For primitive
41bdd1243dSDimitry Andric /// arrays, the Base is followed by an InitMap. In a variety of cases, the
42bdd1243dSDimitry Andric /// Base is preceded by an InlineDescriptor, which is used to track the
43bdd1243dSDimitry Andric /// initialization state, among other things.
44bdd1243dSDimitry Andric ///
45bdd1243dSDimitry Andric /// The Offset field is used to access the actual data. In other words, the
46bdd1243dSDimitry Andric /// data the pointer decribes can be found at
47bdd1243dSDimitry Andric /// Pointee->rawData() + Pointer.Offset.
48bdd1243dSDimitry Andric ///
49bdd1243dSDimitry Andric ///
50bdd1243dSDimitry Andric /// Pointee                      Offset
51bdd1243dSDimitry Andric /// │                              │
52bdd1243dSDimitry Andric /// │                              │
53bdd1243dSDimitry Andric /// ▼                              ▼
54bdd1243dSDimitry Andric /// ┌───────┬────────────┬─────────┬────────────────────────────┐
55bdd1243dSDimitry Andric /// │ Block │ InlineDesc │ InitMap │ Actual Data                │
56bdd1243dSDimitry Andric /// └───────┴────────────┴─────────┴────────────────────────────┘
57bdd1243dSDimitry Andric ///                      ▲
58bdd1243dSDimitry Andric ///                      │
59bdd1243dSDimitry Andric ///                      │
60bdd1243dSDimitry Andric ///                     Base
61a7dea167SDimitry Andric class Pointer {
62a7dea167SDimitry Andric private:
63bdd1243dSDimitry Andric   static constexpr unsigned PastEndMark = ~0u;
64bdd1243dSDimitry Andric   static constexpr unsigned RootPtrMark = ~0u;
65a7dea167SDimitry Andric 
66a7dea167SDimitry Andric public:
67a7dea167SDimitry Andric   Pointer() {}
68a7dea167SDimitry Andric   Pointer(Block *B);
69bdd1243dSDimitry Andric   Pointer(Block *B, unsigned BaseAndOffset);
70a7dea167SDimitry Andric   Pointer(const Pointer &P);
71a7dea167SDimitry Andric   Pointer(Pointer &&P);
72a7dea167SDimitry Andric   ~Pointer();
73a7dea167SDimitry Andric 
74a7dea167SDimitry Andric   void operator=(const Pointer &P);
75a7dea167SDimitry Andric   void operator=(Pointer &&P);
76a7dea167SDimitry Andric 
77a7dea167SDimitry Andric   /// Converts the pointer to an APValue.
78a7dea167SDimitry Andric   APValue toAPValue() const;
79a7dea167SDimitry Andric 
80a7dea167SDimitry Andric   /// Offsets a pointer inside an array.
81a7dea167SDimitry Andric   Pointer atIndex(unsigned Idx) const {
82a7dea167SDimitry Andric     if (Base == RootPtrMark)
83a7dea167SDimitry Andric       return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize());
84a7dea167SDimitry Andric     unsigned Off = Idx * elemSize();
85a7dea167SDimitry Andric     if (getFieldDesc()->ElemDesc)
86a7dea167SDimitry Andric       Off += sizeof(InlineDescriptor);
87a7dea167SDimitry Andric     else
88a7dea167SDimitry Andric       Off += sizeof(InitMap *);
89a7dea167SDimitry Andric     return Pointer(Pointee, Base, Base + Off);
90a7dea167SDimitry Andric   }
91a7dea167SDimitry Andric 
92a7dea167SDimitry Andric   /// Creates a pointer to a field.
93a7dea167SDimitry Andric   Pointer atField(unsigned Off) const {
94a7dea167SDimitry Andric     unsigned Field = Offset + Off;
95a7dea167SDimitry Andric     return Pointer(Pointee, Field, Field);
96a7dea167SDimitry Andric   }
97a7dea167SDimitry Andric 
98a7dea167SDimitry Andric   /// Restricts the scope of an array element pointer.
99a7dea167SDimitry Andric   Pointer narrow() const {
100a7dea167SDimitry Andric     // Null pointers cannot be narrowed.
101a7dea167SDimitry Andric     if (isZero() || isUnknownSizeArray())
102a7dea167SDimitry Andric       return *this;
103a7dea167SDimitry Andric 
104a7dea167SDimitry Andric     // Pointer to an array of base types - enter block.
105a7dea167SDimitry Andric     if (Base == RootPtrMark)
106a7dea167SDimitry Andric       return Pointer(Pointee, 0, Offset == 0 ? Offset : PastEndMark);
107a7dea167SDimitry Andric 
108a7dea167SDimitry Andric     // Pointer is one past end - magic offset marks that.
109a7dea167SDimitry Andric     if (isOnePastEnd())
110a7dea167SDimitry Andric       return Pointer(Pointee, Base, PastEndMark);
111a7dea167SDimitry Andric 
112a7dea167SDimitry Andric     // Primitive arrays are a bit special since they do not have inline
113a7dea167SDimitry Andric     // descriptors. If Offset != Base, then the pointer already points to
114a7dea167SDimitry Andric     // an element and there is nothing to do. Otherwise, the pointer is
115a7dea167SDimitry Andric     // adjusted to the first element of the array.
116a7dea167SDimitry Andric     if (inPrimitiveArray()) {
117a7dea167SDimitry Andric       if (Offset != Base)
118a7dea167SDimitry Andric         return *this;
119a7dea167SDimitry Andric       return Pointer(Pointee, Base, Offset + sizeof(InitMap *));
120a7dea167SDimitry Andric     }
121a7dea167SDimitry Andric 
122a7dea167SDimitry Andric     // Pointer is to a field or array element - enter it.
123a7dea167SDimitry Andric     if (Offset != Base)
124a7dea167SDimitry Andric       return Pointer(Pointee, Offset, Offset);
125a7dea167SDimitry Andric 
126a7dea167SDimitry Andric     // Enter the first element of an array.
127a7dea167SDimitry Andric     if (!getFieldDesc()->isArray())
128a7dea167SDimitry Andric       return *this;
129a7dea167SDimitry Andric 
130a7dea167SDimitry Andric     const unsigned NewBase = Base + sizeof(InlineDescriptor);
131a7dea167SDimitry Andric     return Pointer(Pointee, NewBase, NewBase);
132a7dea167SDimitry Andric   }
133a7dea167SDimitry Andric 
134a7dea167SDimitry Andric   /// Expands a pointer to the containing array, undoing narrowing.
135a7dea167SDimitry Andric   Pointer expand() const {
136a7dea167SDimitry Andric     if (isElementPastEnd()) {
137a7dea167SDimitry Andric       // Revert to an outer one-past-end pointer.
138a7dea167SDimitry Andric       unsigned Adjust;
139a7dea167SDimitry Andric       if (inPrimitiveArray())
140a7dea167SDimitry Andric         Adjust = sizeof(InitMap *);
141a7dea167SDimitry Andric       else
142a7dea167SDimitry Andric         Adjust = sizeof(InlineDescriptor);
143a7dea167SDimitry Andric       return Pointer(Pointee, Base, Base + getSize() + Adjust);
144a7dea167SDimitry Andric     }
145a7dea167SDimitry Andric 
146a7dea167SDimitry Andric     // Do not step out of array elements.
147a7dea167SDimitry Andric     if (Base != Offset)
148a7dea167SDimitry Andric       return *this;
149a7dea167SDimitry Andric 
150a7dea167SDimitry Andric     // If at base, point to an array of base types.
151a7dea167SDimitry Andric     if (Base == 0)
152a7dea167SDimitry Andric       return Pointer(Pointee, RootPtrMark, 0);
153a7dea167SDimitry Andric 
154a7dea167SDimitry Andric     // Step into the containing array, if inside one.
155a7dea167SDimitry Andric     unsigned Next = Base - getInlineDesc()->Offset;
156a7dea167SDimitry Andric     Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc;
157a7dea167SDimitry Andric     if (!Desc->IsArray)
158a7dea167SDimitry Andric       return *this;
159a7dea167SDimitry Andric     return Pointer(Pointee, Next, Offset);
160a7dea167SDimitry Andric   }
161a7dea167SDimitry Andric 
162a7dea167SDimitry Andric   /// Checks if the pointer is null.
163a7dea167SDimitry Andric   bool isZero() const { return Pointee == nullptr; }
164a7dea167SDimitry Andric   /// Checks if the pointer is live.
165a7dea167SDimitry Andric   bool isLive() const { return Pointee && !Pointee->IsDead; }
166a7dea167SDimitry Andric   /// Checks if the item is a field in an object.
167a7dea167SDimitry Andric   bool isField() const { return Base != 0 && Base != RootPtrMark; }
168a7dea167SDimitry Andric 
169a7dea167SDimitry Andric   /// Accessor for information about the declaration site.
170a7dea167SDimitry Andric   Descriptor *getDeclDesc() const { return Pointee->Desc; }
171a7dea167SDimitry Andric   SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
172a7dea167SDimitry Andric 
173a7dea167SDimitry Andric   /// Returns a pointer to the object of which this pointer is a field.
174a7dea167SDimitry Andric   Pointer getBase() const {
175a7dea167SDimitry Andric     if (Base == RootPtrMark) {
176a7dea167SDimitry Andric       assert(Offset == PastEndMark && "cannot get base of a block");
177a7dea167SDimitry Andric       return Pointer(Pointee, Base, 0);
178a7dea167SDimitry Andric     }
179a7dea167SDimitry Andric     assert(Offset == Base && "not an inner field");
180a7dea167SDimitry Andric     unsigned NewBase = Base - getInlineDesc()->Offset;
181a7dea167SDimitry Andric     return Pointer(Pointee, NewBase, NewBase);
182a7dea167SDimitry Andric   }
183a7dea167SDimitry Andric   /// Returns the parent array.
184a7dea167SDimitry Andric   Pointer getArray() const {
185a7dea167SDimitry Andric     if (Base == RootPtrMark) {
186a7dea167SDimitry Andric       assert(Offset != 0 && Offset != PastEndMark && "not an array element");
187a7dea167SDimitry Andric       return Pointer(Pointee, Base, 0);
188a7dea167SDimitry Andric     }
189a7dea167SDimitry Andric     assert(Offset != Base && "not an array element");
190a7dea167SDimitry Andric     return Pointer(Pointee, Base, Base);
191a7dea167SDimitry Andric   }
192a7dea167SDimitry Andric 
193a7dea167SDimitry Andric   /// Accessors for information about the innermost field.
194a7dea167SDimitry Andric   Descriptor *getFieldDesc() const {
195a7dea167SDimitry Andric     if (Base == 0 || Base == RootPtrMark)
196a7dea167SDimitry Andric       return getDeclDesc();
197a7dea167SDimitry Andric     return getInlineDesc()->Desc;
198a7dea167SDimitry Andric   }
199a7dea167SDimitry Andric 
200a7dea167SDimitry Andric   /// Returns the type of the innermost field.
201a7dea167SDimitry Andric   QualType getType() const { return getFieldDesc()->getType(); }
202a7dea167SDimitry Andric 
203*06c3fb27SDimitry Andric   Pointer getDeclPtr() const { return Pointer(Pointee); }
204*06c3fb27SDimitry Andric 
205a7dea167SDimitry Andric   /// Returns the element size of the innermost field.
206a7dea167SDimitry Andric   size_t elemSize() const {
207a7dea167SDimitry Andric     if (Base == RootPtrMark)
208a7dea167SDimitry Andric       return getDeclDesc()->getSize();
209a7dea167SDimitry Andric     return getFieldDesc()->getElemSize();
210a7dea167SDimitry Andric   }
211a7dea167SDimitry Andric   /// Returns the total size of the innermost field.
212a7dea167SDimitry Andric   size_t getSize() const { return getFieldDesc()->getSize(); }
213a7dea167SDimitry Andric 
214a7dea167SDimitry Andric   /// Returns the offset into an array.
215a7dea167SDimitry Andric   unsigned getOffset() const {
216a7dea167SDimitry Andric     assert(Offset != PastEndMark && "invalid offset");
217a7dea167SDimitry Andric     if (Base == RootPtrMark)
218a7dea167SDimitry Andric       return Offset;
219a7dea167SDimitry Andric 
220a7dea167SDimitry Andric     unsigned Adjust = 0;
221a7dea167SDimitry Andric     if (Offset != Base) {
222a7dea167SDimitry Andric       if (getFieldDesc()->ElemDesc)
223a7dea167SDimitry Andric         Adjust = sizeof(InlineDescriptor);
224a7dea167SDimitry Andric       else
225a7dea167SDimitry Andric         Adjust = sizeof(InitMap *);
226a7dea167SDimitry Andric     }
227a7dea167SDimitry Andric     return Offset - Base - Adjust;
228a7dea167SDimitry Andric   }
229a7dea167SDimitry Andric 
230*06c3fb27SDimitry Andric   /// Whether this array refers to an array, but not
231*06c3fb27SDimitry Andric   /// to the first element.
232*06c3fb27SDimitry Andric   bool isArrayRoot() const { return inArray() && Offset == Base; }
233*06c3fb27SDimitry Andric 
234a7dea167SDimitry Andric   /// Checks if the innermost field is an array.
235a7dea167SDimitry Andric   bool inArray() const { return getFieldDesc()->IsArray; }
236a7dea167SDimitry Andric   /// Checks if the structure is a primitive array.
237a7dea167SDimitry Andric   bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
238a7dea167SDimitry Andric   /// Checks if the structure is an array of unknown size.
239a7dea167SDimitry Andric   bool isUnknownSizeArray() const {
240a7dea167SDimitry Andric     return getFieldDesc()->isUnknownSizeArray();
241a7dea167SDimitry Andric   }
242a7dea167SDimitry Andric   /// Checks if the pointer points to an array.
243a7dea167SDimitry Andric   bool isArrayElement() const { return Base != Offset; }
244a7dea167SDimitry Andric   /// Pointer points directly to a block.
245a7dea167SDimitry Andric   bool isRoot() const {
246a7dea167SDimitry Andric     return (Base == 0 || Base == RootPtrMark) && Offset == 0;
247a7dea167SDimitry Andric   }
248a7dea167SDimitry Andric 
249a7dea167SDimitry Andric   /// Returns the record descriptor of a class.
250*06c3fb27SDimitry Andric   const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
251*06c3fb27SDimitry Andric   /// Returns the element record type, if this is a non-primive array.
252*06c3fb27SDimitry Andric   const Record *getElemRecord() const {
253*06c3fb27SDimitry Andric     return getFieldDesc()->ElemDesc->ElemRecord;
254*06c3fb27SDimitry Andric   }
255a7dea167SDimitry Andric   /// Returns the field information.
256a7dea167SDimitry Andric   const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
257a7dea167SDimitry Andric 
258a7dea167SDimitry Andric   /// Checks if the object is a union.
259a7dea167SDimitry Andric   bool isUnion() const;
260a7dea167SDimitry Andric 
261a7dea167SDimitry Andric   /// Checks if the storage is extern.
262a7dea167SDimitry Andric   bool isExtern() const { return Pointee->isExtern(); }
263a7dea167SDimitry Andric   /// Checks if the storage is static.
264a7dea167SDimitry Andric   bool isStatic() const { return Pointee->isStatic(); }
265a7dea167SDimitry Andric   /// Checks if the storage is temporary.
266a7dea167SDimitry Andric   bool isTemporary() const { return Pointee->isTemporary(); }
267a7dea167SDimitry Andric   /// Checks if the storage is a static temporary.
268a7dea167SDimitry Andric   bool isStaticTemporary() const { return isStatic() && isTemporary(); }
269a7dea167SDimitry Andric 
270a7dea167SDimitry Andric   /// Checks if the field is mutable.
271bdd1243dSDimitry Andric   bool isMutable() const {
272bdd1243dSDimitry Andric     return Base != 0 && getInlineDesc()->IsFieldMutable;
273bdd1243dSDimitry Andric   }
274a7dea167SDimitry Andric   /// Checks if an object was initialized.
275a7dea167SDimitry Andric   bool isInitialized() const;
276a7dea167SDimitry Andric   /// Checks if the object is active.
277a7dea167SDimitry Andric   bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; }
278a7dea167SDimitry Andric   /// Checks if a structure is a base class.
279a7dea167SDimitry Andric   bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
280a7dea167SDimitry Andric 
281a7dea167SDimitry Andric   /// Checks if an object or a subfield is mutable.
282a7dea167SDimitry Andric   bool isConst() const {
283a7dea167SDimitry Andric     return Base == 0 ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;
284a7dea167SDimitry Andric   }
285a7dea167SDimitry Andric 
286a7dea167SDimitry Andric   /// Returns the declaration ID.
287bdd1243dSDimitry Andric   std::optional<unsigned> getDeclID() const { return Pointee->getDeclID(); }
288a7dea167SDimitry Andric 
289a7dea167SDimitry Andric   /// Returns the byte offset from the start.
290a7dea167SDimitry Andric   unsigned getByteOffset() const {
291a7dea167SDimitry Andric     return Offset;
292a7dea167SDimitry Andric   }
293a7dea167SDimitry Andric 
294a7dea167SDimitry Andric   /// Returns the number of elements.
295a7dea167SDimitry Andric   unsigned getNumElems() const { return getSize() / elemSize(); }
296a7dea167SDimitry Andric 
297*06c3fb27SDimitry Andric   const Block *block() const { return Pointee; }
298*06c3fb27SDimitry Andric 
299a7dea167SDimitry Andric   /// Returns the index into an array.
300a7dea167SDimitry Andric   int64_t getIndex() const {
301a7dea167SDimitry Andric     if (isElementPastEnd())
302a7dea167SDimitry Andric       return 1;
303a7dea167SDimitry Andric     if (auto ElemSize = elemSize())
304a7dea167SDimitry Andric       return getOffset() / ElemSize;
305a7dea167SDimitry Andric     return 0;
306a7dea167SDimitry Andric   }
307a7dea167SDimitry Andric 
308a7dea167SDimitry Andric   /// Checks if the index is one past end.
309a7dea167SDimitry Andric   bool isOnePastEnd() const {
310a7dea167SDimitry Andric     return isElementPastEnd() || getSize() == getOffset();
311a7dea167SDimitry Andric   }
312a7dea167SDimitry Andric 
313a7dea167SDimitry Andric   /// Checks if the pointer is an out-of-bounds element pointer.
314a7dea167SDimitry Andric   bool isElementPastEnd() const { return Offset == PastEndMark; }
315a7dea167SDimitry Andric 
316a7dea167SDimitry Andric   /// Dereferences the pointer, if it's live.
317a7dea167SDimitry Andric   template <typename T> T &deref() const {
318a7dea167SDimitry Andric     assert(isLive() && "Invalid pointer");
319*06c3fb27SDimitry Andric     if (isArrayRoot())
320*06c3fb27SDimitry Andric       return *reinterpret_cast<T *>(Pointee->rawData() + Base +
321*06c3fb27SDimitry Andric                                     sizeof(InitMap *));
322*06c3fb27SDimitry Andric 
323bdd1243dSDimitry Andric     return *reinterpret_cast<T *>(Pointee->rawData() + Offset);
324a7dea167SDimitry Andric   }
325a7dea167SDimitry Andric 
326a7dea167SDimitry Andric   /// Dereferences a primitive element.
327a7dea167SDimitry Andric   template <typename T> T &elem(unsigned I) const {
328*06c3fb27SDimitry Andric     assert(I < getNumElems());
329*06c3fb27SDimitry Andric     return reinterpret_cast<T *>(Pointee->data() + sizeof(InitMap *))[I];
330a7dea167SDimitry Andric   }
331a7dea167SDimitry Andric 
332a7dea167SDimitry Andric   /// Initializes a field.
333a7dea167SDimitry Andric   void initialize() const;
334a7dea167SDimitry Andric   /// Activats a field.
335a7dea167SDimitry Andric   void activate() const;
336a7dea167SDimitry Andric   /// Deactivates an entire strurcutre.
337a7dea167SDimitry Andric   void deactivate() const;
338a7dea167SDimitry Andric 
339a7dea167SDimitry Andric   /// Checks if two pointers are comparable.
340a7dea167SDimitry Andric   static bool hasSameBase(const Pointer &A, const Pointer &B);
341a7dea167SDimitry Andric   /// Checks if two pointers can be subtracted.
342a7dea167SDimitry Andric   static bool hasSameArray(const Pointer &A, const Pointer &B);
343a7dea167SDimitry Andric 
344a7dea167SDimitry Andric   /// Prints the pointer.
345a7dea167SDimitry Andric   void print(llvm::raw_ostream &OS) const {
346bdd1243dSDimitry Andric     OS << Pointee << " {" << Base << ", " << Offset << ", ";
347a7dea167SDimitry Andric     if (Pointee)
348a7dea167SDimitry Andric       OS << Pointee->getSize();
349a7dea167SDimitry Andric     else
350a7dea167SDimitry Andric       OS << "nullptr";
351a7dea167SDimitry Andric     OS << "}";
352a7dea167SDimitry Andric   }
353a7dea167SDimitry Andric 
354a7dea167SDimitry Andric private:
355a7dea167SDimitry Andric   friend class Block;
356a7dea167SDimitry Andric   friend class DeadBlock;
357a7dea167SDimitry Andric 
358a7dea167SDimitry Andric   Pointer(Block *Pointee, unsigned Base, unsigned Offset);
359a7dea167SDimitry Andric 
360a7dea167SDimitry Andric   /// Returns the embedded descriptor preceding a field.
361a7dea167SDimitry Andric   InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); }
362a7dea167SDimitry Andric 
363a7dea167SDimitry Andric   /// Returns a descriptor at a given offset.
364a7dea167SDimitry Andric   InlineDescriptor *getDescriptor(unsigned Offset) const {
365a7dea167SDimitry Andric     assert(Offset != 0 && "Not a nested pointer");
366bdd1243dSDimitry Andric     return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) -
367bdd1243dSDimitry Andric            1;
368a7dea167SDimitry Andric   }
369a7dea167SDimitry Andric 
370a7dea167SDimitry Andric   /// Returns a reference to the pointer which stores the initialization map.
371a7dea167SDimitry Andric   InitMap *&getInitMap() const {
372bdd1243dSDimitry Andric     return *reinterpret_cast<InitMap **>(Pointee->rawData() + Base);
373a7dea167SDimitry Andric   }
374a7dea167SDimitry Andric 
375a7dea167SDimitry Andric   /// The block the pointer is pointing to.
376a7dea167SDimitry Andric   Block *Pointee = nullptr;
377a7dea167SDimitry Andric   /// Start of the current subfield.
378a7dea167SDimitry Andric   unsigned Base = 0;
379a7dea167SDimitry Andric   /// Offset into the block.
380a7dea167SDimitry Andric   unsigned Offset = 0;
381a7dea167SDimitry Andric 
382a7dea167SDimitry Andric   /// Previous link in the pointer chain.
383a7dea167SDimitry Andric   Pointer *Prev = nullptr;
384a7dea167SDimitry Andric   /// Next link in the pointer chain.
385a7dea167SDimitry Andric   Pointer *Next = nullptr;
386a7dea167SDimitry Andric };
387a7dea167SDimitry Andric 
388a7dea167SDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
389a7dea167SDimitry Andric   P.print(OS);
390a7dea167SDimitry Andric   return OS;
391a7dea167SDimitry Andric }
392a7dea167SDimitry Andric 
393a7dea167SDimitry Andric } // namespace interp
394a7dea167SDimitry Andric } // namespace clang
395a7dea167SDimitry Andric 
396a7dea167SDimitry Andric #endif
397