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