xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Compiler.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===--- Compiler.h - Code generator for expressions -----*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // Defines the constexpr bytecode compiler.
10*0fca6ea1SDimitry Andric //
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
14*0fca6ea1SDimitry Andric #define LLVM_CLANG_AST_INTERP_BYTECODEEXPRGEN_H
15*0fca6ea1SDimitry Andric 
16*0fca6ea1SDimitry Andric #include "ByteCodeEmitter.h"
17*0fca6ea1SDimitry Andric #include "EvalEmitter.h"
18*0fca6ea1SDimitry Andric #include "Pointer.h"
19*0fca6ea1SDimitry Andric #include "PrimType.h"
20*0fca6ea1SDimitry Andric #include "Record.h"
21*0fca6ea1SDimitry Andric #include "clang/AST/Decl.h"
22*0fca6ea1SDimitry Andric #include "clang/AST/Expr.h"
23*0fca6ea1SDimitry Andric #include "clang/AST/StmtVisitor.h"
24*0fca6ea1SDimitry Andric #include "clang/Basic/TargetInfo.h"
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric namespace clang {
27*0fca6ea1SDimitry Andric class QualType;
28*0fca6ea1SDimitry Andric 
29*0fca6ea1SDimitry Andric namespace interp {
30*0fca6ea1SDimitry Andric 
31*0fca6ea1SDimitry Andric template <class Emitter> class LocalScope;
32*0fca6ea1SDimitry Andric template <class Emitter> class DestructorScope;
33*0fca6ea1SDimitry Andric template <class Emitter> class VariableScope;
34*0fca6ea1SDimitry Andric template <class Emitter> class DeclScope;
35*0fca6ea1SDimitry Andric template <class Emitter> class InitLinkScope;
36*0fca6ea1SDimitry Andric template <class Emitter> class InitStackScope;
37*0fca6ea1SDimitry Andric template <class Emitter> class OptionScope;
38*0fca6ea1SDimitry Andric template <class Emitter> class ArrayIndexScope;
39*0fca6ea1SDimitry Andric template <class Emitter> class SourceLocScope;
40*0fca6ea1SDimitry Andric template <class Emitter> class LoopScope;
41*0fca6ea1SDimitry Andric template <class Emitter> class LabelScope;
42*0fca6ea1SDimitry Andric template <class Emitter> class SwitchScope;
43*0fca6ea1SDimitry Andric template <class Emitter> class StmtExprScope;
44*0fca6ea1SDimitry Andric 
45*0fca6ea1SDimitry Andric template <class Emitter> class Compiler;
46*0fca6ea1SDimitry Andric struct InitLink {
47*0fca6ea1SDimitry Andric public:
48*0fca6ea1SDimitry Andric   enum {
49*0fca6ea1SDimitry Andric     K_This = 0,
50*0fca6ea1SDimitry Andric     K_Field = 1,
51*0fca6ea1SDimitry Andric     K_Temp = 2,
52*0fca6ea1SDimitry Andric     K_Decl = 3,
53*0fca6ea1SDimitry Andric   };
54*0fca6ea1SDimitry Andric 
55*0fca6ea1SDimitry Andric   static InitLink This() { return InitLink{K_This}; }
56*0fca6ea1SDimitry Andric   static InitLink Field(unsigned Offset) {
57*0fca6ea1SDimitry Andric     InitLink IL{K_Field};
58*0fca6ea1SDimitry Andric     IL.Offset = Offset;
59*0fca6ea1SDimitry Andric     return IL;
60*0fca6ea1SDimitry Andric   }
61*0fca6ea1SDimitry Andric   static InitLink Temp(unsigned Offset) {
62*0fca6ea1SDimitry Andric     InitLink IL{K_Temp};
63*0fca6ea1SDimitry Andric     IL.Offset = Offset;
64*0fca6ea1SDimitry Andric     return IL;
65*0fca6ea1SDimitry Andric   }
66*0fca6ea1SDimitry Andric   static InitLink Decl(const ValueDecl *D) {
67*0fca6ea1SDimitry Andric     InitLink IL{K_Decl};
68*0fca6ea1SDimitry Andric     IL.D = D;
69*0fca6ea1SDimitry Andric     return IL;
70*0fca6ea1SDimitry Andric   }
71*0fca6ea1SDimitry Andric 
72*0fca6ea1SDimitry Andric   InitLink(uint8_t Kind) : Kind(Kind) {}
73*0fca6ea1SDimitry Andric   template <class Emitter>
74*0fca6ea1SDimitry Andric   bool emit(Compiler<Emitter> *Ctx, const Expr *E) const;
75*0fca6ea1SDimitry Andric 
76*0fca6ea1SDimitry Andric   uint32_t Kind;
77*0fca6ea1SDimitry Andric   union {
78*0fca6ea1SDimitry Andric     unsigned Offset;
79*0fca6ea1SDimitry Andric     const ValueDecl *D;
80*0fca6ea1SDimitry Andric   };
81*0fca6ea1SDimitry Andric };
82*0fca6ea1SDimitry Andric 
83*0fca6ea1SDimitry Andric /// State encapsulating if a the variable creation has been successful,
84*0fca6ea1SDimitry Andric /// unsuccessful, or no variable has been created at all.
85*0fca6ea1SDimitry Andric struct VarCreationState {
86*0fca6ea1SDimitry Andric   std::optional<bool> S = std::nullopt;
87*0fca6ea1SDimitry Andric   VarCreationState() = default;
88*0fca6ea1SDimitry Andric   VarCreationState(bool b) : S(b) {}
89*0fca6ea1SDimitry Andric   static VarCreationState NotCreated() { return VarCreationState(); }
90*0fca6ea1SDimitry Andric 
91*0fca6ea1SDimitry Andric   operator bool() const { return S && *S; }
92*0fca6ea1SDimitry Andric   bool notCreated() const { return !S; }
93*0fca6ea1SDimitry Andric };
94*0fca6ea1SDimitry Andric 
95*0fca6ea1SDimitry Andric /// Compilation context for expressions.
96*0fca6ea1SDimitry Andric template <class Emitter>
97*0fca6ea1SDimitry Andric class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
98*0fca6ea1SDimitry Andric                  public Emitter {
99*0fca6ea1SDimitry Andric protected:
100*0fca6ea1SDimitry Andric   // Aliases for types defined in the emitter.
101*0fca6ea1SDimitry Andric   using LabelTy = typename Emitter::LabelTy;
102*0fca6ea1SDimitry Andric   using AddrTy = typename Emitter::AddrTy;
103*0fca6ea1SDimitry Andric   using OptLabelTy = std::optional<LabelTy>;
104*0fca6ea1SDimitry Andric   using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
105*0fca6ea1SDimitry Andric 
106*0fca6ea1SDimitry Andric   /// Current compilation context.
107*0fca6ea1SDimitry Andric   Context &Ctx;
108*0fca6ea1SDimitry Andric   /// Program to link to.
109*0fca6ea1SDimitry Andric   Program &P;
110*0fca6ea1SDimitry Andric 
111*0fca6ea1SDimitry Andric public:
112*0fca6ea1SDimitry Andric   /// Initializes the compiler and the backend emitter.
113*0fca6ea1SDimitry Andric   template <typename... Tys>
114*0fca6ea1SDimitry Andric   Compiler(Context &Ctx, Program &P, Tys &&...Args)
115*0fca6ea1SDimitry Andric       : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
116*0fca6ea1SDimitry Andric 
117*0fca6ea1SDimitry Andric   // Expressions.
118*0fca6ea1SDimitry Andric   bool VisitCastExpr(const CastExpr *E);
119*0fca6ea1SDimitry Andric   bool VisitIntegerLiteral(const IntegerLiteral *E);
120*0fca6ea1SDimitry Andric   bool VisitFloatingLiteral(const FloatingLiteral *E);
121*0fca6ea1SDimitry Andric   bool VisitImaginaryLiteral(const ImaginaryLiteral *E);
122*0fca6ea1SDimitry Andric   bool VisitParenExpr(const ParenExpr *E);
123*0fca6ea1SDimitry Andric   bool VisitBinaryOperator(const BinaryOperator *E);
124*0fca6ea1SDimitry Andric   bool VisitLogicalBinOp(const BinaryOperator *E);
125*0fca6ea1SDimitry Andric   bool VisitPointerArithBinOp(const BinaryOperator *E);
126*0fca6ea1SDimitry Andric   bool VisitComplexBinOp(const BinaryOperator *E);
127*0fca6ea1SDimitry Andric   bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E);
128*0fca6ea1SDimitry Andric   bool VisitCallExpr(const CallExpr *E);
129*0fca6ea1SDimitry Andric   bool VisitBuiltinCallExpr(const CallExpr *E);
130*0fca6ea1SDimitry Andric   bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E);
131*0fca6ea1SDimitry Andric   bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E);
132*0fca6ea1SDimitry Andric   bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E);
133*0fca6ea1SDimitry Andric   bool VisitGNUNullExpr(const GNUNullExpr *E);
134*0fca6ea1SDimitry Andric   bool VisitCXXThisExpr(const CXXThisExpr *E);
135*0fca6ea1SDimitry Andric   bool VisitUnaryOperator(const UnaryOperator *E);
136*0fca6ea1SDimitry Andric   bool VisitComplexUnaryOperator(const UnaryOperator *E);
137*0fca6ea1SDimitry Andric   bool VisitDeclRefExpr(const DeclRefExpr *E);
138*0fca6ea1SDimitry Andric   bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E);
139*0fca6ea1SDimitry Andric   bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E);
140*0fca6ea1SDimitry Andric   bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E);
141*0fca6ea1SDimitry Andric   bool VisitInitListExpr(const InitListExpr *E);
142*0fca6ea1SDimitry Andric   bool VisitCXXParenListInitExpr(const CXXParenListInitExpr *E);
143*0fca6ea1SDimitry Andric   bool VisitConstantExpr(const ConstantExpr *E);
144*0fca6ea1SDimitry Andric   bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E);
145*0fca6ea1SDimitry Andric   bool VisitMemberExpr(const MemberExpr *E);
146*0fca6ea1SDimitry Andric   bool VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E);
147*0fca6ea1SDimitry Andric   bool VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
148*0fca6ea1SDimitry Andric   bool VisitOpaqueValueExpr(const OpaqueValueExpr *E);
149*0fca6ea1SDimitry Andric   bool VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
150*0fca6ea1SDimitry Andric   bool VisitStringLiteral(const StringLiteral *E);
151*0fca6ea1SDimitry Andric   bool VisitObjCStringLiteral(const ObjCStringLiteral *E);
152*0fca6ea1SDimitry Andric   bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E);
153*0fca6ea1SDimitry Andric   bool VisitSYCLUniqueStableNameExpr(const SYCLUniqueStableNameExpr *E);
154*0fca6ea1SDimitry Andric   bool VisitCharacterLiteral(const CharacterLiteral *E);
155*0fca6ea1SDimitry Andric   bool VisitCompoundAssignOperator(const CompoundAssignOperator *E);
156*0fca6ea1SDimitry Andric   bool VisitFloatCompoundAssignOperator(const CompoundAssignOperator *E);
157*0fca6ea1SDimitry Andric   bool VisitPointerCompoundAssignOperator(const CompoundAssignOperator *E);
158*0fca6ea1SDimitry Andric   bool VisitExprWithCleanups(const ExprWithCleanups *E);
159*0fca6ea1SDimitry Andric   bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
160*0fca6ea1SDimitry Andric   bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E);
161*0fca6ea1SDimitry Andric   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
162*0fca6ea1SDimitry Andric   bool VisitTypeTraitExpr(const TypeTraitExpr *E);
163*0fca6ea1SDimitry Andric   bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E);
164*0fca6ea1SDimitry Andric   bool VisitLambdaExpr(const LambdaExpr *E);
165*0fca6ea1SDimitry Andric   bool VisitPredefinedExpr(const PredefinedExpr *E);
166*0fca6ea1SDimitry Andric   bool VisitCXXThrowExpr(const CXXThrowExpr *E);
167*0fca6ea1SDimitry Andric   bool VisitCXXReinterpretCastExpr(const CXXReinterpretCastExpr *E);
168*0fca6ea1SDimitry Andric   bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
169*0fca6ea1SDimitry Andric   bool VisitCXXConstructExpr(const CXXConstructExpr *E);
170*0fca6ea1SDimitry Andric   bool VisitSourceLocExpr(const SourceLocExpr *E);
171*0fca6ea1SDimitry Andric   bool VisitOffsetOfExpr(const OffsetOfExpr *E);
172*0fca6ea1SDimitry Andric   bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E);
173*0fca6ea1SDimitry Andric   bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
174*0fca6ea1SDimitry Andric   bool VisitGenericSelectionExpr(const GenericSelectionExpr *E);
175*0fca6ea1SDimitry Andric   bool VisitChooseExpr(const ChooseExpr *E);
176*0fca6ea1SDimitry Andric   bool VisitEmbedExpr(const EmbedExpr *E);
177*0fca6ea1SDimitry Andric   bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
178*0fca6ea1SDimitry Andric   bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
179*0fca6ea1SDimitry Andric   bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E);
180*0fca6ea1SDimitry Andric   bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
181*0fca6ea1SDimitry Andric   bool VisitRequiresExpr(const RequiresExpr *E);
182*0fca6ea1SDimitry Andric   bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
183*0fca6ea1SDimitry Andric   bool VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *E);
184*0fca6ea1SDimitry Andric   bool VisitPseudoObjectExpr(const PseudoObjectExpr *E);
185*0fca6ea1SDimitry Andric   bool VisitPackIndexingExpr(const PackIndexingExpr *E);
186*0fca6ea1SDimitry Andric   bool VisitRecoveryExpr(const RecoveryExpr *E);
187*0fca6ea1SDimitry Andric   bool VisitAddrLabelExpr(const AddrLabelExpr *E);
188*0fca6ea1SDimitry Andric   bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
189*0fca6ea1SDimitry Andric   bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
190*0fca6ea1SDimitry Andric   bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E);
191*0fca6ea1SDimitry Andric   bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
192*0fca6ea1SDimitry Andric   bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E);
193*0fca6ea1SDimitry Andric   bool VisitStmtExpr(const StmtExpr *E);
194*0fca6ea1SDimitry Andric   bool VisitCXXNewExpr(const CXXNewExpr *E);
195*0fca6ea1SDimitry Andric   bool VisitCXXDeleteExpr(const CXXDeleteExpr *E);
196*0fca6ea1SDimitry Andric 
197*0fca6ea1SDimitry Andric   // Statements.
198*0fca6ea1SDimitry Andric   bool visitCompoundStmt(const CompoundStmt *S);
199*0fca6ea1SDimitry Andric   bool visitLoopBody(const Stmt *S);
200*0fca6ea1SDimitry Andric   bool visitDeclStmt(const DeclStmt *DS);
201*0fca6ea1SDimitry Andric   bool visitReturnStmt(const ReturnStmt *RS);
202*0fca6ea1SDimitry Andric   bool visitIfStmt(const IfStmt *IS);
203*0fca6ea1SDimitry Andric   bool visitWhileStmt(const WhileStmt *S);
204*0fca6ea1SDimitry Andric   bool visitDoStmt(const DoStmt *S);
205*0fca6ea1SDimitry Andric   bool visitForStmt(const ForStmt *S);
206*0fca6ea1SDimitry Andric   bool visitCXXForRangeStmt(const CXXForRangeStmt *S);
207*0fca6ea1SDimitry Andric   bool visitBreakStmt(const BreakStmt *S);
208*0fca6ea1SDimitry Andric   bool visitContinueStmt(const ContinueStmt *S);
209*0fca6ea1SDimitry Andric   bool visitSwitchStmt(const SwitchStmt *S);
210*0fca6ea1SDimitry Andric   bool visitCaseStmt(const CaseStmt *S);
211*0fca6ea1SDimitry Andric   bool visitDefaultStmt(const DefaultStmt *S);
212*0fca6ea1SDimitry Andric   bool visitAttributedStmt(const AttributedStmt *S);
213*0fca6ea1SDimitry Andric   bool visitCXXTryStmt(const CXXTryStmt *S);
214*0fca6ea1SDimitry Andric 
215*0fca6ea1SDimitry Andric protected:
216*0fca6ea1SDimitry Andric   bool visitStmt(const Stmt *S);
217*0fca6ea1SDimitry Andric   bool visitExpr(const Expr *E) override;
218*0fca6ea1SDimitry Andric   bool visitFunc(const FunctionDecl *F) override;
219*0fca6ea1SDimitry Andric 
220*0fca6ea1SDimitry Andric   bool visitDeclAndReturn(const VarDecl *VD, bool ConstantContext) override;
221*0fca6ea1SDimitry Andric 
222*0fca6ea1SDimitry Andric protected:
223*0fca6ea1SDimitry Andric   /// Emits scope cleanup instructions.
224*0fca6ea1SDimitry Andric   void emitCleanup();
225*0fca6ea1SDimitry Andric 
226*0fca6ea1SDimitry Andric   /// Returns a record type from a record or pointer type.
227*0fca6ea1SDimitry Andric   const RecordType *getRecordTy(QualType Ty);
228*0fca6ea1SDimitry Andric 
229*0fca6ea1SDimitry Andric   /// Returns a record from a record or pointer type.
230*0fca6ea1SDimitry Andric   Record *getRecord(QualType Ty);
231*0fca6ea1SDimitry Andric   Record *getRecord(const RecordDecl *RD);
232*0fca6ea1SDimitry Andric 
233*0fca6ea1SDimitry Andric   /// Returns a function for the given FunctionDecl.
234*0fca6ea1SDimitry Andric   /// If the function does not exist yet, it is compiled.
235*0fca6ea1SDimitry Andric   const Function *getFunction(const FunctionDecl *FD);
236*0fca6ea1SDimitry Andric 
237*0fca6ea1SDimitry Andric   std::optional<PrimType> classify(const Expr *E) const {
238*0fca6ea1SDimitry Andric     return Ctx.classify(E);
239*0fca6ea1SDimitry Andric   }
240*0fca6ea1SDimitry Andric   std::optional<PrimType> classify(QualType Ty) const {
241*0fca6ea1SDimitry Andric     return Ctx.classify(Ty);
242*0fca6ea1SDimitry Andric   }
243*0fca6ea1SDimitry Andric 
244*0fca6ea1SDimitry Andric   /// Classifies a known primitive type.
245*0fca6ea1SDimitry Andric   PrimType classifyPrim(QualType Ty) const {
246*0fca6ea1SDimitry Andric     if (auto T = classify(Ty)) {
247*0fca6ea1SDimitry Andric       return *T;
248*0fca6ea1SDimitry Andric     }
249*0fca6ea1SDimitry Andric     llvm_unreachable("not a primitive type");
250*0fca6ea1SDimitry Andric   }
251*0fca6ea1SDimitry Andric   /// Classifies a known primitive expression.
252*0fca6ea1SDimitry Andric   PrimType classifyPrim(const Expr *E) const {
253*0fca6ea1SDimitry Andric     if (auto T = classify(E))
254*0fca6ea1SDimitry Andric       return *T;
255*0fca6ea1SDimitry Andric     llvm_unreachable("not a primitive type");
256*0fca6ea1SDimitry Andric   }
257*0fca6ea1SDimitry Andric 
258*0fca6ea1SDimitry Andric   /// Evaluates an expression and places the result on the stack. If the
259*0fca6ea1SDimitry Andric   /// expression is of composite type, a local variable will be created
260*0fca6ea1SDimitry Andric   /// and a pointer to said variable will be placed on the stack.
261*0fca6ea1SDimitry Andric   bool visit(const Expr *E);
262*0fca6ea1SDimitry Andric   /// Compiles an initializer. This is like visit() but it will never
263*0fca6ea1SDimitry Andric   /// create a variable and instead rely on a variable already having
264*0fca6ea1SDimitry Andric   /// been created. visitInitializer() then relies on a pointer to this
265*0fca6ea1SDimitry Andric   /// variable being on top of the stack.
266*0fca6ea1SDimitry Andric   bool visitInitializer(const Expr *E);
267*0fca6ea1SDimitry Andric   /// Evaluates an expression for side effects and discards the result.
268*0fca6ea1SDimitry Andric   bool discard(const Expr *E);
269*0fca6ea1SDimitry Andric   /// Just pass evaluation on to \p E. This leaves all the parsing flags
270*0fca6ea1SDimitry Andric   /// intact.
271*0fca6ea1SDimitry Andric   bool delegate(const Expr *E);
272*0fca6ea1SDimitry Andric   /// Creates and initializes a variable from the given decl.
273*0fca6ea1SDimitry Andric   VarCreationState visitVarDecl(const VarDecl *VD, bool Toplevel = false);
274*0fca6ea1SDimitry Andric   VarCreationState visitDecl(const VarDecl *VD);
275*0fca6ea1SDimitry Andric   /// Visit an APValue.
276*0fca6ea1SDimitry Andric   bool visitAPValue(const APValue &Val, PrimType ValType, const Expr *E);
277*0fca6ea1SDimitry Andric   bool visitAPValueInitializer(const APValue &Val, const Expr *E);
278*0fca6ea1SDimitry Andric   /// Visit the given decl as if we have a reference to it.
279*0fca6ea1SDimitry Andric   bool visitDeclRef(const ValueDecl *D, const Expr *E);
280*0fca6ea1SDimitry Andric 
281*0fca6ea1SDimitry Andric   /// Visits an expression and converts it to a boolean.
282*0fca6ea1SDimitry Andric   bool visitBool(const Expr *E);
283*0fca6ea1SDimitry Andric 
284*0fca6ea1SDimitry Andric   bool visitInitList(ArrayRef<const Expr *> Inits, const Expr *ArrayFiller,
285*0fca6ea1SDimitry Andric                      const Expr *E);
286*0fca6ea1SDimitry Andric   bool visitArrayElemInit(unsigned ElemIndex, const Expr *Init);
287*0fca6ea1SDimitry Andric 
288*0fca6ea1SDimitry Andric   /// Creates a local primitive value.
289*0fca6ea1SDimitry Andric   unsigned allocateLocalPrimitive(DeclTy &&Decl, PrimType Ty, bool IsConst,
290*0fca6ea1SDimitry Andric                                   bool IsExtended = false);
291*0fca6ea1SDimitry Andric 
292*0fca6ea1SDimitry Andric   /// Allocates a space storing a local given its type.
293*0fca6ea1SDimitry Andric   std::optional<unsigned>
294*0fca6ea1SDimitry Andric   allocateLocal(DeclTy &&Decl, const ValueDecl *ExtendingDecl = nullptr);
295*0fca6ea1SDimitry Andric 
296*0fca6ea1SDimitry Andric private:
297*0fca6ea1SDimitry Andric   friend class VariableScope<Emitter>;
298*0fca6ea1SDimitry Andric   friend class LocalScope<Emitter>;
299*0fca6ea1SDimitry Andric   friend class DestructorScope<Emitter>;
300*0fca6ea1SDimitry Andric   friend class DeclScope<Emitter>;
301*0fca6ea1SDimitry Andric   friend class InitLinkScope<Emitter>;
302*0fca6ea1SDimitry Andric   friend class InitStackScope<Emitter>;
303*0fca6ea1SDimitry Andric   friend class OptionScope<Emitter>;
304*0fca6ea1SDimitry Andric   friend class ArrayIndexScope<Emitter>;
305*0fca6ea1SDimitry Andric   friend class SourceLocScope<Emitter>;
306*0fca6ea1SDimitry Andric   friend struct InitLink;
307*0fca6ea1SDimitry Andric   friend class LoopScope<Emitter>;
308*0fca6ea1SDimitry Andric   friend class LabelScope<Emitter>;
309*0fca6ea1SDimitry Andric   friend class SwitchScope<Emitter>;
310*0fca6ea1SDimitry Andric   friend class StmtExprScope<Emitter>;
311*0fca6ea1SDimitry Andric 
312*0fca6ea1SDimitry Andric   /// Emits a zero initializer.
313*0fca6ea1SDimitry Andric   bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
314*0fca6ea1SDimitry Andric   bool visitZeroRecordInitializer(const Record *R, const Expr *E);
315*0fca6ea1SDimitry Andric 
316*0fca6ea1SDimitry Andric   /// Emits an APSInt constant.
317*0fca6ea1SDimitry Andric   bool emitConst(const llvm::APSInt &Value, PrimType Ty, const Expr *E);
318*0fca6ea1SDimitry Andric   bool emitConst(const llvm::APSInt &Value, const Expr *E);
319*0fca6ea1SDimitry Andric   bool emitConst(const llvm::APInt &Value, const Expr *E) {
320*0fca6ea1SDimitry Andric     return emitConst(static_cast<llvm::APSInt>(Value), E);
321*0fca6ea1SDimitry Andric   }
322*0fca6ea1SDimitry Andric 
323*0fca6ea1SDimitry Andric   /// Emits an integer constant.
324*0fca6ea1SDimitry Andric   template <typename T> bool emitConst(T Value, PrimType Ty, const Expr *E);
325*0fca6ea1SDimitry Andric   template <typename T> bool emitConst(T Value, const Expr *E);
326*0fca6ea1SDimitry Andric 
327*0fca6ea1SDimitry Andric   llvm::RoundingMode getRoundingMode(const Expr *E) const {
328*0fca6ea1SDimitry Andric     FPOptions FPO = E->getFPFeaturesInEffect(Ctx.getLangOpts());
329*0fca6ea1SDimitry Andric 
330*0fca6ea1SDimitry Andric     if (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic)
331*0fca6ea1SDimitry Andric       return llvm::RoundingMode::NearestTiesToEven;
332*0fca6ea1SDimitry Andric 
333*0fca6ea1SDimitry Andric     return FPO.getRoundingMode();
334*0fca6ea1SDimitry Andric   }
335*0fca6ea1SDimitry Andric 
336*0fca6ea1SDimitry Andric   bool emitPrimCast(PrimType FromT, PrimType ToT, QualType ToQT, const Expr *E);
337*0fca6ea1SDimitry Andric   PrimType classifyComplexElementType(QualType T) const {
338*0fca6ea1SDimitry Andric     assert(T->isAnyComplexType());
339*0fca6ea1SDimitry Andric 
340*0fca6ea1SDimitry Andric     QualType ElemType = T->getAs<ComplexType>()->getElementType();
341*0fca6ea1SDimitry Andric 
342*0fca6ea1SDimitry Andric     return *this->classify(ElemType);
343*0fca6ea1SDimitry Andric   }
344*0fca6ea1SDimitry Andric 
345*0fca6ea1SDimitry Andric   bool emitComplexReal(const Expr *SubExpr);
346*0fca6ea1SDimitry Andric   bool emitComplexBoolCast(const Expr *E);
347*0fca6ea1SDimitry Andric   bool emitComplexComparison(const Expr *LHS, const Expr *RHS,
348*0fca6ea1SDimitry Andric                              const BinaryOperator *E);
349*0fca6ea1SDimitry Andric 
350*0fca6ea1SDimitry Andric   bool emitRecordDestruction(const Record *R);
351*0fca6ea1SDimitry Andric   bool emitDestruction(const Descriptor *Desc);
352*0fca6ea1SDimitry Andric   unsigned collectBaseOffset(const QualType BaseType,
353*0fca6ea1SDimitry Andric                              const QualType DerivedType);
354*0fca6ea1SDimitry Andric   bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
355*0fca6ea1SDimitry Andric 
356*0fca6ea1SDimitry Andric protected:
357*0fca6ea1SDimitry Andric   /// Variable to storage mapping.
358*0fca6ea1SDimitry Andric   llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
359*0fca6ea1SDimitry Andric 
360*0fca6ea1SDimitry Andric   /// OpaqueValueExpr to location mapping.
361*0fca6ea1SDimitry Andric   llvm::DenseMap<const OpaqueValueExpr *, unsigned> OpaqueExprs;
362*0fca6ea1SDimitry Andric 
363*0fca6ea1SDimitry Andric   /// Current scope.
364*0fca6ea1SDimitry Andric   VariableScope<Emitter> *VarScope = nullptr;
365*0fca6ea1SDimitry Andric 
366*0fca6ea1SDimitry Andric   /// Current argument index. Needed to emit ArrayInitIndexExpr.
367*0fca6ea1SDimitry Andric   std::optional<uint64_t> ArrayIndex;
368*0fca6ea1SDimitry Andric 
369*0fca6ea1SDimitry Andric   /// DefaultInit- or DefaultArgExpr, needed for SourceLocExpr.
370*0fca6ea1SDimitry Andric   const Expr *SourceLocDefaultExpr = nullptr;
371*0fca6ea1SDimitry Andric 
372*0fca6ea1SDimitry Andric   /// Flag indicating if return value is to be discarded.
373*0fca6ea1SDimitry Andric   bool DiscardResult = false;
374*0fca6ea1SDimitry Andric 
375*0fca6ea1SDimitry Andric   bool InStmtExpr = false;
376*0fca6ea1SDimitry Andric 
377*0fca6ea1SDimitry Andric   /// Flag inidicating if we're initializing an already created
378*0fca6ea1SDimitry Andric   /// variable. This is set in visitInitializer().
379*0fca6ea1SDimitry Andric   bool Initializing = false;
380*0fca6ea1SDimitry Andric   const ValueDecl *InitializingDecl = nullptr;
381*0fca6ea1SDimitry Andric 
382*0fca6ea1SDimitry Andric   llvm::SmallVector<InitLink> InitStack;
383*0fca6ea1SDimitry Andric   bool InitStackActive = false;
384*0fca6ea1SDimitry Andric 
385*0fca6ea1SDimitry Andric   /// Flag indicating if we're initializing a global variable.
386*0fca6ea1SDimitry Andric   bool GlobalDecl = false;
387*0fca6ea1SDimitry Andric 
388*0fca6ea1SDimitry Andric   /// Type of the expression returned by the function.
389*0fca6ea1SDimitry Andric   std::optional<PrimType> ReturnType;
390*0fca6ea1SDimitry Andric 
391*0fca6ea1SDimitry Andric   /// Switch case mapping.
392*0fca6ea1SDimitry Andric   CaseMap CaseLabels;
393*0fca6ea1SDimitry Andric 
394*0fca6ea1SDimitry Andric   /// Point to break to.
395*0fca6ea1SDimitry Andric   OptLabelTy BreakLabel;
396*0fca6ea1SDimitry Andric   /// Point to continue to.
397*0fca6ea1SDimitry Andric   OptLabelTy ContinueLabel;
398*0fca6ea1SDimitry Andric   /// Default case label.
399*0fca6ea1SDimitry Andric   OptLabelTy DefaultLabel;
400*0fca6ea1SDimitry Andric };
401*0fca6ea1SDimitry Andric 
402*0fca6ea1SDimitry Andric extern template class Compiler<ByteCodeEmitter>;
403*0fca6ea1SDimitry Andric extern template class Compiler<EvalEmitter>;
404*0fca6ea1SDimitry Andric 
405*0fca6ea1SDimitry Andric /// Scope chain managing the variable lifetimes.
406*0fca6ea1SDimitry Andric template <class Emitter> class VariableScope {
407*0fca6ea1SDimitry Andric public:
408*0fca6ea1SDimitry Andric   VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
409*0fca6ea1SDimitry Andric       : Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD) {
410*0fca6ea1SDimitry Andric     Ctx->VarScope = this;
411*0fca6ea1SDimitry Andric   }
412*0fca6ea1SDimitry Andric 
413*0fca6ea1SDimitry Andric   virtual ~VariableScope() { Ctx->VarScope = this->Parent; }
414*0fca6ea1SDimitry Andric 
415*0fca6ea1SDimitry Andric   void add(const Scope::Local &Local, bool IsExtended) {
416*0fca6ea1SDimitry Andric     if (IsExtended)
417*0fca6ea1SDimitry Andric       this->addExtended(Local);
418*0fca6ea1SDimitry Andric     else
419*0fca6ea1SDimitry Andric       this->addLocal(Local);
420*0fca6ea1SDimitry Andric   }
421*0fca6ea1SDimitry Andric 
422*0fca6ea1SDimitry Andric   virtual void addLocal(const Scope::Local &Local) {
423*0fca6ea1SDimitry Andric     if (this->Parent)
424*0fca6ea1SDimitry Andric       this->Parent->addLocal(Local);
425*0fca6ea1SDimitry Andric   }
426*0fca6ea1SDimitry Andric 
427*0fca6ea1SDimitry Andric   virtual void addExtended(const Scope::Local &Local) {
428*0fca6ea1SDimitry Andric     if (this->Parent)
429*0fca6ea1SDimitry Andric       this->Parent->addExtended(Local);
430*0fca6ea1SDimitry Andric   }
431*0fca6ea1SDimitry Andric 
432*0fca6ea1SDimitry Andric   void addExtended(const Scope::Local &Local, const ValueDecl *ExtendingDecl) {
433*0fca6ea1SDimitry Andric     // Walk up the chain of scopes until we find the one for ExtendingDecl.
434*0fca6ea1SDimitry Andric     // If there is no such scope, attach it to the parent one.
435*0fca6ea1SDimitry Andric     VariableScope *P = this;
436*0fca6ea1SDimitry Andric     while (P) {
437*0fca6ea1SDimitry Andric       if (P->ValDecl == ExtendingDecl) {
438*0fca6ea1SDimitry Andric         P->addLocal(Local);
439*0fca6ea1SDimitry Andric         return;
440*0fca6ea1SDimitry Andric       }
441*0fca6ea1SDimitry Andric       P = P->Parent;
442*0fca6ea1SDimitry Andric       if (!P)
443*0fca6ea1SDimitry Andric         break;
444*0fca6ea1SDimitry Andric     }
445*0fca6ea1SDimitry Andric 
446*0fca6ea1SDimitry Andric     // Use the parent scope.
447*0fca6ea1SDimitry Andric     addExtended(Local);
448*0fca6ea1SDimitry Andric   }
449*0fca6ea1SDimitry Andric 
450*0fca6ea1SDimitry Andric   virtual void emitDestruction() {}
451*0fca6ea1SDimitry Andric   virtual bool emitDestructors() { return true; }
452*0fca6ea1SDimitry Andric   VariableScope *getParent() const { return Parent; }
453*0fca6ea1SDimitry Andric 
454*0fca6ea1SDimitry Andric protected:
455*0fca6ea1SDimitry Andric   /// Compiler instance.
456*0fca6ea1SDimitry Andric   Compiler<Emitter> *Ctx;
457*0fca6ea1SDimitry Andric   /// Link to the parent scope.
458*0fca6ea1SDimitry Andric   VariableScope *Parent;
459*0fca6ea1SDimitry Andric   const ValueDecl *ValDecl = nullptr;
460*0fca6ea1SDimitry Andric };
461*0fca6ea1SDimitry Andric 
462*0fca6ea1SDimitry Andric /// Generic scope for local variables.
463*0fca6ea1SDimitry Andric template <class Emitter> class LocalScope : public VariableScope<Emitter> {
464*0fca6ea1SDimitry Andric public:
465*0fca6ea1SDimitry Andric   LocalScope(Compiler<Emitter> *Ctx) : VariableScope<Emitter>(Ctx, nullptr) {}
466*0fca6ea1SDimitry Andric   LocalScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
467*0fca6ea1SDimitry Andric       : VariableScope<Emitter>(Ctx, VD) {}
468*0fca6ea1SDimitry Andric 
469*0fca6ea1SDimitry Andric   /// Emit a Destroy op for this scope.
470*0fca6ea1SDimitry Andric   ~LocalScope() override {
471*0fca6ea1SDimitry Andric     if (!Idx)
472*0fca6ea1SDimitry Andric       return;
473*0fca6ea1SDimitry Andric     this->Ctx->emitDestroy(*Idx, SourceInfo{});
474*0fca6ea1SDimitry Andric     removeStoredOpaqueValues();
475*0fca6ea1SDimitry Andric   }
476*0fca6ea1SDimitry Andric 
477*0fca6ea1SDimitry Andric   /// Overriden to support explicit destruction.
478*0fca6ea1SDimitry Andric   void emitDestruction() override { destroyLocals(); }
479*0fca6ea1SDimitry Andric 
480*0fca6ea1SDimitry Andric   /// Explicit destruction of local variables.
481*0fca6ea1SDimitry Andric   bool destroyLocals() {
482*0fca6ea1SDimitry Andric     if (!Idx)
483*0fca6ea1SDimitry Andric       return true;
484*0fca6ea1SDimitry Andric 
485*0fca6ea1SDimitry Andric     bool Success = this->emitDestructors();
486*0fca6ea1SDimitry Andric     this->Ctx->emitDestroy(*Idx, SourceInfo{});
487*0fca6ea1SDimitry Andric     removeStoredOpaqueValues();
488*0fca6ea1SDimitry Andric     this->Idx = std::nullopt;
489*0fca6ea1SDimitry Andric     return Success;
490*0fca6ea1SDimitry Andric   }
491*0fca6ea1SDimitry Andric 
492*0fca6ea1SDimitry Andric   void addLocal(const Scope::Local &Local) override {
493*0fca6ea1SDimitry Andric     if (!Idx) {
494*0fca6ea1SDimitry Andric       Idx = this->Ctx->Descriptors.size();
495*0fca6ea1SDimitry Andric       this->Ctx->Descriptors.emplace_back();
496*0fca6ea1SDimitry Andric     }
497*0fca6ea1SDimitry Andric 
498*0fca6ea1SDimitry Andric     this->Ctx->Descriptors[*Idx].emplace_back(Local);
499*0fca6ea1SDimitry Andric   }
500*0fca6ea1SDimitry Andric 
501*0fca6ea1SDimitry Andric   bool emitDestructors() override {
502*0fca6ea1SDimitry Andric     if (!Idx)
503*0fca6ea1SDimitry Andric       return true;
504*0fca6ea1SDimitry Andric     // Emit destructor calls for local variables of record
505*0fca6ea1SDimitry Andric     // type with a destructor.
506*0fca6ea1SDimitry Andric     for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
507*0fca6ea1SDimitry Andric       if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {
508*0fca6ea1SDimitry Andric         if (!this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{}))
509*0fca6ea1SDimitry Andric           return false;
510*0fca6ea1SDimitry Andric 
511*0fca6ea1SDimitry Andric         if (!this->Ctx->emitDestruction(Local.Desc))
512*0fca6ea1SDimitry Andric           return false;
513*0fca6ea1SDimitry Andric 
514*0fca6ea1SDimitry Andric         if (!this->Ctx->emitPopPtr(SourceInfo{}))
515*0fca6ea1SDimitry Andric           return false;
516*0fca6ea1SDimitry Andric         removeIfStoredOpaqueValue(Local);
517*0fca6ea1SDimitry Andric       }
518*0fca6ea1SDimitry Andric     }
519*0fca6ea1SDimitry Andric     return true;
520*0fca6ea1SDimitry Andric   }
521*0fca6ea1SDimitry Andric 
522*0fca6ea1SDimitry Andric   void removeStoredOpaqueValues() {
523*0fca6ea1SDimitry Andric     if (!Idx)
524*0fca6ea1SDimitry Andric       return;
525*0fca6ea1SDimitry Andric 
526*0fca6ea1SDimitry Andric     for (const Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
527*0fca6ea1SDimitry Andric       removeIfStoredOpaqueValue(Local);
528*0fca6ea1SDimitry Andric     }
529*0fca6ea1SDimitry Andric   }
530*0fca6ea1SDimitry Andric 
531*0fca6ea1SDimitry Andric   void removeIfStoredOpaqueValue(const Scope::Local &Local) {
532*0fca6ea1SDimitry Andric     if (const auto *OVE =
533*0fca6ea1SDimitry Andric             llvm::dyn_cast_if_present<OpaqueValueExpr>(Local.Desc->asExpr())) {
534*0fca6ea1SDimitry Andric       if (auto It = this->Ctx->OpaqueExprs.find(OVE);
535*0fca6ea1SDimitry Andric           It != this->Ctx->OpaqueExprs.end())
536*0fca6ea1SDimitry Andric         this->Ctx->OpaqueExprs.erase(It);
537*0fca6ea1SDimitry Andric     };
538*0fca6ea1SDimitry Andric   }
539*0fca6ea1SDimitry Andric 
540*0fca6ea1SDimitry Andric   /// Index of the scope in the chain.
541*0fca6ea1SDimitry Andric   std::optional<unsigned> Idx;
542*0fca6ea1SDimitry Andric };
543*0fca6ea1SDimitry Andric 
544*0fca6ea1SDimitry Andric /// Emits the destructors of the variables of \param OtherScope
545*0fca6ea1SDimitry Andric /// when this scope is destroyed. Does not create a Scope in the bytecode at
546*0fca6ea1SDimitry Andric /// all, this is just a RAII object to emit destructors.
547*0fca6ea1SDimitry Andric template <class Emitter> class DestructorScope final {
548*0fca6ea1SDimitry Andric public:
549*0fca6ea1SDimitry Andric   DestructorScope(LocalScope<Emitter> &OtherScope) : OtherScope(OtherScope) {}
550*0fca6ea1SDimitry Andric 
551*0fca6ea1SDimitry Andric   ~DestructorScope() { OtherScope.emitDestructors(); }
552*0fca6ea1SDimitry Andric 
553*0fca6ea1SDimitry Andric private:
554*0fca6ea1SDimitry Andric   LocalScope<Emitter> &OtherScope;
555*0fca6ea1SDimitry Andric };
556*0fca6ea1SDimitry Andric 
557*0fca6ea1SDimitry Andric /// Scope for storage declared in a compound statement.
558*0fca6ea1SDimitry Andric template <class Emitter> class BlockScope final : public LocalScope<Emitter> {
559*0fca6ea1SDimitry Andric public:
560*0fca6ea1SDimitry Andric   BlockScope(Compiler<Emitter> *Ctx) : LocalScope<Emitter>(Ctx) {}
561*0fca6ea1SDimitry Andric 
562*0fca6ea1SDimitry Andric   void addExtended(const Scope::Local &Local) override {
563*0fca6ea1SDimitry Andric     // If we to this point, just add the variable as a normal local
564*0fca6ea1SDimitry Andric     // variable. It will be destroyed at the end of the block just
565*0fca6ea1SDimitry Andric     // like all others.
566*0fca6ea1SDimitry Andric     this->addLocal(Local);
567*0fca6ea1SDimitry Andric   }
568*0fca6ea1SDimitry Andric };
569*0fca6ea1SDimitry Andric 
570*0fca6ea1SDimitry Andric template <class Emitter> class ArrayIndexScope final {
571*0fca6ea1SDimitry Andric public:
572*0fca6ea1SDimitry Andric   ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
573*0fca6ea1SDimitry Andric     OldArrayIndex = Ctx->ArrayIndex;
574*0fca6ea1SDimitry Andric     Ctx->ArrayIndex = Index;
575*0fca6ea1SDimitry Andric   }
576*0fca6ea1SDimitry Andric 
577*0fca6ea1SDimitry Andric   ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
578*0fca6ea1SDimitry Andric 
579*0fca6ea1SDimitry Andric private:
580*0fca6ea1SDimitry Andric   Compiler<Emitter> *Ctx;
581*0fca6ea1SDimitry Andric   std::optional<uint64_t> OldArrayIndex;
582*0fca6ea1SDimitry Andric };
583*0fca6ea1SDimitry Andric 
584*0fca6ea1SDimitry Andric template <class Emitter> class SourceLocScope final {
585*0fca6ea1SDimitry Andric public:
586*0fca6ea1SDimitry Andric   SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) {
587*0fca6ea1SDimitry Andric     assert(DefaultExpr);
588*0fca6ea1SDimitry Andric     // We only switch if the current SourceLocDefaultExpr is null.
589*0fca6ea1SDimitry Andric     if (!Ctx->SourceLocDefaultExpr) {
590*0fca6ea1SDimitry Andric       Enabled = true;
591*0fca6ea1SDimitry Andric       Ctx->SourceLocDefaultExpr = DefaultExpr;
592*0fca6ea1SDimitry Andric     }
593*0fca6ea1SDimitry Andric   }
594*0fca6ea1SDimitry Andric 
595*0fca6ea1SDimitry Andric   ~SourceLocScope() {
596*0fca6ea1SDimitry Andric     if (Enabled)
597*0fca6ea1SDimitry Andric       Ctx->SourceLocDefaultExpr = nullptr;
598*0fca6ea1SDimitry Andric   }
599*0fca6ea1SDimitry Andric 
600*0fca6ea1SDimitry Andric private:
601*0fca6ea1SDimitry Andric   Compiler<Emitter> *Ctx;
602*0fca6ea1SDimitry Andric   bool Enabled = false;
603*0fca6ea1SDimitry Andric };
604*0fca6ea1SDimitry Andric 
605*0fca6ea1SDimitry Andric template <class Emitter> class InitLinkScope final {
606*0fca6ea1SDimitry Andric public:
607*0fca6ea1SDimitry Andric   InitLinkScope(Compiler<Emitter> *Ctx, InitLink &&Link) : Ctx(Ctx) {
608*0fca6ea1SDimitry Andric     Ctx->InitStack.push_back(std::move(Link));
609*0fca6ea1SDimitry Andric   }
610*0fca6ea1SDimitry Andric 
611*0fca6ea1SDimitry Andric   ~InitLinkScope() { this->Ctx->InitStack.pop_back(); }
612*0fca6ea1SDimitry Andric 
613*0fca6ea1SDimitry Andric private:
614*0fca6ea1SDimitry Andric   Compiler<Emitter> *Ctx;
615*0fca6ea1SDimitry Andric };
616*0fca6ea1SDimitry Andric 
617*0fca6ea1SDimitry Andric template <class Emitter> class InitStackScope final {
618*0fca6ea1SDimitry Andric public:
619*0fca6ea1SDimitry Andric   InitStackScope(Compiler<Emitter> *Ctx, bool Active)
620*0fca6ea1SDimitry Andric       : Ctx(Ctx), OldValue(Ctx->InitStackActive) {
621*0fca6ea1SDimitry Andric     Ctx->InitStackActive = Active;
622*0fca6ea1SDimitry Andric   }
623*0fca6ea1SDimitry Andric 
624*0fca6ea1SDimitry Andric   ~InitStackScope() { this->Ctx->InitStackActive = OldValue; }
625*0fca6ea1SDimitry Andric 
626*0fca6ea1SDimitry Andric private:
627*0fca6ea1SDimitry Andric   Compiler<Emitter> *Ctx;
628*0fca6ea1SDimitry Andric   bool OldValue;
629*0fca6ea1SDimitry Andric };
630*0fca6ea1SDimitry Andric 
631*0fca6ea1SDimitry Andric } // namespace interp
632*0fca6ea1SDimitry Andric } // namespace clang
633*0fca6ea1SDimitry Andric 
634*0fca6ea1SDimitry Andric #endif
635