xref: /llvm-project/clang/lib/AST/ByteCode/Pointer.h (revision 51c7338cc671c90ba9345b53c7ca01dc461341ed)
1a07aba5dSTimm Baeder //===--- Pointer.h - Types for the constexpr VM -----------------*- C++ -*-===//
2a07aba5dSTimm Baeder //
3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information.
5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a07aba5dSTimm Baeder //
7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
8a07aba5dSTimm Baeder //
9a07aba5dSTimm Baeder // Defines the classes responsible for pointer tracking.
10a07aba5dSTimm Baeder //
11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===//
12a07aba5dSTimm Baeder 
13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_POINTER_H
14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_POINTER_H
15a07aba5dSTimm Baeder 
16a07aba5dSTimm Baeder #include "Descriptor.h"
17a07aba5dSTimm Baeder #include "FunctionPointer.h"
18a07aba5dSTimm Baeder #include "InterpBlock.h"
19a07aba5dSTimm Baeder #include "clang/AST/ComparisonCategories.h"
20a07aba5dSTimm Baeder #include "clang/AST/Decl.h"
21a07aba5dSTimm Baeder #include "clang/AST/DeclCXX.h"
22a07aba5dSTimm Baeder #include "clang/AST/Expr.h"
23a07aba5dSTimm Baeder #include "llvm/Support/raw_ostream.h"
24a07aba5dSTimm Baeder 
25a07aba5dSTimm Baeder namespace clang {
26a07aba5dSTimm Baeder namespace interp {
27a07aba5dSTimm Baeder class Block;
28a07aba5dSTimm Baeder class DeadBlock;
29a07aba5dSTimm Baeder class Pointer;
30a07aba5dSTimm Baeder class Context;
31a07aba5dSTimm Baeder template <unsigned A, bool B> class Integral;
32a07aba5dSTimm Baeder enum PrimType : unsigned;
33a07aba5dSTimm Baeder 
34a07aba5dSTimm Baeder class Pointer;
35a07aba5dSTimm Baeder inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);
36a07aba5dSTimm Baeder 
37a07aba5dSTimm Baeder struct BlockPointer {
38a07aba5dSTimm Baeder   /// The block the pointer is pointing to.
39a07aba5dSTimm Baeder   Block *Pointee;
40a07aba5dSTimm Baeder   /// Start of the current subfield.
41a07aba5dSTimm Baeder   unsigned Base;
42a07aba5dSTimm Baeder };
43a07aba5dSTimm Baeder 
44a07aba5dSTimm Baeder struct IntPointer {
45a07aba5dSTimm Baeder   const Descriptor *Desc;
46a07aba5dSTimm Baeder   uint64_t Value;
47a07aba5dSTimm Baeder 
48a07aba5dSTimm Baeder   IntPointer atOffset(const ASTContext &ASTCtx, unsigned Offset) const;
4943fd2c40STimm Baeder   IntPointer baseCast(const ASTContext &ASTCtx, unsigned BaseOffset) const;
50a07aba5dSTimm Baeder };
51a07aba5dSTimm Baeder 
52e86b68ffSTimm Baeder struct TypeidPointer {
53e86b68ffSTimm Baeder   const Type *TypePtr;
54e86b68ffSTimm Baeder   const Type *TypeInfoType;
55e86b68ffSTimm Baeder };
56e86b68ffSTimm Baeder 
57e86b68ffSTimm Baeder enum class Storage { Block, Int, Fn, Typeid };
58a07aba5dSTimm Baeder 
59a07aba5dSTimm Baeder /// A pointer to a memory block, live or dead.
60a07aba5dSTimm Baeder ///
61a07aba5dSTimm Baeder /// This object can be allocated into interpreter stack frames. If pointing to
62a07aba5dSTimm Baeder /// a live block, it is a link in the chain of pointers pointing to the block.
63a07aba5dSTimm Baeder ///
64a07aba5dSTimm Baeder /// In the simplest form, a Pointer has a Block* (the pointee) and both Base
65a07aba5dSTimm Baeder /// and Offset are 0, which means it will point to raw data.
66a07aba5dSTimm Baeder ///
67a07aba5dSTimm Baeder /// The Base field is used to access metadata about the data. For primitive
68a07aba5dSTimm Baeder /// arrays, the Base is followed by an InitMap. In a variety of cases, the
69a07aba5dSTimm Baeder /// Base is preceded by an InlineDescriptor, which is used to track the
70a07aba5dSTimm Baeder /// initialization state, among other things.
71a07aba5dSTimm Baeder ///
72a07aba5dSTimm Baeder /// The Offset field is used to access the actual data. In other words, the
73a07aba5dSTimm Baeder /// data the pointer decribes can be found at
74a07aba5dSTimm Baeder /// Pointee->rawData() + Pointer.Offset.
75a07aba5dSTimm Baeder ///
76a07aba5dSTimm Baeder ///
77a07aba5dSTimm Baeder /// Pointee                      Offset
78a07aba5dSTimm Baeder /// │                              │
79a07aba5dSTimm Baeder /// │                              │
80a07aba5dSTimm Baeder /// ▼                              ▼
81a07aba5dSTimm Baeder /// ┌───────┬────────────┬─────────┬────────────────────────────┐
82a07aba5dSTimm Baeder /// │ Block │ InlineDesc │ InitMap │ Actual Data                │
83a07aba5dSTimm Baeder /// └───────┴────────────┴─────────┴────────────────────────────┘
84a07aba5dSTimm Baeder ///                      ▲
85a07aba5dSTimm Baeder ///                      │
86a07aba5dSTimm Baeder ///                      │
87a07aba5dSTimm Baeder ///                     Base
88a07aba5dSTimm Baeder class Pointer {
89a07aba5dSTimm Baeder private:
90a07aba5dSTimm Baeder   static constexpr unsigned PastEndMark = ~0u;
91a07aba5dSTimm Baeder   static constexpr unsigned RootPtrMark = ~0u;
92a07aba5dSTimm Baeder 
93a07aba5dSTimm Baeder public:
94a07aba5dSTimm Baeder   Pointer() {
95a07aba5dSTimm Baeder     StorageKind = Storage::Int;
96a07aba5dSTimm Baeder     PointeeStorage.Int.Value = 0;
97a07aba5dSTimm Baeder     PointeeStorage.Int.Desc = nullptr;
98a07aba5dSTimm Baeder   }
99a07aba5dSTimm Baeder   Pointer(IntPointer &&IntPtr) : StorageKind(Storage::Int) {
100a07aba5dSTimm Baeder     PointeeStorage.Int = std::move(IntPtr);
101a07aba5dSTimm Baeder   }
102a07aba5dSTimm Baeder   Pointer(Block *B);
103a07aba5dSTimm Baeder   Pointer(Block *B, uint64_t BaseAndOffset);
104a07aba5dSTimm Baeder   Pointer(const Pointer &P);
105a07aba5dSTimm Baeder   Pointer(Pointer &&P);
106a07aba5dSTimm Baeder   Pointer(uint64_t Address, const Descriptor *Desc, uint64_t Offset = 0)
107a07aba5dSTimm Baeder       : Offset(Offset), StorageKind(Storage::Int) {
108a07aba5dSTimm Baeder     PointeeStorage.Int.Value = Address;
109a07aba5dSTimm Baeder     PointeeStorage.Int.Desc = Desc;
110a07aba5dSTimm Baeder   }
111a07aba5dSTimm Baeder   Pointer(const Function *F, uint64_t Offset = 0)
112a07aba5dSTimm Baeder       : Offset(Offset), StorageKind(Storage::Fn) {
113a07aba5dSTimm Baeder     PointeeStorage.Fn = FunctionPointer(F);
114a07aba5dSTimm Baeder   }
115e86b68ffSTimm Baeder   Pointer(const Type *TypePtr, const Type *TypeInfoType, uint64_t Offset = 0)
116e86b68ffSTimm Baeder       : Offset(Offset), StorageKind(Storage::Typeid) {
117e86b68ffSTimm Baeder     PointeeStorage.Typeid.TypePtr = TypePtr;
118e86b68ffSTimm Baeder     PointeeStorage.Typeid.TypeInfoType = TypeInfoType;
119e86b68ffSTimm Baeder   }
1201f2d9345STimm Baeder   Pointer(Block *Pointee, unsigned Base, uint64_t Offset);
121a07aba5dSTimm Baeder   ~Pointer();
122a07aba5dSTimm Baeder 
123a07aba5dSTimm Baeder   void operator=(const Pointer &P);
124a07aba5dSTimm Baeder   void operator=(Pointer &&P);
125a07aba5dSTimm Baeder 
126a07aba5dSTimm Baeder   /// Equality operators are just for tests.
127a07aba5dSTimm Baeder   bool operator==(const Pointer &P) const {
128a07aba5dSTimm Baeder     if (P.StorageKind != StorageKind)
129a07aba5dSTimm Baeder       return false;
130a07aba5dSTimm Baeder     if (isIntegralPointer())
131a07aba5dSTimm Baeder       return P.asIntPointer().Value == asIntPointer().Value &&
132a07aba5dSTimm Baeder              Offset == P.Offset;
133a07aba5dSTimm Baeder 
134a07aba5dSTimm Baeder     assert(isBlockPointer());
135a07aba5dSTimm Baeder     return P.asBlockPointer().Pointee == asBlockPointer().Pointee &&
136a07aba5dSTimm Baeder            P.asBlockPointer().Base == asBlockPointer().Base &&
137a07aba5dSTimm Baeder            Offset == P.Offset;
138a07aba5dSTimm Baeder   }
139a07aba5dSTimm Baeder 
140a07aba5dSTimm Baeder   bool operator!=(const Pointer &P) const { return !(P == *this); }
141a07aba5dSTimm Baeder 
142a07aba5dSTimm Baeder   /// Converts the pointer to an APValue.
143a07aba5dSTimm Baeder   APValue toAPValue(const ASTContext &ASTCtx) const;
144a07aba5dSTimm Baeder 
145a07aba5dSTimm Baeder   /// Converts the pointer to a string usable in diagnostics.
146a07aba5dSTimm Baeder   std::string toDiagnosticString(const ASTContext &Ctx) const;
147a07aba5dSTimm Baeder 
148a07aba5dSTimm Baeder   uint64_t getIntegerRepresentation() const {
149a07aba5dSTimm Baeder     if (isIntegralPointer())
150a07aba5dSTimm Baeder       return asIntPointer().Value + (Offset * elemSize());
151a07aba5dSTimm Baeder     if (isFunctionPointer())
152db94852bSTimm Baeder       return asFunctionPointer().getIntegerRepresentation() + Offset;
153a07aba5dSTimm Baeder     return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
154a07aba5dSTimm Baeder   }
155a07aba5dSTimm Baeder 
156a07aba5dSTimm Baeder   /// Converts the pointer to an APValue that is an rvalue.
157a07aba5dSTimm Baeder   std::optional<APValue> toRValue(const Context &Ctx,
158a07aba5dSTimm Baeder                                   QualType ResultType) const;
159a07aba5dSTimm Baeder 
160a07aba5dSTimm Baeder   /// Offsets a pointer inside an array.
161a07aba5dSTimm Baeder   [[nodiscard]] Pointer atIndex(uint64_t Idx) const {
162a07aba5dSTimm Baeder     if (isIntegralPointer())
163a07aba5dSTimm Baeder       return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);
164a07aba5dSTimm Baeder     if (isFunctionPointer())
165a07aba5dSTimm Baeder       return Pointer(asFunctionPointer().getFunction(), Idx);
166a07aba5dSTimm Baeder 
167a07aba5dSTimm Baeder     if (asBlockPointer().Base == RootPtrMark)
168a07aba5dSTimm Baeder       return Pointer(asBlockPointer().Pointee, RootPtrMark,
169a07aba5dSTimm Baeder                      getDeclDesc()->getSize());
170a07aba5dSTimm Baeder     uint64_t Off = Idx * elemSize();
171a07aba5dSTimm Baeder     if (getFieldDesc()->ElemDesc)
172a07aba5dSTimm Baeder       Off += sizeof(InlineDescriptor);
173a07aba5dSTimm Baeder     else
174a07aba5dSTimm Baeder       Off += sizeof(InitMapPtr);
175a07aba5dSTimm Baeder     return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
176a07aba5dSTimm Baeder                    asBlockPointer().Base + Off);
177a07aba5dSTimm Baeder   }
178a07aba5dSTimm Baeder 
179a07aba5dSTimm Baeder   /// Creates a pointer to a field.
180a07aba5dSTimm Baeder   [[nodiscard]] Pointer atField(unsigned Off) const {
181a07aba5dSTimm Baeder     assert(isBlockPointer());
182a07aba5dSTimm Baeder     unsigned Field = Offset + Off;
183a07aba5dSTimm Baeder     return Pointer(asBlockPointer().Pointee, Field, Field);
184a07aba5dSTimm Baeder   }
185a07aba5dSTimm Baeder 
186a07aba5dSTimm Baeder   /// Subtract the given offset from the current Base and Offset
187a07aba5dSTimm Baeder   /// of the pointer.
188a07aba5dSTimm Baeder   [[nodiscard]] Pointer atFieldSub(unsigned Off) const {
189a07aba5dSTimm Baeder     assert(Offset >= Off);
190a07aba5dSTimm Baeder     unsigned O = Offset - Off;
191a07aba5dSTimm Baeder     return Pointer(asBlockPointer().Pointee, O, O);
192a07aba5dSTimm Baeder   }
193a07aba5dSTimm Baeder 
194a07aba5dSTimm Baeder   /// Restricts the scope of an array element pointer.
195a07aba5dSTimm Baeder   [[nodiscard]] Pointer narrow() const {
196a07aba5dSTimm Baeder     if (!isBlockPointer())
197a07aba5dSTimm Baeder       return *this;
198a07aba5dSTimm Baeder     assert(isBlockPointer());
199a07aba5dSTimm Baeder     // Null pointers cannot be narrowed.
200a07aba5dSTimm Baeder     if (isZero() || isUnknownSizeArray())
201a07aba5dSTimm Baeder       return *this;
202a07aba5dSTimm Baeder 
203a07aba5dSTimm Baeder     // Pointer to an array of base types - enter block.
204a07aba5dSTimm Baeder     if (asBlockPointer().Base == RootPtrMark)
205a07aba5dSTimm Baeder       return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor),
206a07aba5dSTimm Baeder                      Offset == 0 ? Offset : PastEndMark);
207a07aba5dSTimm Baeder 
208a07aba5dSTimm Baeder     // Pointer is one past end - magic offset marks that.
209a07aba5dSTimm Baeder     if (isOnePastEnd())
210a07aba5dSTimm Baeder       return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
211a07aba5dSTimm Baeder                      PastEndMark);
212a07aba5dSTimm Baeder 
213a07aba5dSTimm Baeder     // Primitive arrays are a bit special since they do not have inline
214a07aba5dSTimm Baeder     // descriptors. If Offset != Base, then the pointer already points to
215a07aba5dSTimm Baeder     // an element and there is nothing to do. Otherwise, the pointer is
216a07aba5dSTimm Baeder     // adjusted to the first element of the array.
217a07aba5dSTimm Baeder     if (inPrimitiveArray()) {
218a07aba5dSTimm Baeder       if (Offset != asBlockPointer().Base)
219a07aba5dSTimm Baeder         return *this;
220a07aba5dSTimm Baeder       return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
221a07aba5dSTimm Baeder                      Offset + sizeof(InitMapPtr));
222a07aba5dSTimm Baeder     }
223a07aba5dSTimm Baeder 
224a07aba5dSTimm Baeder     // Pointer is to a field or array element - enter it.
225a07aba5dSTimm Baeder     if (Offset != asBlockPointer().Base)
226a07aba5dSTimm Baeder       return Pointer(asBlockPointer().Pointee, Offset, Offset);
227a07aba5dSTimm Baeder 
228a07aba5dSTimm Baeder     // Enter the first element of an array.
229a07aba5dSTimm Baeder     if (!getFieldDesc()->isArray())
230a07aba5dSTimm Baeder       return *this;
231a07aba5dSTimm Baeder 
232a07aba5dSTimm Baeder     const unsigned NewBase = asBlockPointer().Base + sizeof(InlineDescriptor);
233a07aba5dSTimm Baeder     return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
234a07aba5dSTimm Baeder   }
235a07aba5dSTimm Baeder 
236a07aba5dSTimm Baeder   /// Expands a pointer to the containing array, undoing narrowing.
237a07aba5dSTimm Baeder   [[nodiscard]] Pointer expand() const {
238a07aba5dSTimm Baeder     assert(isBlockPointer());
239a07aba5dSTimm Baeder     Block *Pointee = asBlockPointer().Pointee;
240a07aba5dSTimm Baeder 
241a07aba5dSTimm Baeder     if (isElementPastEnd()) {
242a07aba5dSTimm Baeder       // Revert to an outer one-past-end pointer.
243a07aba5dSTimm Baeder       unsigned Adjust;
244a07aba5dSTimm Baeder       if (inPrimitiveArray())
245a07aba5dSTimm Baeder         Adjust = sizeof(InitMapPtr);
246a07aba5dSTimm Baeder       else
247a07aba5dSTimm Baeder         Adjust = sizeof(InlineDescriptor);
248a07aba5dSTimm Baeder       return Pointer(Pointee, asBlockPointer().Base,
249a07aba5dSTimm Baeder                      asBlockPointer().Base + getSize() + Adjust);
250a07aba5dSTimm Baeder     }
251a07aba5dSTimm Baeder 
252a07aba5dSTimm Baeder     // Do not step out of array elements.
253a07aba5dSTimm Baeder     if (asBlockPointer().Base != Offset)
254a07aba5dSTimm Baeder       return *this;
255a07aba5dSTimm Baeder 
256a07aba5dSTimm Baeder     if (isRoot())
257d6d60707STimm Baeder       return Pointer(Pointee, asBlockPointer().Base, asBlockPointer().Base);
258a07aba5dSTimm Baeder 
259a07aba5dSTimm Baeder     // Step into the containing array, if inside one.
260a07aba5dSTimm Baeder     unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;
261a07aba5dSTimm Baeder     const Descriptor *Desc =
262a07aba5dSTimm Baeder         (Next == Pointee->getDescriptor()->getMetadataSize())
263a07aba5dSTimm Baeder             ? getDeclDesc()
264a07aba5dSTimm Baeder             : getDescriptor(Next)->Desc;
265a07aba5dSTimm Baeder     if (!Desc->IsArray)
266a07aba5dSTimm Baeder       return *this;
267a07aba5dSTimm Baeder     return Pointer(Pointee, Next, Offset);
268a07aba5dSTimm Baeder   }
269a07aba5dSTimm Baeder 
270a07aba5dSTimm Baeder   /// Checks if the pointer is null.
271a07aba5dSTimm Baeder   bool isZero() const {
272a07aba5dSTimm Baeder     if (isBlockPointer())
273a07aba5dSTimm Baeder       return asBlockPointer().Pointee == nullptr;
274a07aba5dSTimm Baeder     if (isFunctionPointer())
275a07aba5dSTimm Baeder       return asFunctionPointer().isZero();
276e86b68ffSTimm Baeder     if (isTypeidPointer())
277e86b68ffSTimm Baeder       return false;
278a07aba5dSTimm Baeder     assert(isIntegralPointer());
279a07aba5dSTimm Baeder     return asIntPointer().Value == 0 && Offset == 0;
280a07aba5dSTimm Baeder   }
281a07aba5dSTimm Baeder   /// Checks if the pointer is live.
282a07aba5dSTimm Baeder   bool isLive() const {
283a07aba5dSTimm Baeder     if (!isBlockPointer())
284a07aba5dSTimm Baeder       return true;
285a07aba5dSTimm Baeder     return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead;
286a07aba5dSTimm Baeder   }
287a07aba5dSTimm Baeder   /// Checks if the item is a field in an object.
288a07aba5dSTimm Baeder   bool isField() const {
289a07aba5dSTimm Baeder     if (!isBlockPointer())
290a07aba5dSTimm Baeder       return false;
291a07aba5dSTimm Baeder 
292a07aba5dSTimm Baeder     return !isRoot() && getFieldDesc()->asDecl();
293a07aba5dSTimm Baeder   }
294a07aba5dSTimm Baeder 
295a07aba5dSTimm Baeder   /// Accessor for information about the declaration site.
296a07aba5dSTimm Baeder   const Descriptor *getDeclDesc() const {
297a07aba5dSTimm Baeder     if (isIntegralPointer())
298a07aba5dSTimm Baeder       return asIntPointer().Desc;
299e86b68ffSTimm Baeder     if (isFunctionPointer() || isTypeidPointer())
300a07aba5dSTimm Baeder       return nullptr;
301a07aba5dSTimm Baeder 
302a07aba5dSTimm Baeder     assert(isBlockPointer());
303a07aba5dSTimm Baeder     assert(asBlockPointer().Pointee);
304a07aba5dSTimm Baeder     return asBlockPointer().Pointee->Desc;
305a07aba5dSTimm Baeder   }
306a07aba5dSTimm Baeder   SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
307a07aba5dSTimm Baeder 
308a07aba5dSTimm Baeder   /// Returns the expression or declaration the pointer has been created for.
309a07aba5dSTimm Baeder   DeclTy getSource() const {
310a07aba5dSTimm Baeder     if (isBlockPointer())
311a07aba5dSTimm Baeder       return getDeclDesc()->getSource();
312a07aba5dSTimm Baeder     if (isFunctionPointer()) {
313a07aba5dSTimm Baeder       const Function *F = asFunctionPointer().getFunction();
314a07aba5dSTimm Baeder       return F ? F->getDecl() : DeclTy();
315a07aba5dSTimm Baeder     }
316a07aba5dSTimm Baeder     assert(isIntegralPointer());
317a07aba5dSTimm Baeder     return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy();
318a07aba5dSTimm Baeder   }
319a07aba5dSTimm Baeder 
320a07aba5dSTimm Baeder   /// Returns a pointer to the object of which this pointer is a field.
321a07aba5dSTimm Baeder   [[nodiscard]] Pointer getBase() const {
322a07aba5dSTimm Baeder     if (asBlockPointer().Base == RootPtrMark) {
323a07aba5dSTimm Baeder       assert(Offset == PastEndMark && "cannot get base of a block");
324a07aba5dSTimm Baeder       return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
325a07aba5dSTimm Baeder     }
326a07aba5dSTimm Baeder     unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset;
327a07aba5dSTimm Baeder     return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
328a07aba5dSTimm Baeder   }
329a07aba5dSTimm Baeder   /// Returns the parent array.
330a07aba5dSTimm Baeder   [[nodiscard]] Pointer getArray() const {
331a07aba5dSTimm Baeder     if (asBlockPointer().Base == RootPtrMark) {
332a07aba5dSTimm Baeder       assert(Offset != 0 && Offset != PastEndMark && "not an array element");
333a07aba5dSTimm Baeder       return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
334a07aba5dSTimm Baeder     }
335a07aba5dSTimm Baeder     assert(Offset != asBlockPointer().Base && "not an array element");
336a07aba5dSTimm Baeder     return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
337a07aba5dSTimm Baeder                    asBlockPointer().Base);
338a07aba5dSTimm Baeder   }
339a07aba5dSTimm Baeder 
340a07aba5dSTimm Baeder   /// Accessors for information about the innermost field.
341a07aba5dSTimm Baeder   const Descriptor *getFieldDesc() const {
342a07aba5dSTimm Baeder     if (isIntegralPointer())
343a07aba5dSTimm Baeder       return asIntPointer().Desc;
344a07aba5dSTimm Baeder 
345a07aba5dSTimm Baeder     if (isRoot())
346a07aba5dSTimm Baeder       return getDeclDesc();
347a07aba5dSTimm Baeder     return getInlineDesc()->Desc;
348a07aba5dSTimm Baeder   }
349a07aba5dSTimm Baeder 
350a07aba5dSTimm Baeder   /// Returns the type of the innermost field.
351a07aba5dSTimm Baeder   QualType getType() const {
352e86b68ffSTimm Baeder     if (isTypeidPointer())
353e86b68ffSTimm Baeder       return QualType(PointeeStorage.Typeid.TypeInfoType, 0);
354e86b68ffSTimm Baeder 
355a07aba5dSTimm Baeder     if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
356a07aba5dSTimm Baeder       // Unfortunately, complex and vector types are not array types in clang,
357a07aba5dSTimm Baeder       // but they are for us.
358a07aba5dSTimm Baeder       if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
359a07aba5dSTimm Baeder         return AT->getElementType();
360a07aba5dSTimm Baeder       if (const auto *CT = getFieldDesc()->getType()->getAs<ComplexType>())
361a07aba5dSTimm Baeder         return CT->getElementType();
362a07aba5dSTimm Baeder       if (const auto *CT = getFieldDesc()->getType()->getAs<VectorType>())
363a07aba5dSTimm Baeder         return CT->getElementType();
364a07aba5dSTimm Baeder     }
365a07aba5dSTimm Baeder     return getFieldDesc()->getType();
366a07aba5dSTimm Baeder   }
367a07aba5dSTimm Baeder 
368a07aba5dSTimm Baeder   [[nodiscard]] Pointer getDeclPtr() const {
369a07aba5dSTimm Baeder     return Pointer(asBlockPointer().Pointee);
370a07aba5dSTimm Baeder   }
371a07aba5dSTimm Baeder 
372a07aba5dSTimm Baeder   /// Returns the element size of the innermost field.
373a07aba5dSTimm Baeder   size_t elemSize() const {
374a07aba5dSTimm Baeder     if (isIntegralPointer()) {
375a07aba5dSTimm Baeder       if (!asIntPointer().Desc)
376a07aba5dSTimm Baeder         return 1;
377a07aba5dSTimm Baeder       return asIntPointer().Desc->getElemSize();
378a07aba5dSTimm Baeder     }
379a07aba5dSTimm Baeder 
380a07aba5dSTimm Baeder     if (asBlockPointer().Base == RootPtrMark)
381a07aba5dSTimm Baeder       return getDeclDesc()->getSize();
382a07aba5dSTimm Baeder     return getFieldDesc()->getElemSize();
383a07aba5dSTimm Baeder   }
384a07aba5dSTimm Baeder   /// Returns the total size of the innermost field.
385a07aba5dSTimm Baeder   size_t getSize() const {
386a07aba5dSTimm Baeder     assert(isBlockPointer());
387a07aba5dSTimm Baeder     return getFieldDesc()->getSize();
388a07aba5dSTimm Baeder   }
389a07aba5dSTimm Baeder 
390a07aba5dSTimm Baeder   /// Returns the offset into an array.
391a07aba5dSTimm Baeder   unsigned getOffset() const {
392a07aba5dSTimm Baeder     assert(Offset != PastEndMark && "invalid offset");
393a07aba5dSTimm Baeder     assert(isBlockPointer());
394a07aba5dSTimm Baeder     if (asBlockPointer().Base == RootPtrMark)
395a07aba5dSTimm Baeder       return Offset;
396a07aba5dSTimm Baeder 
397a07aba5dSTimm Baeder     unsigned Adjust = 0;
398a07aba5dSTimm Baeder     if (Offset != asBlockPointer().Base) {
399a07aba5dSTimm Baeder       if (getFieldDesc()->ElemDesc)
400a07aba5dSTimm Baeder         Adjust = sizeof(InlineDescriptor);
401a07aba5dSTimm Baeder       else
402a07aba5dSTimm Baeder         Adjust = sizeof(InitMapPtr);
403a07aba5dSTimm Baeder     }
404a07aba5dSTimm Baeder     return Offset - asBlockPointer().Base - Adjust;
405a07aba5dSTimm Baeder   }
406a07aba5dSTimm Baeder 
407a07aba5dSTimm Baeder   /// Whether this array refers to an array, but not
408a07aba5dSTimm Baeder   /// to the first element.
409a07aba5dSTimm Baeder   bool isArrayRoot() const {
410a07aba5dSTimm Baeder     return inArray() && Offset == asBlockPointer().Base;
411a07aba5dSTimm Baeder   }
412a07aba5dSTimm Baeder 
413a07aba5dSTimm Baeder   /// Checks if the innermost field is an array.
414a07aba5dSTimm Baeder   bool inArray() const {
415a07aba5dSTimm Baeder     if (isBlockPointer())
416a07aba5dSTimm Baeder       return getFieldDesc()->IsArray;
417a07aba5dSTimm Baeder     return false;
418a07aba5dSTimm Baeder   }
419a07aba5dSTimm Baeder   bool inUnion() const {
420a07aba5dSTimm Baeder     if (isBlockPointer())
421a07aba5dSTimm Baeder       return getInlineDesc()->InUnion;
422a07aba5dSTimm Baeder     return false;
423a07aba5dSTimm Baeder   };
424a07aba5dSTimm Baeder 
425a07aba5dSTimm Baeder   /// Checks if the structure is a primitive array.
426a07aba5dSTimm Baeder   bool inPrimitiveArray() const {
427a07aba5dSTimm Baeder     if (isBlockPointer())
428a07aba5dSTimm Baeder       return getFieldDesc()->isPrimitiveArray();
429a07aba5dSTimm Baeder     return false;
430a07aba5dSTimm Baeder   }
431a07aba5dSTimm Baeder   /// Checks if the structure is an array of unknown size.
432a07aba5dSTimm Baeder   bool isUnknownSizeArray() const {
433a07aba5dSTimm Baeder     if (!isBlockPointer())
434a07aba5dSTimm Baeder       return false;
435a07aba5dSTimm Baeder     return getFieldDesc()->isUnknownSizeArray();
436a07aba5dSTimm Baeder   }
437a07aba5dSTimm Baeder   /// Checks if the pointer points to an array.
438a07aba5dSTimm Baeder   bool isArrayElement() const {
439800b0739STimm Baeder     if (!isBlockPointer())
440800b0739STimm Baeder       return false;
441800b0739STimm Baeder 
442800b0739STimm Baeder     const BlockPointer &BP = asBlockPointer();
443800b0739STimm Baeder     if (inArray() && BP.Base != Offset)
444800b0739STimm Baeder       return true;
445800b0739STimm Baeder 
446800b0739STimm Baeder     // Might be a narrow()'ed element in a composite array.
447800b0739STimm Baeder     // Check the inline descriptor.
448800b0739STimm Baeder     if (BP.Base >= sizeof(InlineDescriptor) && getInlineDesc()->IsArrayElement)
449800b0739STimm Baeder       return true;
450800b0739STimm Baeder 
451a07aba5dSTimm Baeder     return false;
452a07aba5dSTimm Baeder   }
453a07aba5dSTimm Baeder   /// Pointer points directly to a block.
454a07aba5dSTimm Baeder   bool isRoot() const {
455e86b68ffSTimm Baeder     if (isZero() || !isBlockPointer())
456a07aba5dSTimm Baeder       return true;
457a07aba5dSTimm Baeder     return (asBlockPointer().Base ==
458a07aba5dSTimm Baeder                 asBlockPointer().Pointee->getDescriptor()->getMetadataSize() ||
459a07aba5dSTimm Baeder             asBlockPointer().Base == 0);
460a07aba5dSTimm Baeder   }
461a07aba5dSTimm Baeder   /// If this pointer has an InlineDescriptor we can use to initialize.
462a07aba5dSTimm Baeder   bool canBeInitialized() const {
463a07aba5dSTimm Baeder     if (!isBlockPointer())
464a07aba5dSTimm Baeder       return false;
465a07aba5dSTimm Baeder 
466a07aba5dSTimm Baeder     return asBlockPointer().Pointee && asBlockPointer().Base > 0;
467a07aba5dSTimm Baeder   }
468a07aba5dSTimm Baeder 
469a07aba5dSTimm Baeder   [[nodiscard]] const BlockPointer &asBlockPointer() const {
470a07aba5dSTimm Baeder     assert(isBlockPointer());
471a07aba5dSTimm Baeder     return PointeeStorage.BS;
472a07aba5dSTimm Baeder   }
473a07aba5dSTimm Baeder   [[nodiscard]] const IntPointer &asIntPointer() const {
474a07aba5dSTimm Baeder     assert(isIntegralPointer());
475a07aba5dSTimm Baeder     return PointeeStorage.Int;
476a07aba5dSTimm Baeder   }
477a07aba5dSTimm Baeder   [[nodiscard]] const FunctionPointer &asFunctionPointer() const {
478a07aba5dSTimm Baeder     assert(isFunctionPointer());
479a07aba5dSTimm Baeder     return PointeeStorage.Fn;
480a07aba5dSTimm Baeder   }
481a07aba5dSTimm Baeder 
482a07aba5dSTimm Baeder   bool isBlockPointer() const { return StorageKind == Storage::Block; }
483a07aba5dSTimm Baeder   bool isIntegralPointer() const { return StorageKind == Storage::Int; }
484a07aba5dSTimm Baeder   bool isFunctionPointer() const { return StorageKind == Storage::Fn; }
485e86b68ffSTimm Baeder   bool isTypeidPointer() const { return StorageKind == Storage::Typeid; }
486a07aba5dSTimm Baeder 
487a07aba5dSTimm Baeder   /// Returns the record descriptor of a class.
488a07aba5dSTimm Baeder   const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
489a07aba5dSTimm Baeder   /// Returns the element record type, if this is a non-primive array.
490a07aba5dSTimm Baeder   const Record *getElemRecord() const {
491a07aba5dSTimm Baeder     const Descriptor *ElemDesc = getFieldDesc()->ElemDesc;
492a07aba5dSTimm Baeder     return ElemDesc ? ElemDesc->ElemRecord : nullptr;
493a07aba5dSTimm Baeder   }
494a07aba5dSTimm Baeder   /// Returns the field information.
495a07aba5dSTimm Baeder   const FieldDecl *getField() const { return getFieldDesc()->asFieldDecl(); }
496a07aba5dSTimm Baeder 
497a07aba5dSTimm Baeder   /// Checks if the object is a union.
498a07aba5dSTimm Baeder   bool isUnion() const;
499a07aba5dSTimm Baeder 
500a07aba5dSTimm Baeder   /// Checks if the storage is extern.
501a07aba5dSTimm Baeder   bool isExtern() const {
502a07aba5dSTimm Baeder     if (isBlockPointer())
503a07aba5dSTimm Baeder       return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern();
504a07aba5dSTimm Baeder     return false;
505a07aba5dSTimm Baeder   }
506a07aba5dSTimm Baeder   /// Checks if the storage is static.
507a07aba5dSTimm Baeder   bool isStatic() const {
508a07aba5dSTimm Baeder     if (!isBlockPointer())
509a07aba5dSTimm Baeder       return true;
510a07aba5dSTimm Baeder     assert(asBlockPointer().Pointee);
511a07aba5dSTimm Baeder     return asBlockPointer().Pointee->isStatic();
512a07aba5dSTimm Baeder   }
513a07aba5dSTimm Baeder   /// Checks if the storage is temporary.
514a07aba5dSTimm Baeder   bool isTemporary() const {
515a07aba5dSTimm Baeder     if (isBlockPointer()) {
516a07aba5dSTimm Baeder       assert(asBlockPointer().Pointee);
517a07aba5dSTimm Baeder       return asBlockPointer().Pointee->isTemporary();
518a07aba5dSTimm Baeder     }
519a07aba5dSTimm Baeder     return false;
520a07aba5dSTimm Baeder   }
521df11ee21STimm Baeder   /// Checks if the storage has been dynamically allocated.
522df11ee21STimm Baeder   bool isDynamic() const {
523df11ee21STimm Baeder     if (isBlockPointer()) {
524df11ee21STimm Baeder       assert(asBlockPointer().Pointee);
525df11ee21STimm Baeder       return asBlockPointer().Pointee->isDynamic();
526df11ee21STimm Baeder     }
527df11ee21STimm Baeder     return false;
528df11ee21STimm Baeder   }
529a07aba5dSTimm Baeder   /// Checks if the storage is a static temporary.
530a07aba5dSTimm Baeder   bool isStaticTemporary() const { return isStatic() && isTemporary(); }
531a07aba5dSTimm Baeder 
532a07aba5dSTimm Baeder   /// Checks if the field is mutable.
533a07aba5dSTimm Baeder   bool isMutable() const {
534a07aba5dSTimm Baeder     if (!isBlockPointer())
535a07aba5dSTimm Baeder       return false;
536a07aba5dSTimm Baeder     return !isRoot() && getInlineDesc()->IsFieldMutable;
537a07aba5dSTimm Baeder   }
538a07aba5dSTimm Baeder 
539a07aba5dSTimm Baeder   bool isWeak() const {
540a07aba5dSTimm Baeder     if (!isBlockPointer())
541a07aba5dSTimm Baeder       return false;
542a07aba5dSTimm Baeder 
543a07aba5dSTimm Baeder     assert(isBlockPointer());
5444e5f8a8fSTimm Baeder     return asBlockPointer().Pointee->isWeak();
545a07aba5dSTimm Baeder   }
546a07aba5dSTimm Baeder   /// Checks if an object was initialized.
547a07aba5dSTimm Baeder   bool isInitialized() const;
548a07aba5dSTimm Baeder   /// Checks if the object is active.
549a07aba5dSTimm Baeder   bool isActive() const {
550a07aba5dSTimm Baeder     if (!isBlockPointer())
551a07aba5dSTimm Baeder       return true;
552a07aba5dSTimm Baeder     return isRoot() || getInlineDesc()->IsActive;
553a07aba5dSTimm Baeder   }
554a07aba5dSTimm Baeder   /// Checks if a structure is a base class.
555a07aba5dSTimm Baeder   bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
556a07aba5dSTimm Baeder   bool isVirtualBaseClass() const {
557a07aba5dSTimm Baeder     return isField() && getInlineDesc()->IsVirtualBase;
558a07aba5dSTimm Baeder   }
559a07aba5dSTimm Baeder   /// Checks if the pointer points to a dummy value.
560a07aba5dSTimm Baeder   bool isDummy() const {
561a07aba5dSTimm Baeder     if (!isBlockPointer())
562a07aba5dSTimm Baeder       return false;
563a07aba5dSTimm Baeder 
564a07aba5dSTimm Baeder     if (!asBlockPointer().Pointee)
565a07aba5dSTimm Baeder       return false;
566a07aba5dSTimm Baeder 
567a07aba5dSTimm Baeder     return getDeclDesc()->isDummy();
568a07aba5dSTimm Baeder   }
569a07aba5dSTimm Baeder 
570a07aba5dSTimm Baeder   /// Checks if an object or a subfield is mutable.
571a07aba5dSTimm Baeder   bool isConst() const {
572a07aba5dSTimm Baeder     if (isIntegralPointer())
573a07aba5dSTimm Baeder       return true;
574a07aba5dSTimm Baeder     return isRoot() ? getDeclDesc()->IsConst : getInlineDesc()->IsConst;
575a07aba5dSTimm Baeder   }
576a07aba5dSTimm Baeder 
577a07aba5dSTimm Baeder   /// Returns the declaration ID.
578a07aba5dSTimm Baeder   std::optional<unsigned> getDeclID() const {
579a07aba5dSTimm Baeder     if (isBlockPointer()) {
580a07aba5dSTimm Baeder       assert(asBlockPointer().Pointee);
581a07aba5dSTimm Baeder       return asBlockPointer().Pointee->getDeclID();
582a07aba5dSTimm Baeder     }
583a07aba5dSTimm Baeder     return std::nullopt;
584a07aba5dSTimm Baeder   }
585a07aba5dSTimm Baeder 
586a07aba5dSTimm Baeder   /// Returns the byte offset from the start.
587db94852bSTimm Baeder   uint64_t getByteOffset() const {
588a07aba5dSTimm Baeder     if (isIntegralPointer())
589a07aba5dSTimm Baeder       return asIntPointer().Value + Offset;
590a07aba5dSTimm Baeder     if (isOnePastEnd())
591a07aba5dSTimm Baeder       return PastEndMark;
592a07aba5dSTimm Baeder     return Offset;
593a07aba5dSTimm Baeder   }
594a07aba5dSTimm Baeder 
595a07aba5dSTimm Baeder   /// Returns the number of elements.
596a07aba5dSTimm Baeder   unsigned getNumElems() const {
597a07aba5dSTimm Baeder     if (!isBlockPointer())
598a07aba5dSTimm Baeder       return ~0u;
599a07aba5dSTimm Baeder     return getSize() / elemSize();
600a07aba5dSTimm Baeder   }
601a07aba5dSTimm Baeder 
602a07aba5dSTimm Baeder   const Block *block() const { return asBlockPointer().Pointee; }
603a07aba5dSTimm Baeder 
604a07aba5dSTimm Baeder   /// Returns the index into an array.
605a07aba5dSTimm Baeder   int64_t getIndex() const {
606a07aba5dSTimm Baeder     if (!isBlockPointer())
607dac18299STimm Baeder       return getIntegerRepresentation();
608a07aba5dSTimm Baeder 
609a07aba5dSTimm Baeder     if (isZero())
610a07aba5dSTimm Baeder       return 0;
611a07aba5dSTimm Baeder 
612a07aba5dSTimm Baeder     // narrow()ed element in a composite array.
613a07aba5dSTimm Baeder     if (asBlockPointer().Base > sizeof(InlineDescriptor) &&
614a07aba5dSTimm Baeder         asBlockPointer().Base == Offset)
615a07aba5dSTimm Baeder       return 0;
616a07aba5dSTimm Baeder 
617a07aba5dSTimm Baeder     if (auto ElemSize = elemSize())
618a07aba5dSTimm Baeder       return getOffset() / ElemSize;
619a07aba5dSTimm Baeder     return 0;
620a07aba5dSTimm Baeder   }
621a07aba5dSTimm Baeder 
622a07aba5dSTimm Baeder   /// Checks if the index is one past end.
623a07aba5dSTimm Baeder   bool isOnePastEnd() const {
624e86b68ffSTimm Baeder     if (!isBlockPointer())
625a07aba5dSTimm Baeder       return false;
626a07aba5dSTimm Baeder 
627a07aba5dSTimm Baeder     if (!asBlockPointer().Pointee)
628a07aba5dSTimm Baeder       return false;
629a07aba5dSTimm Baeder 
630a07aba5dSTimm Baeder     if (isUnknownSizeArray())
631a07aba5dSTimm Baeder       return false;
632a07aba5dSTimm Baeder 
633*51c7338cSTimm Baeder     return isPastEnd() || (getSize() == getOffset() && !isZeroSizeArray());
634a07aba5dSTimm Baeder   }
635a07aba5dSTimm Baeder 
636a07aba5dSTimm Baeder   /// Checks if the pointer points past the end of the object.
637a07aba5dSTimm Baeder   bool isPastEnd() const {
638a07aba5dSTimm Baeder     if (isIntegralPointer())
639a07aba5dSTimm Baeder       return false;
640a07aba5dSTimm Baeder 
641a07aba5dSTimm Baeder     return !isZero() && Offset > PointeeStorage.BS.Pointee->getSize();
642a07aba5dSTimm Baeder   }
643a07aba5dSTimm Baeder 
644a07aba5dSTimm Baeder   /// Checks if the pointer is an out-of-bounds element pointer.
645a07aba5dSTimm Baeder   bool isElementPastEnd() const { return Offset == PastEndMark; }
646a07aba5dSTimm Baeder 
647a07aba5dSTimm Baeder   /// Checks if the pointer is pointing to a zero-size array.
648a07aba5dSTimm Baeder   bool isZeroSizeArray() const {
649db94852bSTimm Baeder     if (isFunctionPointer())
650db94852bSTimm Baeder       return false;
651a07aba5dSTimm Baeder     if (const auto *Desc = getFieldDesc())
652a07aba5dSTimm Baeder       return Desc->isZeroSizeArray();
653a07aba5dSTimm Baeder     return false;
654a07aba5dSTimm Baeder   }
655a07aba5dSTimm Baeder 
656a07aba5dSTimm Baeder   /// Dereferences the pointer, if it's live.
657a07aba5dSTimm Baeder   template <typename T> T &deref() const {
658a07aba5dSTimm Baeder     assert(isLive() && "Invalid pointer");
659a07aba5dSTimm Baeder     assert(isBlockPointer());
660a07aba5dSTimm Baeder     assert(asBlockPointer().Pointee);
661a07aba5dSTimm Baeder     assert(isDereferencable());
662a07aba5dSTimm Baeder     assert(Offset + sizeof(T) <=
663a07aba5dSTimm Baeder            asBlockPointer().Pointee->getDescriptor()->getAllocSize());
664a07aba5dSTimm Baeder 
665a07aba5dSTimm Baeder     if (isArrayRoot())
666a07aba5dSTimm Baeder       return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
667a07aba5dSTimm Baeder                                     asBlockPointer().Base + sizeof(InitMapPtr));
668a07aba5dSTimm Baeder 
669a07aba5dSTimm Baeder     return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset);
670a07aba5dSTimm Baeder   }
671a07aba5dSTimm Baeder 
672a07aba5dSTimm Baeder   /// Whether this block can be read from at all. This is only true for
673a07aba5dSTimm Baeder   /// block pointers that point to a valid location inside that block.
674a07aba5dSTimm Baeder   bool isDereferencable() const {
675a07aba5dSTimm Baeder     if (!isBlockPointer())
676a07aba5dSTimm Baeder       return false;
677a07aba5dSTimm Baeder     if (isPastEnd())
678a07aba5dSTimm Baeder       return false;
679a07aba5dSTimm Baeder 
680a07aba5dSTimm Baeder     return true;
681a07aba5dSTimm Baeder   }
682a07aba5dSTimm Baeder 
683a07aba5dSTimm Baeder   /// Initializes a field.
684a07aba5dSTimm Baeder   void initialize() const;
685a07aba5dSTimm Baeder   /// Activats a field.
686a07aba5dSTimm Baeder   void activate() const;
687a07aba5dSTimm Baeder   /// Deactivates an entire strurcutre.
688a07aba5dSTimm Baeder   void deactivate() const;
689a07aba5dSTimm Baeder 
690a07aba5dSTimm Baeder   /// Compare two pointers.
691a07aba5dSTimm Baeder   ComparisonCategoryResult compare(const Pointer &Other) const {
692a07aba5dSTimm Baeder     if (!hasSameBase(*this, Other))
693a07aba5dSTimm Baeder       return ComparisonCategoryResult::Unordered;
694a07aba5dSTimm Baeder 
695a07aba5dSTimm Baeder     if (Offset < Other.Offset)
696a07aba5dSTimm Baeder       return ComparisonCategoryResult::Less;
697a07aba5dSTimm Baeder     else if (Offset > Other.Offset)
698a07aba5dSTimm Baeder       return ComparisonCategoryResult::Greater;
699a07aba5dSTimm Baeder 
700a07aba5dSTimm Baeder     return ComparisonCategoryResult::Equal;
701a07aba5dSTimm Baeder   }
702a07aba5dSTimm Baeder 
703a07aba5dSTimm Baeder   /// Checks if two pointers are comparable.
704a07aba5dSTimm Baeder   static bool hasSameBase(const Pointer &A, const Pointer &B);
705a07aba5dSTimm Baeder   /// Checks if two pointers can be subtracted.
706a07aba5dSTimm Baeder   static bool hasSameArray(const Pointer &A, const Pointer &B);
707a07aba5dSTimm Baeder   /// Checks if both given pointers point to the same block.
708a07aba5dSTimm Baeder   static bool pointToSameBlock(const Pointer &A, const Pointer &B);
709a07aba5dSTimm Baeder 
710360e4abfSTimm Baeder   /// Whether this points to a block that's been created for a "literal lvalue",
711360e4abfSTimm Baeder   /// i.e. a non-MaterializeTemporaryExpr Expr.
712360e4abfSTimm Baeder   bool pointsToLiteral() const;
713360e4abfSTimm Baeder 
714a07aba5dSTimm Baeder   /// Prints the pointer.
715a07aba5dSTimm Baeder   void print(llvm::raw_ostream &OS) const;
716a07aba5dSTimm Baeder 
717a07aba5dSTimm Baeder private:
718a07aba5dSTimm Baeder   friend class Block;
719a07aba5dSTimm Baeder   friend class DeadBlock;
720a07aba5dSTimm Baeder   friend class MemberPointer;
721a07aba5dSTimm Baeder   friend class InterpState;
722a07aba5dSTimm Baeder   friend struct InitMap;
723a07aba5dSTimm Baeder   friend class DynamicAllocator;
724a07aba5dSTimm Baeder 
725a07aba5dSTimm Baeder   /// Returns the embedded descriptor preceding a field.
726a07aba5dSTimm Baeder   InlineDescriptor *getInlineDesc() const {
727d6d60707STimm Baeder     assert(isBlockPointer());
728a07aba5dSTimm Baeder     assert(asBlockPointer().Base != sizeof(GlobalInlineDescriptor));
729a07aba5dSTimm Baeder     assert(asBlockPointer().Base <= asBlockPointer().Pointee->getSize());
730d6d60707STimm Baeder     assert(asBlockPointer().Base >= sizeof(InlineDescriptor));
731a07aba5dSTimm Baeder     return getDescriptor(asBlockPointer().Base);
732a07aba5dSTimm Baeder   }
733a07aba5dSTimm Baeder 
734a07aba5dSTimm Baeder   /// Returns a descriptor at a given offset.
735a07aba5dSTimm Baeder   InlineDescriptor *getDescriptor(unsigned Offset) const {
736a07aba5dSTimm Baeder     assert(Offset != 0 && "Not a nested pointer");
737a07aba5dSTimm Baeder     assert(isBlockPointer());
738a07aba5dSTimm Baeder     assert(!isZero());
739a07aba5dSTimm Baeder     return reinterpret_cast<InlineDescriptor *>(
740a07aba5dSTimm Baeder                asBlockPointer().Pointee->rawData() + Offset) -
741a07aba5dSTimm Baeder            1;
742a07aba5dSTimm Baeder   }
743a07aba5dSTimm Baeder 
744a07aba5dSTimm Baeder   /// Returns a reference to the InitMapPtr which stores the initialization map.
745a07aba5dSTimm Baeder   InitMapPtr &getInitMap() const {
746a07aba5dSTimm Baeder     assert(isBlockPointer());
747a07aba5dSTimm Baeder     assert(!isZero());
748a07aba5dSTimm Baeder     return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() +
749a07aba5dSTimm Baeder                                            asBlockPointer().Base);
750a07aba5dSTimm Baeder   }
751a07aba5dSTimm Baeder 
752a07aba5dSTimm Baeder   /// Offset into the storage.
753a07aba5dSTimm Baeder   uint64_t Offset = 0;
754a07aba5dSTimm Baeder 
755a07aba5dSTimm Baeder   /// Previous link in the pointer chain.
756a07aba5dSTimm Baeder   Pointer *Prev = nullptr;
757a07aba5dSTimm Baeder   /// Next link in the pointer chain.
758a07aba5dSTimm Baeder   Pointer *Next = nullptr;
759a07aba5dSTimm Baeder 
760a07aba5dSTimm Baeder   union {
761a07aba5dSTimm Baeder     BlockPointer BS;
762a07aba5dSTimm Baeder     IntPointer Int;
763a07aba5dSTimm Baeder     FunctionPointer Fn;
764e86b68ffSTimm Baeder     TypeidPointer Typeid;
765a07aba5dSTimm Baeder   } PointeeStorage;
766a07aba5dSTimm Baeder   Storage StorageKind = Storage::Int;
767a07aba5dSTimm Baeder };
768a07aba5dSTimm Baeder 
769a07aba5dSTimm Baeder inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
770a07aba5dSTimm Baeder   P.print(OS);
771a07aba5dSTimm Baeder   return OS;
772a07aba5dSTimm Baeder }
773a07aba5dSTimm Baeder 
774a07aba5dSTimm Baeder } // namespace interp
775a07aba5dSTimm Baeder } // namespace clang
776a07aba5dSTimm Baeder 
777a07aba5dSTimm Baeder #endif
778