clang 20.0.0git
Context.cpp
Go to the documentation of this file.
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"
20
21using namespace clang;
22using namespace clang::interp;
23
24Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {}
25
27
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 if (!Run(Parent, Func))
38 return false;
39
40 return Func->isConstexpr();
41}
42
44 ++EvalID;
45 bool Recursing = !Stk.empty();
46 size_t StackSizeBefore = Stk.size();
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.clearTo(StackSizeBefore);
54 return false;
55 }
56
57 if (!Recursing) {
58 assert(Stk.empty());
59 C.cleanup();
60#ifndef NDEBUG
61 // Make sure we don't rely on some value being still alive in
62 // InterpStack memory.
63 Stk.clearTo(StackSizeBefore);
64#endif
65 }
66
67 Result = Res.toAPValue();
68
69 return true;
70}
71
73 ConstantExprKind Kind) {
74 ++EvalID;
75 bool Recursing = !Stk.empty();
76 size_t StackSizeBefore = Stk.size();
77 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
78
79 auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/false,
80 /*DestroyToplevelScope=*/true);
81 if (Res.isInvalid()) {
82 C.cleanup();
83 Stk.clearTo(StackSizeBefore);
84 return false;
85 }
86
87 if (!Recursing) {
88 assert(Stk.empty());
89 C.cleanup();
90#ifndef NDEBUG
91 // Make sure we don't rely on some value being still alive in
92 // InterpStack memory.
93 Stk.clearTo(StackSizeBefore);
94#endif
95 }
96
97 Result = Res.toAPValue();
98 return true;
99}
100
102 APValue &Result) {
103 ++EvalID;
104 bool Recursing = !Stk.empty();
105 size_t StackSizeBefore = Stk.size();
106 Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
107
110 (VD->getType()->isRecordType() || VD->getType()->isArrayType());
111 auto Res = C.interpretDecl(VD, CheckGlobalInitialized);
112 if (Res.isInvalid()) {
113 C.cleanup();
114 Stk.clearTo(StackSizeBefore);
115
116 return false;
117 }
118
119 if (!Recursing) {
120 assert(Stk.empty());
121 C.cleanup();
122#ifndef NDEBUG
123 // Make sure we don't rely on some value being still alive in
124 // InterpStack memory.
125 Stk.clearTo(StackSizeBefore);
126#endif
127 }
128
129 Result = Res.toAPValue();
130 return true;
131}
132
133const LangOptions &Context::getLangOpts() const { return Ctx.getLangOpts(); }
134
135std::optional<PrimType> Context::classify(QualType T) const {
136 if (T->isBooleanType())
137 return PT_Bool;
138
139 // We map these to primitive arrays.
140 if (T->isAnyComplexType() || T->isVectorType())
141 return std::nullopt;
142
144 switch (Ctx.getIntWidth(T)) {
145 case 64:
146 return PT_Sint64;
147 case 32:
148 return PT_Sint32;
149 case 16:
150 return PT_Sint16;
151 case 8:
152 return PT_Sint8;
153 default:
154 return PT_IntAPS;
155 }
156 }
157
159 switch (Ctx.getIntWidth(T)) {
160 case 64:
161 return PT_Uint64;
162 case 32:
163 return PT_Uint32;
164 case 16:
165 return PT_Uint16;
166 case 8:
167 return PT_Uint8;
168 case 1:
169 // Might happen for enum types.
170 return PT_Bool;
171 default:
172 return PT_IntAP;
173 }
174 }
175
176 if (T->isNullPtrType())
177 return PT_Ptr;
178
179 if (T->isFloatingType())
180 return PT_Float;
181
182 if (T->isSpecificBuiltinType(BuiltinType::BoundMember) ||
184 return PT_MemberPtr;
185
188 return PT_FnPtr;
189
191 return PT_Ptr;
192
193 if (const auto *AT = T->getAs<AtomicType>())
194 return classify(AT->getValueType());
195
196 if (const auto *DT = dyn_cast<DecltypeType>(T))
197 return classify(DT->getUnderlyingType());
198
199 if (T->isFixedPointType())
200 return PT_FixedPoint;
201
202 return std::nullopt;
203}
204
205unsigned Context::getCharBit() const {
206 return Ctx.getTargetInfo().getCharWidth();
207}
208
209/// Simple wrapper around getFloatTypeSemantics() to make code a
210/// little shorter.
211const llvm::fltSemantics &Context::getFloatSemantics(QualType T) const {
212 return Ctx.getFloatTypeSemantics(T);
213}
214
215bool Context::Run(State &Parent, const Function *Func) {
216
217 {
218 InterpState State(Parent, *P, Stk, *this);
219 State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
220 Func->getArgSize());
221 if (Interpret(State)) {
222 assert(Stk.empty());
223 return true;
224 }
225
226 // State gets destroyed here, so the Stk.clear() below doesn't accidentally
227 // remove values the State's destructor might access.
228 }
229
230 Stk.clear();
231 return false;
232}
233
234// TODO: Virtual bases?
235const CXXMethodDecl *
237 const CXXRecordDecl *StaticDecl,
238 const CXXMethodDecl *InitialFunction) const {
239 assert(DynamicDecl);
240 assert(StaticDecl);
241 assert(InitialFunction);
242
243 const CXXRecordDecl *CurRecord = DynamicDecl;
244 const CXXMethodDecl *FoundFunction = InitialFunction;
245 for (;;) {
246 const CXXMethodDecl *Overrider =
247 FoundFunction->getCorrespondingMethodDeclaredInClass(CurRecord, false);
248 if (Overrider)
249 return Overrider;
250
251 // Common case of only one base class.
252 if (CurRecord->getNumBases() == 1) {
253 CurRecord = CurRecord->bases_begin()->getType()->getAsCXXRecordDecl();
254 continue;
255 }
256
257 // Otherwise, go to the base class that will lead to the StaticDecl.
258 for (const CXXBaseSpecifier &Spec : CurRecord->bases()) {
259 const CXXRecordDecl *Base = Spec.getType()->getAsCXXRecordDecl();
260 if (Base == StaticDecl || Base->isDerivedFrom(StaticDecl)) {
261 CurRecord = Base;
262 break;
263 }
264 }
265 }
266
267 llvm_unreachable(
268 "Couldn't find an overriding function in the class hierarchy?");
269 return nullptr;
270}
271
273 assert(FD);
274 const Function *Func = P->getFunction(FD);
275 bool IsBeingCompiled = Func && Func->isDefined() && !Func->isFullyCompiled();
276 bool WasNotDefined = Func && !Func->isConstexpr() && !Func->isDefined();
277
278 if (IsBeingCompiled)
279 return Func;
280
281 if (!Func || WasNotDefined) {
282 if (auto F = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD))
283 Func = F;
284 }
285
286 return Func;
287}
288
289unsigned Context::collectBaseOffset(const RecordDecl *BaseDecl,
290 const RecordDecl *DerivedDecl) const {
291 assert(BaseDecl);
292 assert(DerivedDecl);
293 const auto *FinalDecl = cast<CXXRecordDecl>(BaseDecl);
294 const RecordDecl *CurDecl = DerivedDecl;
295 const Record *CurRecord = P->getOrCreateRecord(CurDecl);
296 assert(CurDecl && FinalDecl);
297
298 unsigned OffsetSum = 0;
299 for (;;) {
300 assert(CurRecord->getNumBases() > 0);
301 // One level up
302 for (const Record::Base &B : CurRecord->bases()) {
303 const auto *BaseDecl = cast<CXXRecordDecl>(B.Decl);
304
305 if (BaseDecl == FinalDecl || BaseDecl->isDerivedFrom(FinalDecl)) {
306 OffsetSum += B.Offset;
307 CurRecord = B.R;
308 CurDecl = BaseDecl;
309 break;
310 }
311 }
312 if (CurDecl == FinalDecl)
313 break;
314 }
315
316 assert(OffsetSum > 0);
317 return OffsetSum;
318}
319
320const Record *Context::getRecord(const RecordDecl *D) const {
321 return P->getOrCreateRecord(D);
322}
NodeId Parent
Definition: ASTDiff.cpp:191
StringRef P
const Decl * D
Expr * E
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:188
unsigned getIntWidth(QualType T) const
const llvm::fltSemantics & getFloatTypeSemantics(QualType T) const
Return the APFloat 'semantics' for the specified scalar floating point type.
const LangOptions & getLangOpts() const
Definition: ASTContext.h:834
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:799
Represents a base class of a C++ class.
Definition: DeclCXX.h:146
QualType getType() const
Retrieves the type of the base class.
Definition: DeclCXX.h:249
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2078
CXXMethodDecl * getCorrespondingMethodDeclaredInClass(const CXXRecordDecl *RD, bool MayBeBase=false)
Find if RD declares a function that overrides this function, and if so, return it.
Definition: DeclCXX.cpp:2302
Represents a C++ struct/union/class.
Definition: DeclCXX.h:258
base_class_range bases()
Definition: DeclCXX.h:620
unsigned getNumBases() const
Retrieves the number of base classes of this class.
Definition: DeclCXX.h:614
base_class_iterator bases_begin()
Definition: DeclCXX.h:627
This represents one expression.
Definition: Expr.h:110
bool isGLValue() const
Definition: Expr.h:280
ConstantExprKind
Definition: Expr.h:748
Represents a function declaration or definition.
Definition: Decl.h:1935
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:499
A (possibly-)qualified type.
Definition: Type.h:929
Represents a struct/union/class.
Definition: Decl.h:4148
unsigned getCharWidth() const
Definition: TargetInfo.h:502
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
Definition: Type.cpp:1916
bool isBlockPointerType() const
Definition: Type.h:8200
bool isBooleanType() const
Definition: Type.h:8638
bool isFunctionReferenceType() const
Definition: Type.h:8233
bool isSignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is signed or an enumeration types whose underlying ty...
Definition: Type.cpp:2201
bool isUnsignedIntegerOrEnumerationType() const
Determines whether this is an integer type that is unsigned or an enumeration types whose underlying ...
Definition: Type.cpp:2251
bool isArrayType() const
Definition: Type.h:8258
bool isFunctionPointerType() const
Definition: Type.h:8226
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
Definition: Type.h:8479
bool isAnyComplexType() const
Definition: Type.h:8294
bool isFixedPointType() const
Return true if this is a fixed point type according to ISO/IEC JTC1 SC22 WG14 N1169.
Definition: Type.h:8563
bool isMemberPointerType() const
Definition: Type.h:8240
bool isPointerOrReferenceType() const
Definition: Type.h:8190
bool isFunctionType() const
Definition: Type.h:8182
bool isObjCObjectPointerType() const
Definition: Type.h:8328
bool isVectorType() const
Definition: Type.h:8298
bool isFloatingType() const
Definition: Type.cpp:2283
const T * getAs() const
Member-template getAs<specific type>'.
Definition: Type.h:8731
bool isNullPtrType() const
Definition: Type.h:8543
bool isRecordType() const
Definition: Type.h:8286
QualType getType() const
Definition: Decl.h:682
Represents a variable declaration or definition.
Definition: Decl.h:882
Pointer into the code segment.
Definition: Source.h:30
Compilation context for expressions.
Definition: Compiler.h:104
const LangOptions & getLangOpts() const
Returns the language options.
Definition: Context.cpp:133
~Context()
Cleans up the constexpr VM.
Definition: Context.cpp:26
Context(ASTContext &Ctx)
Initialises the constexpr VM.
Definition: Context.cpp:24
unsigned getCharBit() const
Returns CHAR_BIT.
Definition: Context.cpp:205
bool evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result)
Evaluates a toplevel initializer.
Definition: Context.cpp:101
const llvm::fltSemantics & getFloatSemantics(QualType T) const
Return the floating-point semantics for T.
Definition: Context.cpp:211
static bool shouldBeGloballyIndexed(const ValueDecl *VD)
Returns whether we should create a global variable for the given ValueDecl.
Definition: Context.h:98
unsigned collectBaseOffset(const RecordDecl *BaseDecl, const RecordDecl *DerivedDecl) const
Definition: Context.cpp:289
const Record * getRecord(const RecordDecl *D) const
Definition: Context.cpp:320
bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FnDecl)
Checks if a function is a potential constant expression.
Definition: Context.cpp:28
bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result)
Evaluates a toplevel expression as an rvalue.
Definition: Context.cpp:43
const CXXMethodDecl * getOverridingFunction(const CXXRecordDecl *DynamicDecl, const CXXRecordDecl *StaticDecl, const CXXMethodDecl *InitialFunction) const
Definition: Context.cpp:236
bool evaluate(State &Parent, const Expr *E, APValue &Result, ConstantExprKind Kind)
Like evaluateAsRvalue(), but does no implicit lvalue-to-rvalue conversion.
Definition: Context.cpp:72
std::optional< PrimType > classify(QualType T) const
Classifies a type.
Definition: Context.cpp:135
const Function * getOrCreateFunction(const FunctionDecl *FD)
Definition: Context.cpp:272
Bytecode function.
Definition: Function.h:81
Frame storing local variables.
Definition: InterpFrame.h:26
void clearTo(size_t NewSize)
Definition: InterpStack.cpp:36
void clear()
Clears the stack without calling any destructors.
Definition: InterpStack.cpp:24
size_t size() const
Returns the size of the stack in bytes.
Definition: InterpStack.h:86
bool empty() const
Returns whether the stack is empty.
Definition: InterpStack.h:93
Interpreter context.
Definition: InterpState.h:36
The program contains and links the bytecode for all functions.
Definition: Program.h:39
Structure/Class descriptor.
Definition: Record.h:25
unsigned getNumBases() const
Definition: Record.h:92
llvm::iterator_range< const_base_iter > bases() const
Definition: Record.h:88
Interface for the VM to interact with the AST walker's context.
Definition: State.h:57
Defines the clang::TargetInfo interface.
bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr)
Check if a global variable is initialized.
Definition: Interp.cpp:559
bool Interpret(InterpState &S)
Interpreter entry point.
Definition: Interp.cpp:1602
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
const FunctionProtoType * T