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