Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Context.cpp
35291 views
1
//===--- Context.cpp - Context 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 "Context.h"
10
#include "ByteCodeEmitter.h"
11
#include "Compiler.h"
12
#include "EvalEmitter.h"
13
#include "Interp.h"
14
#include "InterpFrame.h"
15
#include "InterpStack.h"
16
#include "PrimType.h"
17
#include "Program.h"
18
#include "clang/AST/Expr.h"
19
#include "clang/Basic/TargetInfo.h"
20
21
using namespace clang;
22
using namespace clang::interp;
23
24
Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}
25
26
Context::~Context() {}
27
28
bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
29
assert(Stk.empty());
30
Function *Func = P->getFunction(FD);
31
if (!Func || !Func->hasBody())
32
Func = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD);
33
34
if (!Func)
35
return false;
36
37
APValue DummyResult;
38
if (!Run(Parent, Func, DummyResult))
39
return false;
40
41
return Func->isConstexpr();
42
}
43
44
bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
45
++EvalID;
46
bool Recursing = !Stk.empty();
47
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
48
49
auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());
50
51
if (Res.isInvalid()) {
52
C.cleanup();
53
Stk.clear();
54
return false;
55
}
56
57
if (!Recursing) {
58
assert(Stk.empty());
59
#ifndef NDEBUG
60
// Make sure we don't rely on some value being still alive in
61
// InterpStack memory.
62
Stk.clear();
63
#endif
64
}
65
66
Result = Res.toAPValue();
67
68
return true;
69
}
70
71
bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) {
72
++EvalID;
73
bool Recursing = !Stk.empty();
74
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
75
76
auto Res = C.interpretExpr(E);
77
if (Res.isInvalid()) {
78
C.cleanup();
79
Stk.clear();
80
return false;
81
}
82
83
if (!Recursing) {
84
assert(Stk.empty());
85
#ifndef NDEBUG
86
// Make sure we don't rely on some value being still alive in
87
// InterpStack memory.
88
Stk.clear();
89
#endif
90
}
91
92
Result = Res.toAPValue();
93
return true;
94
}
95
96
bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
97
APValue &Result) {
98
++EvalID;
99
bool Recursing = !Stk.empty();
100
Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
101
102
bool CheckGlobalInitialized =
103
shouldBeGloballyIndexed(VD) &&
104
(VD->getType()->isRecordType() || VD->getType()->isArrayType());
105
auto Res = C.interpretDecl(VD, CheckGlobalInitialized);
106
if (Res.isInvalid()) {
107
C.cleanup();
108
Stk.clear();
109
return false;
110
}
111
112
if (!Recursing) {
113
assert(Stk.empty());
114
#ifndef NDEBUG
115
// Make sure we don't rely on some value being still alive in
116
// InterpStack memory.
117
Stk.clear();
118
#endif
119
}
120
121
Result = Res.toAPValue();
122
return true;
123
}
124
125
const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
126
127
std::optional<PrimType> Context::classify(QualType T) const {
128
if (T->isBooleanType())
129
return PT_Bool;
130
131
// We map these to primitive arrays.
132
if (T->isAnyComplexType() || T->isVectorType())
133
return std::nullopt;
134
135
if (T->isSignedIntegerOrEnumerationType()) {
136
switch (Ctx.getIntWidth(T)) {
137
case 64:
138
return PT_Sint64;
139
case 32:
140
return PT_Sint32;
141
case 16:
142
return PT_Sint16;
143
case 8:
144
return PT_Sint8;
145
default:
146
return PT_IntAPS;
147
}
148
}
149
150
if (T->isUnsignedIntegerOrEnumerationType()) {
151
switch (Ctx.getIntWidth(T)) {
152
case 64:
153
return PT_Uint64;
154
case 32:
155
return PT_Uint32;
156
case 16:
157
return PT_Uint16;
158
case 8:
159
return PT_Uint8;
160
default:
161
return PT_IntAP;
162
}
163
}
164
165
if (T->isNullPtrType())
166
return PT_Ptr;
167
168
if (T->isFloatingType())
169
return PT_Float;
170
171
if (T->isSpecificBuiltinType(BuiltinType::BoundMember) ||
172
T->isMemberPointerType())
173
return PT_MemberPtr;
174
175
if (T->isFunctionPointerType() || T->isFunctionReferenceType() ||
176
T->isFunctionType())
177
return PT_FnPtr;
178
179
if (T->isReferenceType() || T->isPointerType() ||
180
T->isObjCObjectPointerType())
181
return PT_Ptr;
182
183
if (const auto *AT = T->getAs<AtomicType>())
184
return classify(AT->getValueType());
185
186
if (const auto *DT = dyn_cast<DecltypeType>(T))
187
return classify(DT->getUnderlyingType());
188
189
return std::nullopt;
190
}
191
192
unsigned Context::getCharBit() const {
193
return Ctx.getTargetInfo().getCharWidth();
194
}
195
196
/// Simple wrapper around getFloatTypeSemantics() to make code a
197
/// little shorter.
198
const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
199
return Ctx.getFloatTypeSemantics(T);
200
}
201
202
bool Context::Run(State &Parent, const Function *Func, APValue &Result) {
203
204
{
205
InterpState State(Parent, *P, Stk, *this);
206
State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
207
Func->getArgSize());
208
if (Interpret(State, Result)) {
209
assert(Stk.empty());
210
return true;
211
}
212
213
// State gets destroyed here, so the Stk.clear() below doesn't accidentally
214
// remove values the State's destructor might access.
215
}
216
217
Stk.clear();
218
return false;
219
}
220
221
// TODO: Virtual bases?
222
const CXXMethodDecl *
223
Context::getOverridingFunction(const CXXRecordDecl *DynamicDecl,
224
const CXXRecordDecl *StaticDecl,
225
const CXXMethodDecl *InitialFunction) const {
226
assert(DynamicDecl);
227
assert(StaticDecl);
228
assert(InitialFunction);
229
230
const CXXRecordDecl *CurRecord = DynamicDecl;
231
const CXXMethodDecl *FoundFunction = InitialFunction;
232
for (;;) {
233
const CXXMethodDecl *Overrider =
234
FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false);
235
if (Overrider)
236
return Overrider;
237
238
// Common case of only one base class.
239
if (CurRecord->getNumBases() == 1) {
240
CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl();
241
continue;
242
}
243
244
// Otherwise, go to the base class that will lead to the StaticDecl.
245
for (const CXXBaseSpecifier &Spec : CurRecord->bases()) {
246
const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();
247
if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {
248
CurRecord = Base;
249
break;
250
}
251
}
252
}
253
254
llvm_unreachable(
255
"Couldn't find an overriding function in the class hierarchy?");
256
return nullptr;
257
}
258
259
const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {
260
assert(FD);
261
const Function *Func = P->getFunction(FD);
262
bool IsBeingCompiled = Func && Func->isDefined() && !Func->isFullyCompiled();
263
bool WasNotDefined = Func && !Func->isConstexpr() && !Func->isDefined();
264
265
if (IsBeingCompiled)
266
return Func;
267
268
if (!Func || WasNotDefined) {
269
if (auto F = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD))
270
Func = F;
271
}
272
273
return Func;
274
}
275
276
unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,
277
const RecordDecl *DerivedDecl) const {
278
assert(BaseDecl);
279
assert(DerivedDecl);
280
const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);
281
const RecordDecl *CurDecl = DerivedDecl;
282
const Record *CurRecord = P->getOrCreateRecord(CurDecl);
283
assert(CurDecl && FinalDecl);
284
285
unsigned OffsetSum = 0;
286
for (;;) {
287
assert(CurRecord->getNumBases() > 0);
288
// One level up
289
for (const Record::Base &B : CurRecord->bases()) {
290
const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);
291
292
if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {
293
OffsetSum += B.Offset;
294
CurRecord = B.R;
295
CurDecl = BaseDecl;
296
break;
297
}
298
}
299
if (CurDecl == FinalDecl)
300
break;
301
}
302
303
assert(OffsetSum > 0);
304
return OffsetSum;
305
}
306
307
const Record *Context::getRecord(const RecordDecl *D) const {
308
return P->getOrCreateRecord(D);
309
}
310
311