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