/src/llvm-project/clang/lib/AST/Interp/ByteCodeExprGen.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- ByteCodeExprGen.h - Code generator for expressions -----*- 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 constexpr bytecode compiler. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H |
14 | | #define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H |
15 | | |
16 | | #include "ByteCodeEmitter.h" |
17 | | #include "EvalEmitter.h" |
18 | | #include "Pointer.h" |
19 | | #include "PrimType.h" |
20 | | #include "Record.h" |
21 | | #include "clang/AST/Decl.h" |
22 | | #include "clang/AST/Expr.h" |
23 | | #include "clang/AST/StmtVisitor.h" |
24 | | #include "clang/Basic/TargetInfo.h" |
25 | | |
26 | | namespace clang { |
27 | | class QualType; |
28 | | |
29 | | namespace interp { |
30 | | |
31 | | template <class Emitter> class LocalScope; |
32 | | template <class Emitter> class DestructorScope; |
33 | | template <class Emitter> class RecordScope; |
34 | | template <class Emitter> class VariableScope; |
35 | | template <class Emitter> class DeclScope; |
36 | | template <class Emitter> class OptionScope; |
37 | | template <class Emitter> class ArrayIndexScope; |
38 | | template <class Emitter> class SourceLocScope; |
39 | | |
40 | | /// Compilation context for expressions. |
41 | | template <class Emitter> |
42 | | class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>, |
43 | | public Emitter { |
44 | | protected: |
45 | | // Aliases for types defined in the emitter. |
46 | | using LabelTy = typename Emitter::LabelTy; |
47 | | using AddrTy = typename Emitter::AddrTy; |
48 | | |
49 | | /// Current compilation context. |
50 | | Context &Ctx; |
51 | | /// Program to link to. |
52 | | Program &P; |
53 | | |
54 | | public: |
55 | | /// Initializes the compiler and the backend emitter. |
56 | | template <typename... Tys> |
57 | | ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args) |
58 | 0 | : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {} Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::ByteCodeExprGen<>(clang::interp::Context&, clang::interp::Program&) Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::ByteCodeExprGen<clang::interp::State&, clang::interp::InterpStack&, clang::APValue&>(clang::interp::Context&, clang::interp::Program&, clang::interp::State&, clang::interp::InterpStack&, clang::APValue&) |
59 | | |
60 | | // Expression visitors - result returned on interp stack. |
61 | | bool VisitCastExpr(const CastExpr *E); |
62 | | bool VisitIntegerLiteral(const IntegerLiteral *E); |
63 | | bool VisitFloatingLiteral(const FloatingLiteral *E); |
64 | | bool VisitParenExpr(const ParenExpr *E); |
65 | | bool VisitBinaryOperator(const BinaryOperator *E); |
66 | | bool VisitLogicalBinOp(const BinaryOperator *E); |
67 | | bool VisitPointerArithBinOp(const BinaryOperator *E); |
68 | | bool VisitComplexBinOp(const BinaryOperator *E); |
69 | | bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E); |
70 | | bool VisitCallExpr(const CallExpr *E); |
71 | | bool VisitBuiltinCallExpr(const CallExpr *E); |
72 | | bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E); |
73 | | bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E); |
74 | | bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E); |
75 | | bool VisitGNUNullExpr(const GNUNullExpr *E); |
76 | | bool VisitCXXThisExpr(const CXXThisExpr *E); |
77 | | bool VisitUnaryOperator(const UnaryOperator *E); |
78 | | bool VisitDeclRefExpr(const DeclRefExpr *E); |
79 | | bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E); |
80 | | bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E); |
81 | | bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); |
82 | | bool VisitInitListExpr(const InitListExpr *E); |
83 | | bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E); |
84 | | bool VisitConstantExpr(const ConstantExpr *E); |
85 | | bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); |
86 | | bool VisitMemberExpr(const MemberExpr *E); |
87 | | bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E); |
88 | | bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E); |
89 | | bool VisitOpaqueValueExpr(const OpaqueValueExpr *E); |
90 | | bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E); |
91 | | bool VisitStringLiteral(const StringLiteral *E); |
92 | | bool VisitCharacterLiteral(const CharacterLiteral *E); |
93 | | bool VisitCompoundAssignOperator(const CompoundAssignOperator *E); |
94 | | bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E); |
95 | | bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E); |
96 | | bool VisitExprWithCleanups(const ExprWithCleanups *E); |
97 | | bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); |
98 | | bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E); |
99 | | bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); |
100 | | bool VisitTypeTraitExpr(const TypeTraitExpr *E); |
101 | | bool VisitLambdaExpr(const LambdaExpr *E); |
102 | | bool VisitPredefinedExpr(const PredefinedExpr *E); |
103 | | bool VisitCXXThrowExpr(const CXXThrowExpr *E); |
104 | | bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E); |
105 | | bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E); |
106 | | bool VisitCXXConstructExpr(const CXXConstructExpr *E); |
107 | | bool VisitSourceLocExpr(const SourceLocExpr *E); |
108 | | bool VisitOffsetOfExpr(const OffsetOfExpr *E); |
109 | | bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E); |
110 | | bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); |
111 | | |
112 | | protected: |
113 | | bool visitExpr(const Expr *E) override; |
114 | | bool visitDecl(const VarDecl *VD) override; |
115 | | |
116 | | protected: |
117 | | /// Emits scope cleanup instructions. |
118 | | void emitCleanup(); |
119 | | |
120 | | /// Returns a record type from a record or pointer type. |
121 | | const RecordType *getRecordTy(QualType Ty); |
122 | | |
123 | | /// Returns a record from a record or pointer type. |
124 | | Record *getRecord(QualType Ty); |
125 | | Record *getRecord(const RecordDecl *RD); |
126 | | |
127 | | // Returns a function for the given FunctionDecl. |
128 | | // If the function does not exist yet, it is compiled. |
129 | | const Function *getFunction(const FunctionDecl *FD); |
130 | | |
131 | | /// Classifies a type. |
132 | 0 | std::optional<PrimType> classify(const Expr *E) const { |
133 | 0 | if (E->isGLValue()) { |
134 | 0 | if (E->getType()->isFunctionType()) |
135 | 0 | return PT_FnPtr; |
136 | 0 | return PT_Ptr; |
137 | 0 | } |
138 | | |
139 | 0 | return classify(E->getType()); |
140 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classify(clang::Expr const*) const Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classify(clang::Expr const*) const |
141 | 0 | std::optional<PrimType> classify(QualType Ty) const { |
142 | 0 | return Ctx.classify(Ty); |
143 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classify(clang::QualType) const Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classify(clang::QualType) const |
144 | | |
145 | | /// Classifies a known primitive type |
146 | 0 | PrimType classifyPrim(QualType Ty) const { |
147 | 0 | if (auto T = classify(Ty)) { |
148 | 0 | return *T; |
149 | 0 | } |
150 | 0 | llvm_unreachable("not a primitive type"); |
151 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classifyPrim(clang::QualType) const Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classifyPrim(clang::QualType) const |
152 | | /// Evaluates an expression and places the result on the stack. If the |
153 | | /// expression is of composite type, a local variable will be created |
154 | | /// and a pointer to said variable will be placed on the stack. |
155 | | bool visit(const Expr *E); |
156 | | /// Compiles an initializer. This is like visit() but it will never |
157 | | /// create a variable and instead rely on a variable already having |
158 | | /// been created. visitInitializer() then relies on a pointer to this |
159 | | /// variable being on top of the stack. |
160 | | bool visitInitializer(const Expr *E); |
161 | | /// Evaluates an expression for side effects and discards the result. |
162 | | bool discard(const Expr *E); |
163 | | /// Just pass evaluation on to \p E. This leaves all the parsing flags |
164 | | /// intact. |
165 | | bool delegate(const Expr *E); |
166 | | |
167 | | /// Creates and initializes a variable from the given decl. |
168 | | bool visitVarDecl(const VarDecl *VD); |
169 | | /// Visit an APValue. |
170 | | bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E); |
171 | | |
172 | | /// Visits an expression and converts it to a boolean. |
173 | | bool visitBool(const Expr *E); |
174 | | |
175 | | /// Visits an initializer for a local. |
176 | 0 | bool visitLocalInitializer(const Expr *Init, unsigned I) { |
177 | 0 | if (!this->emitGetPtrLocal(I, Init)) |
178 | 0 | return false; |
179 | | |
180 | 0 | if (!visitInitializer(Init)) |
181 | 0 | return false; |
182 | | |
183 | 0 | return this->emitPopPtr(Init); |
184 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int) Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitLocalInitializer(clang::Expr const*, unsigned int) |
185 | | |
186 | | /// Visits an initializer for a global. |
187 | 0 | bool visitGlobalInitializer(const Expr *Init, unsigned I) { |
188 | 0 | if (!this->emitGetPtrGlobal(I, Init)) |
189 | 0 | return false; |
190 | | |
191 | 0 | if (!visitInitializer(Init)) |
192 | 0 | return false; |
193 | | |
194 | 0 | if ((Init->getType()->isArrayType() || Init->getType()->isRecordType()) && |
195 | 0 | !this->emitCheckGlobalCtor(Init)) |
196 | 0 | return false; |
197 | | |
198 | 0 | return this->emitPopPtr(Init); |
199 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int) Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitGlobalInitializer(clang::Expr const*, unsigned int) |
200 | | |
201 | | /// Visits a delegated initializer. |
202 | 0 | bool visitThisInitializer(const Expr *I) { |
203 | 0 | if (!this->emitThis(I)) |
204 | 0 | return false; |
205 | | |
206 | 0 | if (!visitInitializer(I)) |
207 | 0 | return false; |
208 | | |
209 | 0 | return this->emitPopPtr(I); |
210 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::visitThisInitializer(clang::Expr const*) Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::visitThisInitializer(clang::Expr const*) |
211 | | |
212 | | bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *E); |
213 | | bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init); |
214 | | |
215 | | /// Creates a local primitive value. |
216 | | unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst, |
217 | | bool IsExtended = false); |
218 | | |
219 | | /// Allocates a space storing a local given its type. |
220 | | std::optional<unsigned> allocateLocal(DeclTy &&Decl, bool IsExtended = false); |
221 | | |
222 | | private: |
223 | | friend class VariableScope<Emitter>; |
224 | | friend class LocalScope<Emitter>; |
225 | | friend class DestructorScope<Emitter>; |
226 | | friend class RecordScope<Emitter>; |
227 | | friend class DeclScope<Emitter>; |
228 | | friend class OptionScope<Emitter>; |
229 | | friend class ArrayIndexScope<Emitter>; |
230 | | friend class SourceLocScope<Emitter>; |
231 | | |
232 | | /// Emits a zero initializer. |
233 | | bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E); |
234 | | bool visitZeroRecordInitializer(const Record *R, const Expr *E); |
235 | | |
236 | | enum class DerefKind { |
237 | | /// Value is read and pushed to stack. |
238 | | Read, |
239 | | /// Direct method generates a value which is written. Returns pointer. |
240 | | Write, |
241 | | /// Direct method receives the value, pushes mutated value. Returns pointer. |
242 | | ReadWrite, |
243 | | }; |
244 | | |
245 | | /// Method to directly load a value. If the value can be fetched directly, |
246 | | /// the direct handler is called. Otherwise, a pointer is left on the stack |
247 | | /// and the indirect handler is expected to operate on that. |
248 | | bool dereference(const Expr *LV, DerefKind AK, |
249 | | llvm::function_ref<bool(PrimType)> Direct, |
250 | | llvm::function_ref<bool(PrimType)> Indirect); |
251 | | bool dereferenceParam(const Expr *LV, PrimType T, const ParmVarDecl *PD, |
252 | | DerefKind AK, |
253 | | llvm::function_ref<bool(PrimType)> Direct, |
254 | | llvm::function_ref<bool(PrimType)> Indirect); |
255 | | bool dereferenceVar(const Expr *LV, PrimType T, const VarDecl *PD, |
256 | | DerefKind AK, llvm::function_ref<bool(PrimType)> Direct, |
257 | | llvm::function_ref<bool(PrimType)> Indirect); |
258 | | |
259 | | /// Emits an APSInt constant. |
260 | | bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E); |
261 | | bool emitConst(const llvm::APSInt &Value, const Expr *E); |
262 | 0 | bool emitConst(const llvm::APInt &Value, const Expr *E) { |
263 | 0 | return emitConst(static_cast<llvm::APSInt>(Value), E); |
264 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::emitConst(llvm::APInt const&, clang::Expr const*) Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::emitConst(llvm::APInt const&, clang::Expr const*) |
265 | | |
266 | | /// Emits an integer constant. |
267 | | template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E); |
268 | | template <typename T> bool emitConst(T Value, const Expr *E); |
269 | | |
270 | | /// Returns the CXXRecordDecl for the type of the given expression, |
271 | | /// or nullptr if no such decl exists. |
272 | 0 | const CXXRecordDecl *getRecordDecl(const Expr *E) const { |
273 | 0 | QualType T = E->getType(); |
274 | 0 | if (const auto *RD = T->getPointeeCXXRecordDecl()) |
275 | 0 | return RD; |
276 | 0 | return T->getAsCXXRecordDecl(); |
277 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::getRecordDecl(clang::Expr const*) const Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::getRecordDecl(clang::Expr const*) const |
278 | | |
279 | 0 | llvm::RoundingMode getRoundingMode(const Expr *E) const { |
280 | 0 | FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts()); |
281 | |
|
282 | 0 | if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) |
283 | 0 | return llvm::RoundingMode::NearestTiesToEven; |
284 | | |
285 | 0 | return FPO.getRoundingMode(); |
286 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::getRoundingMode(clang::Expr const*) const Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::getRoundingMode(clang::Expr const*) const |
287 | | |
288 | | bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E); |
289 | 0 | std::optional<PrimType> classifyComplexElementType(QualType T) const { |
290 | 0 | assert(T->isAnyComplexType()); |
291 | | |
292 | 0 | QualType ElemType = T->getAs<ComplexType>()->getElementType(); |
293 | |
|
294 | 0 | return this->classify(ElemType); |
295 | 0 | } Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>::classifyComplexElementType(clang::QualType) const Unexecuted instantiation: clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>::classifyComplexElementType(clang::QualType) const |
296 | | |
297 | | bool emitRecordDestruction(const Descriptor *Desc); |
298 | | unsigned collectBaseOffset(const RecordType *BaseType, |
299 | | const RecordType *DerivedType); |
300 | | |
301 | | protected: |
302 | | /// Variable to storage mapping. |
303 | | llvm::DenseMap<const ValueDecl *, Scope::Local> Locals; |
304 | | |
305 | | /// OpaqueValueExpr to location mapping. |
306 | | llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs; |
307 | | |
308 | | /// Current scope. |
309 | | VariableScope<Emitter> *VarScope = nullptr; |
310 | | |
311 | | /// Current argument index. Needed to emit ArrayInitIndexExpr. |
312 | | std::optional<uint64_t> ArrayIndex; |
313 | | |
314 | | /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr. |
315 | | const Expr *SourceLocDefaultExpr = nullptr; |
316 | | |
317 | | /// Flag indicating if return value is to be discarded. |
318 | | bool DiscardResult = false; |
319 | | |
320 | | /// Flag inidicating if we're initializing an already created |
321 | | /// variable. This is set in visitInitializer(). |
322 | | bool Initializing = false; |
323 | | |
324 | | /// Flag indicating if we're initializing a global variable. |
325 | | bool GlobalDecl = false; |
326 | | }; |
327 | | |
328 | | extern template class ByteCodeExprGen<ByteCodeEmitter>; |
329 | | extern template class ByteCodeExprGen<EvalEmitter>; |
330 | | |
331 | | /// Scope chain managing the variable lifetimes. |
332 | | template <class Emitter> class VariableScope { |
333 | | public: |
334 | | VariableScope(ByteCodeExprGen<Emitter> *Ctx) |
335 | 0 | : Ctx(Ctx), Parent(Ctx->VarScope) { |
336 | 0 | Ctx->VarScope = this; |
337 | 0 | } Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::VariableScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*) Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::VariableScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*) |
338 | | |
339 | 0 | virtual ~VariableScope() { Ctx->VarScope = this->Parent; } Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::~VariableScope() Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::~VariableScope() |
340 | | |
341 | 0 | void add(const Scope::Local &Local, bool IsExtended) { |
342 | 0 | if (IsExtended) |
343 | 0 | this->addExtended(Local); |
344 | 0 | else |
345 | 0 | this->addLocal(Local); |
346 | 0 | } Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::add(clang::interp::Scope::Local const&, bool) Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::add(clang::interp::Scope::Local const&, bool) |
347 | | |
348 | 0 | virtual void addLocal(const Scope::Local &Local) { |
349 | 0 | if (this->Parent) |
350 | 0 | this->Parent->addLocal(Local); |
351 | 0 | } Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::addLocal(clang::interp::Scope::Local const&) Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::addLocal(clang::interp::Scope::Local const&) |
352 | | |
353 | 0 | virtual void addExtended(const Scope::Local &Local) { |
354 | 0 | if (this->Parent) |
355 | 0 | this->Parent->addExtended(Local); |
356 | 0 | } Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&) Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&) |
357 | | |
358 | 0 | virtual void emitDestruction() {} Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::emitDestruction() Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::emitDestruction() |
359 | 0 | virtual void emitDestructors() {} Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::emitDestructors() Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::emitDestructors() |
360 | 0 | VariableScope *getParent() const { return Parent; } Unexecuted instantiation: clang::interp::VariableScope<clang::interp::ByteCodeEmitter>::getParent() const Unexecuted instantiation: clang::interp::VariableScope<clang::interp::EvalEmitter>::getParent() const |
361 | | |
362 | | protected: |
363 | | /// ByteCodeExprGen instance. |
364 | | ByteCodeExprGen<Emitter> *Ctx; |
365 | | /// Link to the parent scope. |
366 | | VariableScope *Parent; |
367 | | }; |
368 | | |
369 | | /// Generic scope for local variables. |
370 | | template <class Emitter> class LocalScope : public VariableScope<Emitter> { |
371 | | public: |
372 | 0 | LocalScope(ByteCodeExprGen<Emitter> *Ctx) : VariableScope<Emitter>(Ctx) {} Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::LocalScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*) Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::LocalScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*) |
373 | | |
374 | | /// Emit a Destroy op for this scope. |
375 | 0 | ~LocalScope() override { |
376 | 0 | if (!Idx) |
377 | 0 | return; |
378 | 0 | this->Ctx->emitDestroy(*Idx, SourceInfo{}); |
379 | 0 | } Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::~LocalScope() Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::~LocalScope() |
380 | | |
381 | | /// Overriden to support explicit destruction. |
382 | 0 | void emitDestruction() override { |
383 | 0 | if (!Idx) |
384 | 0 | return; |
385 | 0 | this->emitDestructors(); |
386 | 0 | this->Ctx->emitDestroy(*Idx, SourceInfo{}); |
387 | 0 | this->Idx = std::nullopt; |
388 | 0 | } Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::emitDestruction() Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::emitDestruction() |
389 | | |
390 | 0 | void addLocal(const Scope::Local &Local) override { |
391 | 0 | if (!Idx) { |
392 | 0 | Idx = this->Ctx->Descriptors.size(); |
393 | 0 | this->Ctx->Descriptors.emplace_back(); |
394 | 0 | } |
395 | |
|
396 | 0 | this->Ctx->Descriptors[*Idx].emplace_back(Local); |
397 | 0 | } Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::addLocal(clang::interp::Scope::Local const&) Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::addLocal(clang::interp::Scope::Local const&) |
398 | | |
399 | 0 | void emitDestructors() override { |
400 | 0 | if (!Idx) |
401 | 0 | return; |
402 | | // Emit destructor calls for local variables of record |
403 | | // type with a destructor. |
404 | 0 | for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) { |
405 | 0 | if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) { |
406 | 0 | this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{}); |
407 | 0 | this->Ctx->emitRecordDestruction(Local.Desc); |
408 | 0 | } |
409 | 0 | } |
410 | 0 | } Unexecuted instantiation: clang::interp::LocalScope<clang::interp::ByteCodeEmitter>::emitDestructors() Unexecuted instantiation: clang::interp::LocalScope<clang::interp::EvalEmitter>::emitDestructors() |
411 | | |
412 | | /// Index of the scope in the chain. |
413 | | std::optional<unsigned> Idx; |
414 | | }; |
415 | | |
416 | | /// Emits the destructors of the variables of \param OtherScope |
417 | | /// when this scope is destroyed. Does not create a Scope in the bytecode at |
418 | | /// all, this is just a RAII object to emit destructors. |
419 | | template <class Emitter> class DestructorScope final { |
420 | | public: |
421 | 0 | DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {} Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::ByteCodeEmitter>::DestructorScope(clang::interp::LocalScope<clang::interp::ByteCodeEmitter>&) Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::EvalEmitter>::DestructorScope(clang::interp::LocalScope<clang::interp::EvalEmitter>&) |
422 | | |
423 | 0 | ~DestructorScope() { OtherScope.emitDestructors(); } Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::ByteCodeEmitter>::~DestructorScope() Unexecuted instantiation: clang::interp::DestructorScope<clang::interp::EvalEmitter>::~DestructorScope() |
424 | | |
425 | | private: |
426 | | LocalScope<Emitter> &OtherScope; |
427 | | }; |
428 | | |
429 | | /// Like a regular LocalScope, except that the destructors of all local |
430 | | /// variables are automatically emitted when the AutoScope is destroyed. |
431 | | template <class Emitter> class AutoScope : public LocalScope<Emitter> { |
432 | | public: |
433 | | AutoScope(ByteCodeExprGen<Emitter> *Ctx) |
434 | 0 | : LocalScope<Emitter>(Ctx), DS(*this) {} Unexecuted instantiation: clang::interp::AutoScope<clang::interp::ByteCodeEmitter>::AutoScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*) Unexecuted instantiation: clang::interp::AutoScope<clang::interp::EvalEmitter>::AutoScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*) |
435 | | |
436 | | private: |
437 | | DestructorScope<Emitter> DS; |
438 | | }; |
439 | | |
440 | | /// Scope for storage declared in a compound statement. |
441 | | template <class Emitter> class BlockScope final : public AutoScope<Emitter> { |
442 | | public: |
443 | 0 | BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} Unexecuted instantiation: clang::interp::BlockScope<clang::interp::ByteCodeEmitter>::BlockScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*) Unexecuted instantiation: clang::interp::BlockScope<clang::interp::EvalEmitter>::BlockScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*) |
444 | | |
445 | 0 | void addExtended(const Scope::Local &Local) override { |
446 | | // If we to this point, just add the variable as a normal local |
447 | | // variable. It will be destroyed at the end of the block just |
448 | | // like all others. |
449 | 0 | this->addLocal(Local); |
450 | 0 | } Unexecuted instantiation: clang::interp::BlockScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&) Unexecuted instantiation: clang::interp::BlockScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&) |
451 | | }; |
452 | | |
453 | | /// Expression scope which tracks potentially lifetime extended |
454 | | /// temporaries which are hoisted to the parent scope on exit. |
455 | | template <class Emitter> class ExprScope final : public AutoScope<Emitter> { |
456 | | public: |
457 | 0 | ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {} Unexecuted instantiation: clang::interp::ExprScope<clang::interp::ByteCodeEmitter>::ExprScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*) Unexecuted instantiation: clang::interp::ExprScope<clang::interp::EvalEmitter>::ExprScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*) |
458 | | |
459 | 0 | void addExtended(const Scope::Local &Local) override { |
460 | 0 | if (this->Parent) |
461 | 0 | this->Parent->addLocal(Local); |
462 | 0 | } Unexecuted instantiation: clang::interp::ExprScope<clang::interp::ByteCodeEmitter>::addExtended(clang::interp::Scope::Local const&) Unexecuted instantiation: clang::interp::ExprScope<clang::interp::EvalEmitter>::addExtended(clang::interp::Scope::Local const&) |
463 | | }; |
464 | | |
465 | | template <class Emitter> class ArrayIndexScope final { |
466 | | public: |
467 | 0 | ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) { |
468 | 0 | OldArrayIndex = Ctx->ArrayIndex; |
469 | 0 | Ctx->ArrayIndex = Index; |
470 | 0 | } Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::ByteCodeEmitter>::ArrayIndexScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*, unsigned long) Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::EvalEmitter>::ArrayIndexScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*, unsigned long) |
471 | | |
472 | 0 | ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; } Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::ByteCodeEmitter>::~ArrayIndexScope() Unexecuted instantiation: clang::interp::ArrayIndexScope<clang::interp::EvalEmitter>::~ArrayIndexScope() |
473 | | |
474 | | private: |
475 | | ByteCodeExprGen<Emitter> *Ctx; |
476 | | std::optional<uint64_t> OldArrayIndex; |
477 | | }; |
478 | | |
479 | | template <class Emitter> class SourceLocScope final { |
480 | | public: |
481 | | SourceLocScope(ByteCodeExprGen<Emitter> *Ctx, const Expr *DefaultExpr) |
482 | 0 | : Ctx(Ctx) { |
483 | 0 | assert(DefaultExpr); |
484 | | // We only switch if the current SourceLocDefaultExpr is null. |
485 | 0 | if (!Ctx->SourceLocDefaultExpr) { |
486 | 0 | Enabled = true; |
487 | 0 | Ctx->SourceLocDefaultExpr = DefaultExpr; |
488 | 0 | } |
489 | 0 | } Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::ByteCodeEmitter>::SourceLocScope(clang::interp::ByteCodeExprGen<clang::interp::ByteCodeEmitter>*, clang::Expr const*) Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::EvalEmitter>::SourceLocScope(clang::interp::ByteCodeExprGen<clang::interp::EvalEmitter>*, clang::Expr const*) |
490 | | |
491 | 0 | ~SourceLocScope() { |
492 | 0 | if (Enabled) |
493 | 0 | Ctx->SourceLocDefaultExpr = nullptr; |
494 | 0 | } Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::ByteCodeEmitter>::~SourceLocScope() Unexecuted instantiation: clang::interp::SourceLocScope<clang::interp::EvalEmitter>::~SourceLocScope() |
495 | | |
496 | | private: |
497 | | ByteCodeExprGen<Emitter> *Ctx; |
498 | | bool Enabled = false; |
499 | | }; |
500 | | |
501 | | } // namespace interp |
502 | | } // namespace clang |
503 | | |
504 | | #endif |