xref: /freebsd/contrib/llvm-project/clang/lib/AST/Interp/Pointer.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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;
30*5f757f3fSDimitry Andric class Context;
31a7dea167SDimitry Andric enum PrimType : unsigned;
32a7dea167SDimitry Andric 
33*5f757f3fSDimitry Andric class Pointer;
34*5f757f3fSDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);
35*5f757f3fSDimitry Andric 
36a7dea167SDimitry Andric /// A pointer to a memory block, live or dead.
37a7dea167SDimitry Andric ///
38a7dea167SDimitry Andric /// This object can be allocated into interpreter stack frames. If pointing to
39a7dea167SDimitry Andric /// a live block, it is a link in the chain of pointers pointing to the block.
40bdd1243dSDimitry Andric ///
41bdd1243dSDimitry Andric /// In the simplest form, a Pointer has a Block* (the pointee) and both Base
42bdd1243dSDimitry Andric /// and Offset are 0, which means it will point to raw data.
43bdd1243dSDimitry Andric ///
44bdd1243dSDimitry Andric /// The Base field is used to access metadata about the data. For primitive
45bdd1243dSDimitry Andric /// arrays, the Base is followed by an InitMap. In a variety of cases, the
46bdd1243dSDimitry Andric /// Base is preceded by an InlineDescriptor, which is used to track the
47bdd1243dSDimitry Andric /// initialization state, among other things.
48bdd1243dSDimitry Andric ///
49bdd1243dSDimitry Andric /// The Offset field is used to access the actual data. In other words, the
50bdd1243dSDimitry Andric /// data the pointer decribes can be found at
51bdd1243dSDimitry Andric /// Pointee->rawData() + Pointer.Offset.
52bdd1243dSDimitry Andric ///
53bdd1243dSDimitry Andric ///
54bdd1243dSDimitry Andric /// Pointee                      Offset
55bdd1243dSDimitry Andric /// │                              │
56bdd1243dSDimitry Andric /// │                              │
57bdd1243dSDimitry Andric /// ▼                              ▼
58bdd1243dSDimitry Andric /// ┌───────┬────────────┬─────────┬────────────────────────────┐
59bdd1243dSDimitry Andric /// │ Block │ InlineDesc │ InitMap │ Actual Data                │
60bdd1243dSDimitry Andric /// └───────┴────────────┴─────────┴────────────────────────────┘
61bdd1243dSDimitry Andric ///                      ▲
62bdd1243dSDimitry Andric ///                      │
63bdd1243dSDimitry Andric ///                      │
64bdd1243dSDimitry Andric ///                     Base
65a7dea167SDimitry Andric class Pointer {
66a7dea167SDimitry Andric private:
67bdd1243dSDimitry Andric   static constexpr unsigned PastEndMark = ~0u;
68bdd1243dSDimitry Andric   static constexpr unsigned RootPtrMark = ~0u;
69a7dea167SDimitry Andric 
70a7dea167SDimitry Andric public:
71a7dea167SDimitry Andric   Pointer() {}
72a7dea167SDimitry Andric   Pointer(Block *B);
73bdd1243dSDimitry Andric   Pointer(Block *B, unsigned BaseAndOffset);
74a7dea167SDimitry Andric   Pointer(const Pointer &P);
75a7dea167SDimitry Andric   Pointer(Pointer &&P);
76a7dea167SDimitry Andric   ~Pointer();
77a7dea167SDimitry Andric 
78a7dea167SDimitry Andric   void operator=(const Pointer &P);
79a7dea167SDimitry Andric   void operator=(Pointer &&P);
80a7dea167SDimitry Andric 
81*5f757f3fSDimitry Andric   /// Equality operators are just for tests.
82*5f757f3fSDimitry Andric   bool operator==(const Pointer &P) const {
83*5f757f3fSDimitry Andric     return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
84*5f757f3fSDimitry Andric   }
85*5f757f3fSDimitry Andric 
86*5f757f3fSDimitry Andric   bool operator!=(const Pointer &P) const {
87*5f757f3fSDimitry Andric     return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;
88*5f757f3fSDimitry Andric   }
89*5f757f3fSDimitry Andric 
90a7dea167SDimitry Andric   /// Converts the pointer to an APValue.
91a7dea167SDimitry Andric   APValue toAPValue() const;
92a7dea167SDimitry Andric 
93*5f757f3fSDimitry Andric   /// Converts the pointer to a string usable in diagnostics.
94*5f757f3fSDimitry Andric   std::string toDiagnosticString(const ASTContext &Ctx) const;
95*5f757f3fSDimitry Andric 
96*5f757f3fSDimitry Andric   unsigned getIntegerRepresentation() const {
97*5f757f3fSDimitry Andric     return reinterpret_cast<uintptr_t>(Pointee) + Offset;
98*5f757f3fSDimitry Andric   }
99*5f757f3fSDimitry Andric 
100*5f757f3fSDimitry Andric   /// Converts the pointer to an APValue that is an rvalue.
101*5f757f3fSDimitry Andric   APValue toRValue(const Context &Ctx) const;
102*5f757f3fSDimitry Andric 
103a7dea167SDimitry Andric   /// Offsets a pointer inside an array.
104*5f757f3fSDimitry Andric   [[nodiscard]] Pointer atIndex(unsigned Idx) const {
105a7dea167SDimitry Andric     if (Base == RootPtrMark)
106a7dea167SDimitry Andric       return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize());
107a7dea167SDimitry Andric     unsigned Off = Idx * elemSize();
108a7dea167SDimitry Andric     if (getFieldDesc()->ElemDesc)
109a7dea167SDimitry Andric       Off += sizeof(InlineDescriptor);
110a7dea167SDimitry Andric     else
111*5f757f3fSDimitry Andric       Off += sizeof(InitMapPtr);
112a7dea167SDimitry Andric     return Pointer(Pointee, Base, Base + Off);
113a7dea167SDimitry Andric   }
114a7dea167SDimitry Andric 
115a7dea167SDimitry Andric   /// Creates a pointer to a field.
116*5f757f3fSDimitry Andric   [[nodiscard]] Pointer atField(unsigned Off) const {
117a7dea167SDimitry Andric     unsigned Field = Offset + Off;
118a7dea167SDimitry Andric     return Pointer(Pointee, Field, Field);
119a7dea167SDimitry Andric   }
120a7dea167SDimitry Andric 
121*5f757f3fSDimitry Andric   /// Subtract the given offset from the current Base and Offset
122*5f757f3fSDimitry Andric   /// of the pointer.
123*5f757f3fSDimitry Andric   [[nodiscard]]  Pointer atFieldSub(unsigned Off) const {
124*5f757f3fSDimitry Andric     assert(Offset >= Off);
125*5f757f3fSDimitry Andric     unsigned O = Offset - Off;
126*5f757f3fSDimitry Andric     return Pointer(Pointee, O, O);
127*5f757f3fSDimitry Andric   }
128*5f757f3fSDimitry Andric 
129a7dea167SDimitry Andric   /// Restricts the scope of an array element pointer.
130*5f757f3fSDimitry Andric   [[nodiscard]] Pointer narrow() const {
131a7dea167SDimitry Andric     // Null pointers cannot be narrowed.
132a7dea167SDimitry Andric     if (isZero() || isUnknownSizeArray())
133a7dea167SDimitry Andric       return *this;
134a7dea167SDimitry Andric 
135a7dea167SDimitry Andric     // Pointer to an array of base types - enter block.
136a7dea167SDimitry Andric     if (Base == RootPtrMark)
137a7dea167SDimitry Andric       return Pointer(Pointee, 0, Offset == 0 ? Offset : PastEndMark);
138a7dea167SDimitry Andric 
139a7dea167SDimitry Andric     // Pointer is one past end - magic offset marks that.
140a7dea167SDimitry Andric     if (isOnePastEnd())
141a7dea167SDimitry Andric       return Pointer(Pointee, Base, PastEndMark);
142a7dea167SDimitry Andric 
143a7dea167SDimitry Andric     // Primitive arrays are a bit special since they do not have inline
144a7dea167SDimitry Andric     // descriptors. If Offset != Base, then the pointer already points to
145a7dea167SDimitry Andric     // an element and there is nothing to do. Otherwise, the pointer is
146a7dea167SDimitry Andric     // adjusted to the first element of the array.
147a7dea167SDimitry Andric     if (inPrimitiveArray()) {
148a7dea167SDimitry Andric       if (Offset != Base)
149a7dea167SDimitry Andric         return *this;
150*5f757f3fSDimitry Andric       return Pointer(Pointee, Base, Offset + sizeof(InitMapPtr));
151a7dea167SDimitry Andric     }
152a7dea167SDimitry Andric 
153a7dea167SDimitry Andric     // Pointer is to a field or array element - enter it.
154a7dea167SDimitry Andric     if (Offset != Base)
155a7dea167SDimitry Andric       return Pointer(Pointee, Offset, Offset);
156a7dea167SDimitry Andric 
157a7dea167SDimitry Andric     // Enter the first element of an array.
158a7dea167SDimitry Andric     if (!getFieldDesc()->isArray())
159a7dea167SDimitry Andric       return *this;
160a7dea167SDimitry Andric 
161a7dea167SDimitry Andric     const unsigned NewBase = Base + sizeof(InlineDescriptor);
162a7dea167SDimitry Andric     return Pointer(Pointee, NewBase, NewBase);
163a7dea167SDimitry Andric   }
164a7dea167SDimitry Andric 
165a7dea167SDimitry Andric   /// Expands a pointer to the containing array, undoing narrowing.
166*5f757f3fSDimitry Andric   [[nodiscard]] Pointer expand() const {
167a7dea167SDimitry Andric     if (isElementPastEnd()) {
168a7dea167SDimitry Andric       // Revert to an outer one-past-end pointer.
169a7dea167SDimitry Andric       unsigned Adjust;
170a7dea167SDimitry Andric       if (inPrimitiveArray())
171*5f757f3fSDimitry Andric         Adjust = sizeof(InitMapPtr);
172a7dea167SDimitry Andric       else
173a7dea167SDimitry Andric         Adjust = sizeof(InlineDescriptor);
174a7dea167SDimitry Andric       return Pointer(Pointee, Base, Base + getSize() + Adjust);
175a7dea167SDimitry Andric     }
176a7dea167SDimitry Andric 
177a7dea167SDimitry Andric     // Do not step out of array elements.
178a7dea167SDimitry Andric     if (Base != Offset)
179a7dea167SDimitry Andric       return *this;
180a7dea167SDimitry Andric 
181a7dea167SDimitry Andric     // If at base, point to an array of base types.
182a7dea167SDimitry Andric     if (Base == 0)
183a7dea167SDimitry Andric       return Pointer(Pointee, RootPtrMark, 0);
184a7dea167SDimitry Andric 
185a7dea167SDimitry Andric     // Step into the containing array, if inside one.
186a7dea167SDimitry Andric     unsigned Next = Base - getInlineDesc()->Offset;
187*5f757f3fSDimitry Andric     const Descriptor *Desc =
188*5f757f3fSDimitry Andric         Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc;
189a7dea167SDimitry Andric     if (!Desc->IsArray)
190a7dea167SDimitry Andric       return *this;
191a7dea167SDimitry Andric     return Pointer(Pointee, Next, Offset);
192a7dea167SDimitry Andric   }
193a7dea167SDimitry Andric 
194a7dea167SDimitry Andric   /// Checks if the pointer is null.
195a7dea167SDimitry Andric   bool isZero() const { return Pointee == nullptr; }
196a7dea167SDimitry Andric   /// Checks if the pointer is live.
197a7dea167SDimitry Andric   bool isLive() const { return Pointee && !Pointee->IsDead; }
198a7dea167SDimitry Andric   /// Checks if the item is a field in an object.
199a7dea167SDimitry Andric   bool isField() const { return Base != 0 && Base != RootPtrMark; }
200a7dea167SDimitry Andric 
201a7dea167SDimitry Andric   /// Accessor for information about the declaration site.
202*5f757f3fSDimitry Andric   const Descriptor *getDeclDesc() const {
203*5f757f3fSDimitry Andric     assert(Pointee);
204*5f757f3fSDimitry Andric     return Pointee->Desc;
205*5f757f3fSDimitry Andric   }
206a7dea167SDimitry Andric   SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
207a7dea167SDimitry Andric 
208a7dea167SDimitry Andric   /// Returns a pointer to the object of which this pointer is a field.
209*5f757f3fSDimitry Andric   [[nodiscard]] Pointer getBase() const {
210a7dea167SDimitry Andric     if (Base == RootPtrMark) {
211a7dea167SDimitry Andric       assert(Offset == PastEndMark && "cannot get base of a block");
212a7dea167SDimitry Andric       return Pointer(Pointee, Base, 0);
213a7dea167SDimitry Andric     }
214a7dea167SDimitry Andric     assert(Offset == Base && "not an inner field");
215a7dea167SDimitry Andric     unsigned NewBase = Base - getInlineDesc()->Offset;
216a7dea167SDimitry Andric     return Pointer(Pointee, NewBase, NewBase);
217a7dea167SDimitry Andric   }
218a7dea167SDimitry Andric   /// Returns the parent array.
219*5f757f3fSDimitry Andric   [[nodiscard]] Pointer getArray() const {
220a7dea167SDimitry Andric     if (Base == RootPtrMark) {
221a7dea167SDimitry Andric       assert(Offset != 0 && Offset != PastEndMark && "not an array element");
222a7dea167SDimitry Andric       return Pointer(Pointee, Base, 0);
223a7dea167SDimitry Andric     }
224a7dea167SDimitry Andric     assert(Offset != Base && "not an array element");
225a7dea167SDimitry Andric     return Pointer(Pointee, Base, Base);
226a7dea167SDimitry Andric   }
227a7dea167SDimitry Andric 
228a7dea167SDimitry Andric   /// Accessors for information about the innermost field.
229*5f757f3fSDimitry Andric   const Descriptor *getFieldDesc() const {
230a7dea167SDimitry Andric     if (Base == 0 || Base == RootPtrMark)
231a7dea167SDimitry Andric       return getDeclDesc();
232a7dea167SDimitry Andric     return getInlineDesc()->Desc;
233a7dea167SDimitry Andric   }
234a7dea167SDimitry Andric 
235a7dea167SDimitry Andric   /// Returns the type of the innermost field.
236*5f757f3fSDimitry Andric   QualType getType() const {
237*5f757f3fSDimitry Andric     if (inPrimitiveArray() && Offset != Base)
238*5f757f3fSDimitry Andric       return getFieldDesc()->getType()->getAsArrayTypeUnsafe()->getElementType();
239*5f757f3fSDimitry Andric     return getFieldDesc()->getType();
240*5f757f3fSDimitry Andric   }
241a7dea167SDimitry Andric 
242*5f757f3fSDimitry Andric   [[nodiscard]] Pointer getDeclPtr() const { return Pointer(Pointee); }
24306c3fb27SDimitry Andric 
244a7dea167SDimitry Andric   /// Returns the element size of the innermost field.
245a7dea167SDimitry Andric   size_t elemSize() const {
246a7dea167SDimitry Andric     if (Base == RootPtrMark)
247a7dea167SDimitry Andric       return getDeclDesc()->getSize();
248a7dea167SDimitry Andric     return getFieldDesc()->getElemSize();
249a7dea167SDimitry Andric   }
250a7dea167SDimitry Andric   /// Returns the total size of the innermost field.
251a7dea167SDimitry Andric   size_t getSize() const { return getFieldDesc()->getSize(); }
252a7dea167SDimitry Andric 
253a7dea167SDimitry Andric   /// Returns the offset into an array.
254a7dea167SDimitry Andric   unsigned getOffset() const {
255a7dea167SDimitry Andric     assert(Offset != PastEndMark && "invalid offset");
256a7dea167SDimitry Andric     if (Base == RootPtrMark)
257a7dea167SDimitry Andric       return Offset;
258a7dea167SDimitry Andric 
259a7dea167SDimitry Andric     unsigned Adjust = 0;
260a7dea167SDimitry Andric     if (Offset != Base) {
261a7dea167SDimitry Andric       if (getFieldDesc()->ElemDesc)
262a7dea167SDimitry Andric         Adjust = sizeof(InlineDescriptor);
263a7dea167SDimitry Andric       else
264*5f757f3fSDimitry Andric         Adjust = sizeof(InitMapPtr);
265a7dea167SDimitry Andric     }
266a7dea167SDimitry Andric     return Offset - Base - Adjust;
267a7dea167SDimitry Andric   }
268a7dea167SDimitry Andric 
26906c3fb27SDimitry Andric   /// Whether this array refers to an array, but not
27006c3fb27SDimitry Andric   /// to the first element.
27106c3fb27SDimitry Andric   bool isArrayRoot() const { return inArray() && Offset == Base; }
27206c3fb27SDimitry Andric 
273a7dea167SDimitry Andric   /// Checks if the innermost field is an array.
274a7dea167SDimitry Andric   bool inArray() const { return getFieldDesc()->IsArray; }
275a7dea167SDimitry Andric   /// Checks if the structure is a primitive array.
276a7dea167SDimitry Andric   bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
277a7dea167SDimitry Andric   /// Checks if the structure is an array of unknown size.
278a7dea167SDimitry Andric   bool isUnknownSizeArray() const {
279a7dea167SDimitry Andric     return getFieldDesc()->isUnknownSizeArray();
280a7dea167SDimitry Andric   }
281a7dea167SDimitry Andric   /// Checks if the pointer points to an array.
282*5f757f3fSDimitry Andric   bool isArrayElement() const { return inArray() && Base != Offset; }
283a7dea167SDimitry Andric   /// Pointer points directly to a block.
284a7dea167SDimitry Andric   bool isRoot() const {
285a7dea167SDimitry Andric     return (Base == 0 || Base == RootPtrMark) && Offset == 0;
286a7dea167SDimitry Andric   }
287a7dea167SDimitry Andric 
288a7dea167SDimitry Andric   /// Returns the record descriptor of a class.
28906c3fb27SDimitry Andric   const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
29006c3fb27SDimitry Andric   /// Returns the element record type, if this is a non-primive array.
29106c3fb27SDimitry Andric   const Record *getElemRecord() const {
292*5f757f3fSDimitry Andric     const Descriptor *ElemDesc = getFieldDesc()->ElemDesc;
293*5f757f3fSDimitry Andric     return ElemDesc ? ElemDesc->ElemRecord : nullptr;
29406c3fb27SDimitry Andric   }
295a7dea167SDimitry Andric   /// Returns the field information.
296a7dea167SDimitry Andric   const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
297a7dea167SDimitry Andric 
298a7dea167SDimitry Andric   /// Checks if the object is a union.
299a7dea167SDimitry Andric   bool isUnion() const;
300a7dea167SDimitry Andric 
301a7dea167SDimitry Andric   /// Checks if the storage is extern.
302*5f757f3fSDimitry Andric   bool isExtern() const { return Pointee && Pointee->isExtern(); }
303a7dea167SDimitry Andric   /// Checks if the storage is static.
304*5f757f3fSDimitry Andric   bool isStatic() const {
305*5f757f3fSDimitry Andric     assert(Pointee);
306*5f757f3fSDimitry Andric     return Pointee->isStatic();
307*5f757f3fSDimitry Andric   }
308a7dea167SDimitry Andric   /// Checks if the storage is temporary.
309*5f757f3fSDimitry Andric   bool isTemporary() const {
310*5f757f3fSDimitry Andric     assert(Pointee);
311*5f757f3fSDimitry Andric     return Pointee->isTemporary();
312*5f757f3fSDimitry Andric   }
313a7dea167SDimitry Andric   /// Checks if the storage is a static temporary.
314a7dea167SDimitry Andric   bool isStaticTemporary() const { return isStatic() && isTemporary(); }
315a7dea167SDimitry Andric 
316a7dea167SDimitry Andric   /// Checks if the field is mutable.
317bdd1243dSDimitry Andric   bool isMutable() const {
318bdd1243dSDimitry Andric     return Base != 0 && getInlineDesc()->IsFieldMutable;
319bdd1243dSDimitry Andric   }
320a7dea167SDimitry Andric   /// Checks if an object was initialized.
321a7dea167SDimitry Andric   bool isInitialized() const;
322a7dea167SDimitry Andric   /// Checks if the object is active.
323a7dea167SDimitry Andric   bool isActive() const { return Base == 0 || getInlineDesc()->IsActive; }
324a7dea167SDimitry Andric   /// Checks if a structure is a base class.
325a7dea167SDimitry Andric   bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
326*5f757f3fSDimitry Andric   /// Checks if the pointer pointers to a dummy value.
327*5f757f3fSDimitry Andric   bool isDummy() const { return getDeclDesc()->isDummy(); }
328a7dea167SDimitry Andric 
329a7dea167SDimitry Andric   /// Checks if an object or a subfield is mutable.
330a7dea167SDimitry Andric   bool isConst() const {
331a7dea167SDimitry Andric     return Base == 0 ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;
332a7dea167SDimitry Andric   }
333a7dea167SDimitry Andric 
334a7dea167SDimitry Andric   /// Returns the declaration ID.
335*5f757f3fSDimitry Andric   std::optional<unsigned> getDeclID() const {
336*5f757f3fSDimitry Andric     assert(Pointee);
337*5f757f3fSDimitry Andric     return Pointee->getDeclID();
338*5f757f3fSDimitry Andric   }
339a7dea167SDimitry Andric 
340a7dea167SDimitry Andric   /// Returns the byte offset from the start.
341a7dea167SDimitry Andric   unsigned getByteOffset() const {
342a7dea167SDimitry Andric     return Offset;
343a7dea167SDimitry Andric   }
344a7dea167SDimitry Andric 
345a7dea167SDimitry Andric   /// Returns the number of elements.
346a7dea167SDimitry Andric   unsigned getNumElems() const { return getSize() / elemSize(); }
347a7dea167SDimitry Andric 
34806c3fb27SDimitry Andric   const Block *block() const { return Pointee; }
34906c3fb27SDimitry Andric 
350a7dea167SDimitry Andric   /// Returns the index into an array.
351a7dea167SDimitry Andric   int64_t getIndex() const {
352a7dea167SDimitry Andric     if (isElementPastEnd())
353a7dea167SDimitry Andric       return 1;
354*5f757f3fSDimitry Andric 
355*5f757f3fSDimitry Andric     // narrow()ed element in a composite array.
356*5f757f3fSDimitry Andric     if (Base > 0 && Base == Offset)
357*5f757f3fSDimitry Andric       return 0;
358*5f757f3fSDimitry Andric 
359a7dea167SDimitry Andric     if (auto ElemSize = elemSize())
360a7dea167SDimitry Andric       return getOffset() / ElemSize;
361a7dea167SDimitry Andric     return 0;
362a7dea167SDimitry Andric   }
363a7dea167SDimitry Andric 
364a7dea167SDimitry Andric   /// Checks if the index is one past end.
365a7dea167SDimitry Andric   bool isOnePastEnd() const {
366*5f757f3fSDimitry Andric     if (!Pointee)
367*5f757f3fSDimitry Andric       return false;
368a7dea167SDimitry Andric     return isElementPastEnd() || getSize() == getOffset();
369a7dea167SDimitry Andric   }
370a7dea167SDimitry Andric 
371a7dea167SDimitry Andric   /// Checks if the pointer is an out-of-bounds element pointer.
372a7dea167SDimitry Andric   bool isElementPastEnd() const { return Offset == PastEndMark; }
373a7dea167SDimitry Andric 
374a7dea167SDimitry Andric   /// Dereferences the pointer, if it's live.
375a7dea167SDimitry Andric   template <typename T> T &deref() const {
376a7dea167SDimitry Andric     assert(isLive() && "Invalid pointer");
377*5f757f3fSDimitry Andric     assert(Pointee);
37806c3fb27SDimitry Andric     if (isArrayRoot())
37906c3fb27SDimitry Andric       return *reinterpret_cast<T *>(Pointee->rawData() + Base +
380*5f757f3fSDimitry Andric                                     sizeof(InitMapPtr));
38106c3fb27SDimitry Andric 
382bdd1243dSDimitry Andric     return *reinterpret_cast<T *>(Pointee->rawData() + Offset);
383a7dea167SDimitry Andric   }
384a7dea167SDimitry Andric 
385a7dea167SDimitry Andric   /// Dereferences a primitive element.
386a7dea167SDimitry Andric   template <typename T> T &elem(unsigned I) const {
38706c3fb27SDimitry Andric     assert(I < getNumElems());
388*5f757f3fSDimitry Andric     assert(Pointee);
389*5f757f3fSDimitry Andric     return reinterpret_cast<T *>(Pointee->data() + sizeof(InitMapPtr))[I];
390a7dea167SDimitry Andric   }
391a7dea167SDimitry Andric 
392a7dea167SDimitry Andric   /// Initializes a field.
393a7dea167SDimitry Andric   void initialize() const;
394a7dea167SDimitry Andric   /// Activats a field.
395a7dea167SDimitry Andric   void activate() const;
396a7dea167SDimitry Andric   /// Deactivates an entire strurcutre.
397a7dea167SDimitry Andric   void deactivate() const;
398a7dea167SDimitry Andric 
399*5f757f3fSDimitry Andric   /// Compare two pointers.
400*5f757f3fSDimitry Andric   ComparisonCategoryResult compare(const Pointer &Other) const {
401*5f757f3fSDimitry Andric     if (!hasSameBase(*this, Other))
402*5f757f3fSDimitry Andric       return ComparisonCategoryResult::Unordered;
403*5f757f3fSDimitry Andric 
404*5f757f3fSDimitry Andric     if (Offset < Other.Offset)
405*5f757f3fSDimitry Andric       return ComparisonCategoryResult::Less;
406*5f757f3fSDimitry Andric     else if (Offset > Other.Offset)
407*5f757f3fSDimitry Andric       return ComparisonCategoryResult::Greater;
408*5f757f3fSDimitry Andric 
409*5f757f3fSDimitry Andric     return ComparisonCategoryResult::Equal;
410*5f757f3fSDimitry Andric   }
411*5f757f3fSDimitry Andric 
412a7dea167SDimitry Andric   /// Checks if two pointers are comparable.
413a7dea167SDimitry Andric   static bool hasSameBase(const Pointer &A, const Pointer &B);
414a7dea167SDimitry Andric   /// Checks if two pointers can be subtracted.
415a7dea167SDimitry Andric   static bool hasSameArray(const Pointer &A, const Pointer &B);
416a7dea167SDimitry Andric 
417a7dea167SDimitry Andric   /// Prints the pointer.
418a7dea167SDimitry Andric   void print(llvm::raw_ostream &OS) const {
419*5f757f3fSDimitry Andric     OS << Pointee << " {";
420*5f757f3fSDimitry Andric     if (Base == RootPtrMark)
421*5f757f3fSDimitry Andric       OS << "rootptr, ";
422*5f757f3fSDimitry Andric     else
423*5f757f3fSDimitry Andric       OS << Base << ", ";
424*5f757f3fSDimitry Andric 
425*5f757f3fSDimitry Andric     if (Offset == PastEndMark)
426*5f757f3fSDimitry Andric       OS << "pastend, ";
427*5f757f3fSDimitry Andric     else
428*5f757f3fSDimitry Andric       OS << Offset << ", ";
429*5f757f3fSDimitry Andric 
430a7dea167SDimitry Andric     if (Pointee)
431a7dea167SDimitry Andric       OS << Pointee->getSize();
432a7dea167SDimitry Andric     else
433a7dea167SDimitry Andric       OS << "nullptr";
434a7dea167SDimitry Andric     OS << "}";
435a7dea167SDimitry Andric   }
436a7dea167SDimitry Andric 
437a7dea167SDimitry Andric private:
438a7dea167SDimitry Andric   friend class Block;
439a7dea167SDimitry Andric   friend class DeadBlock;
440*5f757f3fSDimitry Andric   friend struct InitMap;
441a7dea167SDimitry Andric 
442a7dea167SDimitry Andric   Pointer(Block *Pointee, unsigned Base, unsigned Offset);
443a7dea167SDimitry Andric 
444a7dea167SDimitry Andric   /// Returns the embedded descriptor preceding a field.
445a7dea167SDimitry Andric   InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); }
446a7dea167SDimitry Andric 
447a7dea167SDimitry Andric   /// Returns a descriptor at a given offset.
448a7dea167SDimitry Andric   InlineDescriptor *getDescriptor(unsigned Offset) const {
449a7dea167SDimitry Andric     assert(Offset != 0 && "Not a nested pointer");
450*5f757f3fSDimitry Andric     assert(Pointee);
451bdd1243dSDimitry Andric     return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) -
452bdd1243dSDimitry Andric            1;
453a7dea167SDimitry Andric   }
454a7dea167SDimitry Andric 
455*5f757f3fSDimitry Andric   /// Returns a reference to the InitMapPtr which stores the initialization map.
456*5f757f3fSDimitry Andric   InitMapPtr &getInitMap() const {
457*5f757f3fSDimitry Andric     assert(Pointee);
458*5f757f3fSDimitry Andric     return *reinterpret_cast<InitMapPtr *>(Pointee->rawData() + Base);
459a7dea167SDimitry Andric   }
460a7dea167SDimitry Andric 
461a7dea167SDimitry Andric   /// The block the pointer is pointing to.
462a7dea167SDimitry Andric   Block *Pointee = nullptr;
463a7dea167SDimitry Andric   /// Start of the current subfield.
464a7dea167SDimitry Andric   unsigned Base = 0;
465a7dea167SDimitry Andric   /// Offset into the block.
466a7dea167SDimitry Andric   unsigned Offset = 0;
467a7dea167SDimitry Andric 
468a7dea167SDimitry Andric   /// Previous link in the pointer chain.
469a7dea167SDimitry Andric   Pointer *Prev = nullptr;
470a7dea167SDimitry Andric   /// Next link in the pointer chain.
471a7dea167SDimitry Andric   Pointer *Next = nullptr;
472a7dea167SDimitry Andric };
473a7dea167SDimitry Andric 
474a7dea167SDimitry Andric inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
475a7dea167SDimitry Andric   P.print(OS);
476a7dea167SDimitry Andric   return OS;
477a7dea167SDimitry Andric }
478a7dea167SDimitry Andric 
479a7dea167SDimitry Andric } // namespace interp
480a7dea167SDimitry Andric } // namespace clang
481a7dea167SDimitry Andric 
482a7dea167SDimitry Andric #endif
483