[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / clang / lib / AST / Interp / Pointer.cpp
blobe979b99b0fdd0a0ea7efff8bd1b0dc87d1a11814
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 //===----------------------------------------------------------------------===//
9 #include "Pointer.h"
10 #include "Boolean.h"
11 #include "Context.h"
12 #include "Floating.h"
13 #include "Function.h"
14 #include "Integral.h"
15 #include "InterpBlock.h"
16 #include "PrimType.h"
17 #include "Record.h"
19 using namespace clang;
20 using namespace clang::interp;
22 Pointer::Pointer(Block *Pointee) : Pointer(Pointee, 0, 0) {}
24 Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
25 : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
27 Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
29 Pointer::Pointer(Pointer &&P)
30 : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
31 if (Pointee)
32 Pointee->replacePointer(&P, this);
35 Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
36 : Pointee(Pointee), Base(Base), Offset(Offset) {
37 assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
38 if (Pointee)
39 Pointee->addPointer(this);
42 Pointer::~Pointer() {
43 if (Pointee) {
44 Pointee->removePointer(this);
45 Pointee->cleanup();
49 void Pointer::operator=(const Pointer &P) {
50 Block *Old = Pointee;
52 if (Pointee)
53 Pointee->removePointer(this);
55 Offset = P.Offset;
56 Base = P.Base;
58 Pointee = P.Pointee;
59 if (Pointee)
60 Pointee->addPointer(this);
62 if (Old)
63 Old->cleanup();
66 void Pointer::operator=(Pointer &&P) {
67 Block *Old = Pointee;
69 if (Pointee)
70 Pointee->removePointer(this);
72 Offset = P.Offset;
73 Base = P.Base;
75 Pointee = P.Pointee;
76 if (Pointee)
77 Pointee->replacePointer(&P, this);
79 if (Old)
80 Old->cleanup();
83 APValue Pointer::toAPValue() const {
84 APValue::LValueBase Base;
85 llvm::SmallVector<APValue::LValuePathEntry, 5> Path;
86 CharUnits Offset;
87 bool IsNullPtr;
88 bool IsOnePastEnd;
90 if (isZero()) {
91 Base = static_cast<const Expr *>(nullptr);
92 IsNullPtr = true;
93 IsOnePastEnd = false;
94 Offset = CharUnits::Zero();
95 } else {
96 // Build the lvalue base from the block.
97 const Descriptor *Desc = getDeclDesc();
98 if (auto *VD = Desc->asValueDecl())
99 Base = VD;
100 else if (auto *E = Desc->asExpr())
101 Base = E;
102 else
103 llvm_unreachable("Invalid allocation type");
105 // Not a null pointer.
106 IsNullPtr = false;
108 if (isUnknownSizeArray()) {
109 IsOnePastEnd = false;
110 Offset = CharUnits::Zero();
111 } else if (Desc->asExpr()) {
112 // Pointer pointing to a an expression.
113 IsOnePastEnd = false;
114 Offset = CharUnits::Zero();
115 } else {
116 // TODO: compute the offset into the object.
117 Offset = CharUnits::Zero();
119 // Build the path into the object.
120 Pointer Ptr = *this;
121 while (Ptr.isField() || Ptr.isArrayElement()) {
122 if (Ptr.isArrayElement()) {
123 Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex()));
124 Ptr = Ptr.getArray();
125 } else {
126 // TODO: figure out if base is virtual
127 bool IsVirtual = false;
129 // Create a path entry for the field.
130 const Descriptor *Desc = Ptr.getFieldDesc();
131 if (const auto *BaseOrMember = Desc->asDecl()) {
132 Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual}));
133 Ptr = Ptr.getBase();
134 continue;
136 llvm_unreachable("Invalid field type");
140 IsOnePastEnd = isOnePastEnd();
144 // We assemble the LValuePath starting from the innermost pointer to the
145 // outermost one. SO in a.b.c, the first element in Path will refer to
146 // the field 'c', while later code expects it to refer to 'a'.
147 // Just invert the order of the elements.
148 std::reverse(Path.begin(), Path.end());
150 return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr);
153 std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
154 if (!Pointee)
155 return "nullptr";
157 return toAPValue().getAsString(Ctx, getType());
160 bool Pointer::isInitialized() const {
161 assert(Pointee && "Cannot check if null pointer was initialized");
162 const Descriptor *Desc = getFieldDesc();
163 assert(Desc);
164 if (Desc->isPrimitiveArray()) {
165 if (isStatic() && Base == 0)
166 return true;
168 InitMapPtr &IM = getInitMap();
170 if (!IM)
171 return false;
173 if (IM->first)
174 return true;
176 return IM->second->isElementInitialized(getIndex());
179 // Field has its bit in an inline descriptor.
180 return Base == 0 || getInlineDesc()->IsInitialized;
183 void Pointer::initialize() const {
184 assert(Pointee && "Cannot initialize null pointer");
185 const Descriptor *Desc = getFieldDesc();
187 assert(Desc);
188 if (Desc->isPrimitiveArray()) {
189 // Primitive global arrays don't have an initmap.
190 if (isStatic() && Base == 0)
191 return;
193 InitMapPtr &IM = getInitMap();
194 if (!IM)
195 IM =
196 std::make_pair(false, std::make_shared<InitMap>(Desc->getNumElems()));
198 assert(IM);
200 // All initialized.
201 if (IM->first)
202 return;
204 if (IM->second->initializeElement(getIndex())) {
205 IM->first = true;
206 IM->second.reset();
208 return;
211 // Field has its bit in an inline descriptor.
212 assert(Base != 0 && "Only composite fields can be initialised");
213 getInlineDesc()->IsInitialized = true;
216 void Pointer::activate() const {
217 // Field has its bit in an inline descriptor.
218 assert(Base != 0 && "Only composite fields can be initialised");
219 getInlineDesc()->IsActive = true;
222 void Pointer::deactivate() const {
223 // TODO: this only appears in constructors, so nothing to deactivate.
226 bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
227 return A.Pointee == B.Pointee;
230 bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
231 return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
234 APValue Pointer::toRValue(const Context &Ctx) const {
235 // Primitives.
236 if (getFieldDesc()->isPrimitive()) {
237 PrimType PT = *Ctx.classify(getType());
238 TYPE_SWITCH(PT, return deref<T>().toAPValue());
239 llvm_unreachable("Unhandled PrimType?");
242 APValue Result;
243 // Records.
244 if (getFieldDesc()->isRecord()) {
245 const Record *R = getRecord();
246 Result =
247 APValue(APValue::UninitStruct(), R->getNumBases(), R->getNumFields());
249 for (unsigned I = 0; I != R->getNumFields(); ++I) {
250 const Pointer &FieldPtr = this->atField(R->getField(I)->Offset);
251 Result.getStructField(I) = FieldPtr.toRValue(Ctx);
254 for (unsigned I = 0; I != R->getNumBases(); ++I) {
255 const Pointer &BasePtr = this->atField(R->getBase(I)->Offset);
256 Result.getStructBase(I) = BasePtr.toRValue(Ctx);
260 // TODO: Arrays
262 return Result;