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