clang  16.0.0git
Pointer.cpp
Go to the documentation of this file.
1 //===--- Pointer.cpp - 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 #include "Pointer.h"
10 #include "Function.h"
11 #include "InterpBlock.h"
12 #include "PrimType.h"
13 
14 using namespace clang;
15 using namespace clang::interp;
16 
17 Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
18 
19 Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
20 
22  : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
23  if (Pointee)
24  Pointee->movePointer(&P, this);
25 }
26 
27 Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
28  : Pointee(Pointee), Base(Base), Offset(Offset) {
29  assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
30  if (Pointee)
31  Pointee->addPointer(this);
32 }
33 
35  if (Pointee) {
36  Pointee->removePointer(this);
37  Pointee->cleanup();
38  }
39 }
40 
42  Block *Old = Pointee;
43 
44  if (Pointee)
45  Pointee->removePointer(this);
46 
47  Offset = P.Offset;
48  Base = P.Base;
49 
50  Pointee = P.Pointee;
51  if (Pointee)
52  Pointee->addPointer(this);
53 
54  if (Old)
55  Old->cleanup();
56 }
57 
59  Block *Old = Pointee;
60 
61  if (Pointee)
62  Pointee->removePointer(this);
63 
64  Offset = P.Offset;
65  Base = P.Base;
66 
67  Pointee = P.Pointee;
68  if (Pointee)
69  Pointee->movePointer(&P, this);
70 
71  if (Old)
72  Old->cleanup();
73 }
74 
79  bool IsNullPtr;
80  bool IsOnePastEnd;
81 
82  if (isZero()) {
83  Base = static_cast<const Expr *>(nullptr);
84  IsNullPtr = true;
85  IsOnePastEnd = false;
87  } else {
88  // Build the lvalue base from the block.
89  Descriptor *Desc = getDeclDesc();
90  if (auto *VD = Desc->asValueDecl())
91  Base = VD;
92  else if (auto *E = Desc->asExpr())
93  Base = E;
94  else
95  llvm_unreachable("Invalid allocation type");
96 
97  // Not a null pointer.
98  IsNullPtr = false;
99 
100  if (isUnknownSizeArray()) {
101  IsOnePastEnd = false;
103  } else {
104  // TODO: compute the offset into the object.
106 
107  // Build the path into the object.
108  Pointer Ptr = *this;
109  while (Ptr.isField() || Ptr.isArrayElement()) {
110  if (Ptr.isArrayElement()) {
111  Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
112  Ptr = Ptr.getArray();
113  } else {
114  // TODO: figure out if base is virtual
115  bool IsVirtual = false;
116 
117  // Create a path entry for the field.
118  Descriptor *Desc = Ptr.getFieldDesc();
119  if (auto *BaseOrMember = Desc->asDecl()) {
120  Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
121  Ptr = Ptr.getBase();
122  continue;
123  }
124  llvm_unreachable("Invalid field type");
125  }
126  }
127 
128  IsOnePastEnd = isOnePastEnd();
129  }
130  }
131 
132  // We assemble the LValuePath starting from the innermost pointer to the
133  // outermost one. SO in a.b.c, the first element in Path will refer to
134  // the field 'c', while later code expects it to refer to 'a'.
135  // Just invert the order of the elements.
136  std::reverse(Path.begin(), Path.end());
137 
138  return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
139 }
140 
142  assert(Pointee && "Cannot check if null pointer was initialized");
143  Descriptor *Desc = getFieldDesc();
144  assert(Desc);
145  if (Desc->isPrimitiveArray()) {
146  if (isStatic() && Base == 0)
147  return true;
148  // Primitive array field are stored in a bitset.
149  InitMap *Map = getInitMap();
150  if (!Map)
151  return false;
152  if (Map == (InitMap *)-1)
153  return true;
154  return Map->isInitialized(getIndex());
155  } else {
156  // Field has its bit in an inline descriptor.
157  return Base == 0 || getInlineDesc()->IsInitialized;
158  }
159 }
160 
161 void Pointer::initialize() const {
162  assert(Pointee && "Cannot initialize null pointer");
163  Descriptor *Desc = getFieldDesc();
164 
165  assert(Desc);
166  if (Desc->isArray()) {
167  if (Desc->isPrimitiveArray()) {
168  // Primitive global arrays don't have an initmap.
169  if (isStatic() && Base == 0)
170  return;
171 
172  // Primitive array initializer.
173  InitMap *&Map = getInitMap();
174  if (Map == (InitMap *)-1)
175  return;
176  if (Map == nullptr)
177  Map = InitMap::allocate(Desc->getNumElems());
178  if (Map->initialize(getIndex())) {
179  free(Map);
180  Map = (InitMap *)-1;
181  }
182  }
183  } else {
184  // Field has its bit in an inline descriptor.
185  assert(Base != 0 && "Only composite fields can be initialised");
186  getInlineDesc()->IsInitialized = true;
187  }
188 }
189 
190 void Pointer::activate() const {
191  // Field has its bit in an inline descriptor.
192  assert(Base != 0 && "Only composite fields can be initialised");
193  getInlineDesc()->IsActive = true;
194 }
195 
196 void Pointer::deactivate() const {
197  // TODO: this only appears in constructors, so nothing to deactivate.
198 }
199 
200 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
201  return A.Pointee == B.Pointee;
202 }
203 
204 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
205  return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
206 }
clang::interp::Pointer::initialize
void initialize() const
Initializes a field.
Definition: Pointer.cpp:161
clang::interp::InitMap::allocate
static InitMap * allocate(unsigned N)
Allocates a map holding N elements.
Definition: Descriptor.cpp:291
clang::APValue::LValueBase
Definition: APValue.h:146
Pointer.h
clang::interp::Descriptor::isPrimitiveArray
bool isPrimitiveArray() const
Checks if the descriptor is of an array of primitives.
Definition: Descriptor.h:144
llvm::SmallVector
Definition: LLVM.h:38
clang::interp::Block::movePointer
void movePointer(Pointer *From, Pointer *To)
Definition: InterpBlock.cpp:47
clang::interp::Descriptor::IsArray
const bool IsArray
Flag indicating if the block is an array.
Definition: Descriptor.h:80
clang::interp::Pointer::getArray
Pointer getArray() const
Returns the parent array.
Definition: Pointer.h:158
clang::interp::Pointer::getDeclDesc
Descriptor * getDeclDesc() const
Accessor for information about the declaration site.
Definition: Pointer.h:144
clang::interp::InitMap::isInitialized
bool isInitialized(unsigned I)
Checks if an element was initialized.
Definition: Descriptor.cpp:286
clang::interp::Pointer::hasSameArray
static bool hasSameArray(const Pointer &A, const Pointer &B)
Checks if two pointers can be subtracted.
Definition: Pointer.cpp:204
clang::interp::Pointer::isField
bool isField() const
Checks if the item is a field in an object.
Definition: Pointer.h:141
clang::interp::Pointer
A pointer to a memory block, live or dead.
Definition: Pointer.h:36
Offset
unsigned Offset
Definition: Format.cpp:2717
clang::interp::Descriptor::getNumElems
unsigned getNumElems() const
Returns the number of elements stored in the block.
Definition: Descriptor.h:139
clang::interp::InitMap
Bitfield tracking the initialisation status of elements of primitive arrays.
Definition: Descriptor.h:189
clang::interp::Pointer::hasSameBase
static bool hasSameBase(const Pointer &A, const Pointer &B)
Checks if two pointers are comparable.
Definition: Pointer.cpp:200
clang::interp
Definition: ASTContext.h:128
clang::interp::Descriptor::isArray
bool isArray() const
Checks if the descriptor is of an array.
Definition: Descriptor.h:154
clang::interp::Pointer::activate
void activate() const
Activats a field.
Definition: Pointer.cpp:190
clang::interp::InlineDescriptor::IsActive
unsigned IsActive
Flag indicating if the field is the active member of a union.
Definition: Descriptor.h:178
clang::interp::Block
A memory block, either on the stack or in the heap.
Definition: InterpBlock.h:35
clang::interp::Pointer::isArrayElement
bool isArrayElement() const
Checks if the pointer points to an array.
Definition: Pointer.h:211
PrimType.h
clang::CharUnits::Zero
static CharUnits Zero()
Zero - Construct a CharUnits quantity of zero.
Definition: CharUnits.h:53
Base
clang::interp::InitMap::initialize
bool initialize(unsigned I)
Initializes an element. Returns true when object if fully initialized.
Definition: Descriptor.cpp:276
clang::interp::Descriptor::asValueDecl
const ValueDecl * asValueDecl() const
Definition: Descriptor.h:115
P
StringRef P
Definition: ASTMatchersInternal.cpp:564
InterpBlock.h
clang::interp::Pointer::deactivate
void deactivate() const
Deactivates an entire strurcutre.
Definition: Pointer.cpp:196
clang::interp::Block::cleanup
void cleanup()
Definition: InterpBlock.cpp:42
clang::interp::Pointer::isZero
bool isZero() const
Checks if the pointer is null.
Definition: Pointer.h:137
clang::APValue::LValuePathEntry::ArrayIndex
static LValuePathEntry ArrayIndex(uint64_t Index)
Definition: APValue.h:216
clang::interp::Descriptor::asDecl
const Decl * asDecl() const
Definition: Descriptor.h:112
clang::interp::Descriptor
Describes a memory block created by an allocation site.
Definition: Descriptor.h:51
clang::interp::Pointer::isInitialized
bool isInitialized() const
Checks if an object was initialized.
Definition: Pointer.cpp:141
clang::interp::Pointer::getBase
Pointer getBase() const
Returns a pointer to the object of which this pointer is a field.
Definition: Pointer.h:148
clang::interp::Pointer::toAPValue
APValue toAPValue() const
Converts the pointer to an APValue.
Definition: Pointer.cpp:75
clang
Definition: CalledOnceCheck.h:17
Function.h
clang::interp::Pointer::~Pointer
~Pointer()
Definition: Pointer.cpp:34
clang::interp::Block::addPointer
void addPointer(Pointer *P)
Definition: InterpBlock.cpp:21
clang::interp::Pointer::Pointer
Pointer()
Definition: Pointer.h:42
clang::interp::Pointer::isStatic
bool isStatic() const
Checks if the storage is static.
Definition: Pointer.h:228
clang::interp::Descriptor::asExpr
const Expr * asExpr() const
Definition: Descriptor.h:113
clang::interp::Pointer::getIndex
int64_t getIndex() const
Returns the index into an array.
Definition: Pointer.h:260
clang::CharUnits
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
clang::APValue
APValue - This class implements a discriminated union of [uninitialized] [APSInt] [APFloat],...
Definition: APValue.h:122
clang::interp::InlineDescriptor::IsInitialized
unsigned IsInitialized
For primitive fields, it indicates if the field was initialized.
Definition: Descriptor.h:174
clang::Expr
This represents one expression.
Definition: Expr.h:109
clang::interp::Pointer::operator=
void operator=(const Pointer &P)
Definition: Pointer.cpp:41
clang::interp::Block::removePointer
void removePointer(Pointer *P)
Definition: InterpBlock.cpp:31
clang::APValue::LValuePathEntry
A non-discriminated union of a base, field, or array index.
Definition: APValue.h:208
clang::interp::Pointer::isUnknownSizeArray
bool isUnknownSizeArray() const
Checks if the structure is an array of unknown size.
Definition: Pointer.h:207
clang::interp::Pointer::getFieldDesc
Descriptor * getFieldDesc() const
Accessors for information about the innermost field.
Definition: Pointer.h:168
clang::interp::Pointer::isOnePastEnd
bool isOnePastEnd() const
Checks if the index is one past end.
Definition: Pointer.h:269