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