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