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