brintos

brintos / llvm-project-archived public Read only

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