[clang] [clang][Interp] Merge ByteCodeExprGen and ByteCodeStmtGen (PR #83683)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Sat Jun 15 01:49:44 PDT 2024


Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>,
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/83683 at github.com>


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/83683

>From 8440f6bb5f16dd33f5227ce942b160997be0a36f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 2 Mar 2024 17:00:26 +0100
Subject: [PATCH 1/3] [clang][Interp] Merge ByteCode{Stmt,Expr}Gen

---
 clang/lib/AST/CMakeLists.txt             |   1 -
 clang/lib/AST/Interp/ByteCodeExprGen.cpp | 701 +++++++++++++++++++++-
 clang/lib/AST/Interp/ByteCodeExprGen.h   |  48 +-
 clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 731 -----------------------
 clang/lib/AST/Interp/ByteCodeStmtGen.h   |  91 ---
 clang/lib/AST/Interp/Context.cpp         |   5 +-
 clang/lib/AST/Interp/EvalEmitter.h       |   1 +
 clang/lib/AST/Interp/Program.cpp         |   1 -
 8 files changed, 748 insertions(+), 831 deletions(-)
 delete mode 100644 clang/lib/AST/Interp/ByteCodeStmtGen.cpp
 delete mode 100644 clang/lib/AST/Interp/ByteCodeStmtGen.h

diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index a5d3dacfc1a84..c5196fbf7ef74 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -66,7 +66,6 @@ add_clang_library(clangAST
   InheritViz.cpp
   Interp/ByteCodeEmitter.cpp
   Interp/ByteCodeExprGen.cpp
-  Interp/ByteCodeStmtGen.cpp
   Interp/Context.cpp
   Interp/Descriptor.cpp
   Interp/Disasm.cpp
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 300c013d15da8..3e06e25c02559 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -8,7 +8,6 @@
 
 #include "ByteCodeExprGen.h"
 #include "ByteCodeEmitter.h"
-#include "ByteCodeStmtGen.h"
 #include "Context.h"
 #include "Floating.h"
 #include "Function.h"
@@ -72,6 +71,70 @@ template <class Emitter> class OptionScope final {
   bool OldInitializing;
 };
 
+/// Scope managing label targets.
+template <class Emitter> class LabelScope {
+public:
+  virtual ~LabelScope() {}
+
+protected:
+  LabelScope(ByteCodeExprGen<Emitter> *Ctx) : Ctx(Ctx) {}
+  /// ByteCodeExprGen instance.
+  ByteCodeExprGen<Emitter> *Ctx;
+};
+
+/// Sets the context for break/continue statements.
+template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
+public:
+  using LabelTy = typename ByteCodeExprGen<Emitter>::LabelTy;
+  using OptLabelTy = typename ByteCodeExprGen<Emitter>::OptLabelTy;
+
+  LoopScope(ByteCodeExprGen<Emitter> *Ctx, LabelTy BreakLabel,
+            LabelTy ContinueLabel)
+      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
+        OldContinueLabel(Ctx->ContinueLabel) {
+    this->Ctx->BreakLabel = BreakLabel;
+    this->Ctx->ContinueLabel = ContinueLabel;
+  }
+
+  ~LoopScope() {
+    this->Ctx->BreakLabel = OldBreakLabel;
+    this->Ctx->ContinueLabel = OldContinueLabel;
+  }
+
+private:
+  OptLabelTy OldBreakLabel;
+  OptLabelTy OldContinueLabel;
+};
+
+// Sets the context for a switch scope, mapping labels.
+template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
+public:
+  using LabelTy = typename ByteCodeExprGen<Emitter>::LabelTy;
+  using OptLabelTy = typename ByteCodeExprGen<Emitter>::OptLabelTy;
+  using CaseMap = typename ByteCodeExprGen<Emitter>::CaseMap;
+
+  SwitchScope(ByteCodeExprGen<Emitter> *Ctx, CaseMap &&CaseLabels,
+              LabelTy BreakLabel, OptLabelTy DefaultLabel)
+      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
+        OldDefaultLabel(this->Ctx->DefaultLabel),
+        OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
+    this->Ctx->BreakLabel = BreakLabel;
+    this->Ctx->DefaultLabel = DefaultLabel;
+    this->Ctx->CaseLabels = std::move(CaseLabels);
+  }
+
+  ~SwitchScope() {
+    this->Ctx->BreakLabel = OldBreakLabel;
+    this->Ctx->DefaultLabel = OldDefaultLabel;
+    this->Ctx->CaseLabels = std::move(OldCaseLabels);
+  }
+
+private:
+  OptLabelTy OldBreakLabel;
+  OptLabelTy OldDefaultLabel;
+  CaseMap OldCaseLabels;
+};
+
 } // namespace interp
 } // namespace clang
 
@@ -3603,6 +3666,642 @@ bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
   return this->emitThis(E);
 }
 
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitStmt(const Stmt *S) {
+  switch (S->getStmtClass()) {
+  case Stmt::CompoundStmtClass:
+    return visitCompoundStmt(cast<CompoundStmt>(S));
+  case Stmt::DeclStmtClass:
+    return visitDeclStmt(cast<DeclStmt>(S));
+  case Stmt::ReturnStmtClass:
+    return visitReturnStmt(cast<ReturnStmt>(S));
+  case Stmt::IfStmtClass:
+    return visitIfStmt(cast<IfStmt>(S));
+  case Stmt::WhileStmtClass:
+    return visitWhileStmt(cast<WhileStmt>(S));
+  case Stmt::DoStmtClass:
+    return visitDoStmt(cast<DoStmt>(S));
+  case Stmt::ForStmtClass:
+    return visitForStmt(cast<ForStmt>(S));
+  case Stmt::CXXForRangeStmtClass:
+    return visitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
+  case Stmt::BreakStmtClass:
+    return visitBreakStmt(cast<BreakStmt>(S));
+  case Stmt::ContinueStmtClass:
+    return visitContinueStmt(cast<ContinueStmt>(S));
+  case Stmt::SwitchStmtClass:
+    return visitSwitchStmt(cast<SwitchStmt>(S));
+  case Stmt::CaseStmtClass:
+    return visitCaseStmt(cast<CaseStmt>(S));
+  case Stmt::DefaultStmtClass:
+    return visitDefaultStmt(cast<DefaultStmt>(S));
+  case Stmt::AttributedStmtClass:
+    return visitAttributedStmt(cast<AttributedStmt>(S));
+  case Stmt::CXXTryStmtClass:
+    return visitCXXTryStmt(cast<CXXTryStmt>(S));
+  case Stmt::NullStmtClass:
+    return true;
+  // Always invalid statements.
+  case Stmt::GCCAsmStmtClass:
+  case Stmt::MSAsmStmtClass:
+  case Stmt::GotoStmtClass:
+    return this->emitInvalid(S);
+  case Stmt::LabelStmtClass:
+    return this->visitStmt(cast<LabelStmt>(S)->getSubStmt());
+  default: {
+    if (const auto *E = dyn_cast<Expr>(S))
+      return this->discard(E);
+    return false;
+  }
+  }
+}
+
+/// Visits the given statment without creating a variable
+/// scope for it in case it is a compound statement.
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitLoopBody(const Stmt *S) {
+  if (isa<NullStmt>(S))
+    return true;
+
+  if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
+    for (auto *InnerStmt : CS->body())
+      if (!visitStmt(InnerStmt))
+        return false;
+    return true;
+  }
+
+  return this->visitStmt(S);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitCompoundStmt(const CompoundStmt *S) {
+  BlockScope<Emitter> Scope(this);
+  for (auto *InnerStmt : S->body())
+    if (!visitStmt(InnerStmt))
+      return false;
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
+  for (auto *D : DS->decls()) {
+    if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl,
+            FunctionDecl>(D))
+      continue;
+
+    const auto *VD = dyn_cast<VarDecl>(D);
+    if (!VD)
+      return false;
+    if (!this->visitVarDecl(VD))
+      return false;
+  }
+
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
+  if (const Expr *RE = RS->getRetValue()) {
+    ExprScope<Emitter> RetScope(this);
+    if (ReturnType) {
+      // Primitive types are simply returned.
+      if (!this->visit(RE))
+        return false;
+      this->emitCleanup();
+      return this->emitRet(*ReturnType, RS);
+    } else if (RE->getType()->isVoidType()) {
+      if (!this->visit(RE))
+        return false;
+    } else {
+      // RVO - construct the value in the return location.
+      if (!this->emitRVOPtr(RE))
+        return false;
+      if (!this->visitInitializer(RE))
+        return false;
+      if (!this->emitPopPtr(RE))
+        return false;
+
+      this->emitCleanup();
+      return this->emitRetVoid(RS);
+    }
+  }
+
+  // Void return.
+  this->emitCleanup();
+  return this->emitRetVoid(RS);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitIfStmt(const IfStmt *IS) {
+  BlockScope<Emitter> IfScope(this);
+
+  if (IS->isNonNegatedConsteval())
+    return visitStmt(IS->getThen());
+  if (IS->isNegatedConsteval())
+    return IS->getElse() ? visitStmt(IS->getElse()) : true;
+
+  if (auto *CondInit = IS->getInit())
+    if (!visitStmt(CondInit))
+      return false;
+
+  if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
+    if (!visitDeclStmt(CondDecl))
+      return false;
+
+  if (!this->visitBool(IS->getCond()))
+    return false;
+
+  if (const Stmt *Else = IS->getElse()) {
+    LabelTy LabelElse = this->getLabel();
+    LabelTy LabelEnd = this->getLabel();
+    if (!this->jumpFalse(LabelElse))
+      return false;
+    if (!visitStmt(IS->getThen()))
+      return false;
+    if (!this->jump(LabelEnd))
+      return false;
+    this->emitLabel(LabelElse);
+    if (!visitStmt(Else))
+      return false;
+    this->emitLabel(LabelEnd);
+  } else {
+    LabelTy LabelEnd = this->getLabel();
+    if (!this->jumpFalse(LabelEnd))
+      return false;
+    if (!visitStmt(IS->getThen()))
+      return false;
+    this->emitLabel(LabelEnd);
+  }
+
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
+  const Expr *Cond = S->getCond();
+  const Stmt *Body = S->getBody();
+
+  LabelTy CondLabel = this->getLabel(); // Label before the condition.
+  LabelTy EndLabel = this->getLabel();  // Label after the loop.
+  LoopScope<Emitter> LS(this, EndLabel, CondLabel);
+
+  this->emitLabel(CondLabel);
+
+  if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
+    if (!visitDeclStmt(CondDecl))
+      return false;
+
+  if (!this->visitBool(Cond))
+    return false;
+  if (!this->jumpFalse(EndLabel))
+    return false;
+
+  LocalScope<Emitter> Scope(this);
+  {
+    DestructorScope<Emitter> DS(Scope);
+    if (!this->visitLoopBody(Body))
+      return false;
+  }
+
+  if (!this->jump(CondLabel))
+    return false;
+  this->emitLabel(EndLabel);
+
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitDoStmt(const DoStmt *S) {
+  const Expr *Cond = S->getCond();
+  const Stmt *Body = S->getBody();
+
+  LabelTy StartLabel = this->getLabel();
+  LabelTy EndLabel = this->getLabel();
+  LabelTy CondLabel = this->getLabel();
+  LoopScope<Emitter> LS(this, EndLabel, CondLabel);
+  LocalScope<Emitter> Scope(this);
+
+  this->emitLabel(StartLabel);
+  {
+    DestructorScope<Emitter> DS(Scope);
+
+    if (!this->visitLoopBody(Body))
+      return false;
+    this->emitLabel(CondLabel);
+    if (!this->visitBool(Cond))
+      return false;
+  }
+  if (!this->jumpTrue(StartLabel))
+    return false;
+
+  this->emitLabel(EndLabel);
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitForStmt(const ForStmt *S) {
+  // for (Init; Cond; Inc) { Body }
+  const Stmt *Init = S->getInit();
+  const Expr *Cond = S->getCond();
+  const Expr *Inc = S->getInc();
+  const Stmt *Body = S->getBody();
+
+  LabelTy EndLabel = this->getLabel();
+  LabelTy CondLabel = this->getLabel();
+  LabelTy IncLabel = this->getLabel();
+  LoopScope<Emitter> LS(this, EndLabel, IncLabel);
+  LocalScope<Emitter> Scope(this);
+
+  if (Init && !this->visitStmt(Init))
+    return false;
+  this->emitLabel(CondLabel);
+
+  if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
+    if (!visitDeclStmt(CondDecl))
+      return false;
+
+  if (Cond) {
+    if (!this->visitBool(Cond))
+      return false;
+    if (!this->jumpFalse(EndLabel))
+      return false;
+  }
+
+  {
+    DestructorScope<Emitter> DS(Scope);
+
+    if (Body && !this->visitLoopBody(Body))
+      return false;
+    this->emitLabel(IncLabel);
+    if (Inc && !this->discard(Inc))
+      return false;
+  }
+
+  if (!this->jump(CondLabel))
+    return false;
+  this->emitLabel(EndLabel);
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
+  const Stmt *Init = S->getInit();
+  const Expr *Cond = S->getCond();
+  const Expr *Inc = S->getInc();
+  const Stmt *Body = S->getBody();
+  const Stmt *BeginStmt = S->getBeginStmt();
+  const Stmt *RangeStmt = S->getRangeStmt();
+  const Stmt *EndStmt = S->getEndStmt();
+  const VarDecl *LoopVar = S->getLoopVariable();
+
+  LabelTy EndLabel = this->getLabel();
+  LabelTy CondLabel = this->getLabel();
+  LabelTy IncLabel = this->getLabel();
+  LoopScope<Emitter> LS(this, EndLabel, IncLabel);
+
+  // Emit declarations needed in the loop.
+  if (Init && !this->visitStmt(Init))
+    return false;
+  if (!this->visitStmt(RangeStmt))
+    return false;
+  if (!this->visitStmt(BeginStmt))
+    return false;
+  if (!this->visitStmt(EndStmt))
+    return false;
+
+  // Now the condition as well as the loop variable assignment.
+  this->emitLabel(CondLabel);
+  if (!this->visitBool(Cond))
+    return false;
+  if (!this->jumpFalse(EndLabel))
+    return false;
+
+  if (!this->visitVarDecl(LoopVar))
+    return false;
+
+  // Body.
+  LocalScope<Emitter> Scope(this);
+  {
+    DestructorScope<Emitter> DS(Scope);
+
+    if (!this->visitLoopBody(Body))
+      return false;
+    this->emitLabel(IncLabel);
+    if (!this->discard(Inc))
+      return false;
+  }
+  if (!this->jump(CondLabel))
+    return false;
+
+  this->emitLabel(EndLabel);
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
+  if (!BreakLabel)
+    return false;
+
+  this->VarScope->emitDestructors();
+  return this->jump(*BreakLabel);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
+  if (!ContinueLabel)
+    return false;
+
+  this->VarScope->emitDestructors();
+  return this->jump(*ContinueLabel);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
+  const Expr *Cond = S->getCond();
+  PrimType CondT = this->classifyPrim(Cond->getType());
+
+  LabelTy EndLabel = this->getLabel();
+  OptLabelTy DefaultLabel = std::nullopt;
+  unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false);
+
+  if (const auto *CondInit = S->getInit())
+    if (!visitStmt(CondInit))
+      return false;
+
+  if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
+    if (!visitDeclStmt(CondDecl))
+      return false;
+
+  // Initialize condition variable.
+  if (!this->visit(Cond))
+    return false;
+  if (!this->emitSetLocal(CondT, CondVar, S))
+    return false;
+
+  CaseMap CaseLabels;
+  // Create labels and comparison ops for all case statements.
+  for (const SwitchCase *SC = S->getSwitchCaseList(); SC;
+       SC = SC->getNextSwitchCase()) {
+    if (const auto *CS = dyn_cast<CaseStmt>(SC)) {
+      // FIXME: Implement ranges.
+      if (CS->caseStmtIsGNURange())
+        return false;
+      CaseLabels[SC] = this->getLabel();
+
+      const Expr *Value = CS->getLHS();
+      PrimType ValueT = this->classifyPrim(Value->getType());
+
+      // Compare the case statement's value to the switch condition.
+      if (!this->emitGetLocal(CondT, CondVar, CS))
+        return false;
+      if (!this->visit(Value))
+        return false;
+
+      // Compare and jump to the case label.
+      if (!this->emitEQ(ValueT, S))
+        return false;
+      if (!this->jumpTrue(CaseLabels[CS]))
+        return false;
+    } else {
+      assert(!DefaultLabel);
+      DefaultLabel = this->getLabel();
+    }
+  }
+
+  // If none of the conditions above were true, fall through to the default
+  // statement or jump after the switch statement.
+  if (DefaultLabel) {
+    if (!this->jump(*DefaultLabel))
+      return false;
+  } else {
+    if (!this->jump(EndLabel))
+      return false;
+  }
+
+  SwitchScope<Emitter> SS(this, std::move(CaseLabels), EndLabel, DefaultLabel);
+  if (!this->visitStmt(S->getBody()))
+    return false;
+  this->emitLabel(EndLabel);
+  return true;
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitCaseStmt(const CaseStmt *S) {
+  this->emitLabel(CaseLabels[S]);
+  return this->visitStmt(S->getSubStmt());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) {
+  this->emitLabel(*DefaultLabel);
+  return this->visitStmt(S->getSubStmt());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
+  if (this->Ctx.getLangOpts().CXXAssumptions &&
+      !this->Ctx.getLangOpts().MSVCCompat) {
+    for (const Attr *A : S->getAttrs()) {
+      auto *AA = dyn_cast<CXXAssumeAttr>(A);
+      if (!AA)
+        continue;
+
+      assert(isa<NullStmt>(S->getSubStmt()));
+
+      const Expr *Assumption = AA->getAssumption();
+      if (Assumption->isValueDependent())
+        return false;
+
+      if (Assumption->HasSideEffects(this->Ctx.getASTContext()))
+        continue;
+
+      // Evaluate assumption.
+      if (!this->visitBool(Assumption))
+        return false;
+
+      if (!this->emitAssume(Assumption))
+        return false;
+    }
+  }
+
+  // Ignore other attributes.
+  return this->visitStmt(S->getSubStmt());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) {
+  // Ignore all handlers.
+  return this->visitStmt(S->getTryBlock());
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::emitLambdaStaticInvokerBody(
+    const CXXMethodDecl *MD) {
+  assert(MD->isLambdaStaticInvoker());
+  assert(MD->hasBody());
+  assert(cast<CompoundStmt>(MD->getBody())->body_empty());
+
+  const CXXRecordDecl *ClosureClass = MD->getParent();
+  const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator();
+  assert(ClosureClass->captures_begin() == ClosureClass->captures_end());
+  const Function *Func = this->getFunction(LambdaCallOp);
+  if (!Func)
+    return false;
+  assert(Func->hasThisPointer());
+  assert(Func->getNumParams() == (MD->getNumParams() + 1 + Func->hasRVO()));
+
+  if (Func->hasRVO()) {
+    if (!this->emitRVOPtr(MD))
+      return false;
+  }
+
+  // The lambda call operator needs an instance pointer, but we don't have
+  // one here, and we don't need one either because the lambda cannot have
+  // any captures, as verified above. Emit a null pointer. This is then
+  // special-cased when interpreting to not emit any misleading diagnostics.
+  if (!this->emitNullPtr(nullptr, MD))
+    return false;
+
+  // Forward all arguments from the static invoker to the lambda call operator.
+  for (const ParmVarDecl *PVD : MD->parameters()) {
+    auto It = this->Params.find(PVD);
+    assert(It != this->Params.end());
+
+    // We do the lvalue-to-rvalue conversion manually here, so no need
+    // to care about references.
+    PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr);
+    if (!this->emitGetParam(ParamType, It->second.Offset, MD))
+      return false;
+  }
+
+  if (!this->emitCall(Func, 0, LambdaCallOp))
+    return false;
+
+  this->emitCleanup();
+  if (ReturnType)
+    return this->emitRet(*ReturnType, MD);
+
+  // Nothing to do, since we emitted the RVO pointer above.
+  return this->emitRetVoid(MD);
+}
+
+template <class Emitter>
+bool ByteCodeExprGen<Emitter>::visitFunc(const FunctionDecl *F) {
+
+  // Classify the return type.
+  ReturnType = this->classify(F->getReturnType());
+
+  auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset,
+                                  const Expr *InitExpr) -> bool {
+    // We don't know what to do with these, so just return false.
+    if (InitExpr->getType().isNull())
+      return false;
+
+    if (std::optional<PrimType> T = this->classify(InitExpr)) {
+      if (!this->visit(InitExpr))
+        return false;
+
+      if (F->isBitField())
+        return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr);
+      return this->emitInitThisField(*T, FieldOffset, InitExpr);
+    }
+    // Non-primitive case. Get a pointer to the field-to-initialize
+    // on the stack and call visitInitialzer() for it.
+    if (!this->emitGetPtrThisField(FieldOffset, InitExpr))
+      return false;
+
+    if (!this->visitInitializer(InitExpr))
+      return false;
+
+    return this->emitPopPtr(InitExpr);
+  };
+
+  // Emit custom code if this is a lambda static invoker.
+  if (const auto *MD = dyn_cast<CXXMethodDecl>(F);
+      MD && MD->isLambdaStaticInvoker())
+    return this->emitLambdaStaticInvokerBody(MD);
+
+  // Constructor. Set up field initializers.
+  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(F)) {
+    const RecordDecl *RD = Ctor->getParent();
+    const Record *R = this->getRecord(RD);
+    if (!R)
+      return false;
+
+    for (const auto *Init : Ctor->inits()) {
+      // Scope needed for the initializers.
+      BlockScope<Emitter> Scope(this);
+
+      const Expr *InitExpr = Init->getInit();
+      if (const FieldDecl *Member = Init->getMember()) {
+        const Record::Field *F = R->getField(Member);
+
+        if (!emitFieldInitializer(F, F->Offset, InitExpr))
+          return false;
+      } else if (const Type *Base = Init->getBaseClass()) {
+        const auto *BaseDecl = Base->getAsCXXRecordDecl();
+        assert(BaseDecl);
+
+        if (Init->isBaseVirtual()) {
+          assert(R->getVirtualBase(BaseDecl));
+          if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr))
+            return false;
+
+        } else {
+          // Base class initializer.
+          // Get This Base and call initializer on it.
+          const Record::Base *B = R->getBase(BaseDecl);
+          assert(B);
+          if (!this->emitGetPtrThisBase(B->Offset, InitExpr))
+            return false;
+        }
+
+        if (!this->visitInitializer(InitExpr))
+          return false;
+        if (!this->emitFinishInitPop(InitExpr))
+          return false;
+      } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) {
+        assert(IFD->getChainingSize() >= 2);
+
+        unsigned NestedFieldOffset = 0;
+        const Record::Field *NestedField = nullptr;
+        for (const NamedDecl *ND : IFD->chain()) {
+          const auto *FD = cast<FieldDecl>(ND);
+          const Record *FieldRecord =
+              this->P.getOrCreateRecord(FD->getParent());
+          assert(FieldRecord);
+
+          NestedField = FieldRecord->getField(FD);
+          assert(NestedField);
+
+          NestedFieldOffset += NestedField->Offset;
+        }
+        assert(NestedField);
+
+        if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr))
+          return false;
+      } else {
+        assert(Init->isDelegatingInitializer());
+        if (!this->emitThis(InitExpr))
+          return false;
+        if (!this->visitInitializer(Init->getInit()))
+          return false;
+        if (!this->emitPopPtr(InitExpr))
+          return false;
+      }
+    }
+  }
+
+  if (const auto *Body = F->getBody())
+    if (!visitStmt(Body))
+      return false;
+
+  // Emit a guard return to protect against a code path missing one.
+  if (F->getReturnType()->isVoidType())
+    return this->emitRetVoid(SourceInfo{});
+  return this->emitNoRet(SourceInfo{});
+}
+
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
   const Expr *SubExpr = E->getSubExpr();
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 7bb5304cac71e..40955dd43a907 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -35,6 +35,9 @@ template <class Emitter> class DeclScope;
 template <class Emitter> class OptionScope;
 template <class Emitter> class ArrayIndexScope;
 template <class Emitter> class SourceLocScope;
+template <class Emitter> class LoopScope;
+template <class Emitter> class LabelScope;
+template <class Emitter> class SwitchScope;
 
 /// Compilation context for expressions.
 template <class Emitter>
@@ -44,6 +47,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   // Aliases for types defined in the emitter.
   using LabelTy = typename Emitter::LabelTy;
   using AddrTy = typename Emitter::AddrTy;
+  using OptLabelTy = std::optional<LabelTy>;
+  using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
 
   /// Current compilation context.
   Context &Ctx;
@@ -56,7 +61,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
       : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
 
-  // Expression visitors - result returned on interp stack.
+  // Expressions.
   bool VisitCastExpr(const CastExpr *E);
   bool VisitIntegerLiteral(const IntegerLiteral *E);
   bool VisitFloatingLiteral(const FloatingLiteral *E);
@@ -130,9 +135,29 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
   bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
 
+  // Statements.
+  bool visitCompoundStmt(const CompoundStmt *S);
+  bool visitLoopBody(const Stmt *S);
+  bool visitDeclStmt(const DeclStmt *DS);
+  bool visitReturnStmt(const ReturnStmt *RS);
+  bool visitIfStmt(const IfStmt *IS);
+  bool visitWhileStmt(const WhileStmt *S);
+  bool visitDoStmt(const DoStmt *S);
+  bool visitForStmt(const ForStmt *S);
+  bool visitCXXForRangeStmt(const CXXForRangeStmt *S);
+  bool visitBreakStmt(const BreakStmt *S);
+  bool visitContinueStmt(const ContinueStmt *S);
+  bool visitSwitchStmt(const SwitchStmt *S);
+  bool visitCaseStmt(const CaseStmt *S);
+  bool visitDefaultStmt(const DefaultStmt *S);
+  bool visitAttributedStmt(const AttributedStmt *S);
+  bool visitCXXTryStmt(const CXXTryStmt *S);
+
 protected:
+  bool visitStmt(const Stmt *S);
   bool visitExpr(const Expr *E) override;
   bool visitDecl(const VarDecl *VD) override;
+  bool visitFunc(const FunctionDecl *F) override;
 
 protected:
   /// Emits scope cleanup instructions.
@@ -145,8 +170,8 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   Record *getRecord(QualType Ty);
   Record *getRecord(const RecordDecl *RD);
 
-  // Returns a function for the given FunctionDecl.
-  // If the function does not exist yet, it is compiled.
+  /// Returns a function for the given FunctionDecl.
+  /// If the function does not exist yet, it is compiled.
   const Function *getFunction(const FunctionDecl *FD);
 
   std::optional<PrimType> classify(const Expr *E) const {
@@ -255,6 +280,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   friend class OptionScope<Emitter>;
   friend class ArrayIndexScope<Emitter>;
   friend class SourceLocScope<Emitter>;
+  friend class LoopScope<Emitter>;
+  friend class LabelScope<Emitter>;
+  friend class SwitchScope<Emitter>;
 
   /// Emits a zero initializer.
   bool visitZeroInitializer(PrimType T, QualType QT, const Expr *E);
@@ -298,6 +326,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   bool emitDestruction(const Descriptor *Desc);
   unsigned collectBaseOffset(const QualType BaseType,
                              const QualType DerivedType);
+  bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
 
 protected:
   /// Variable to storage mapping.
@@ -325,6 +354,19 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
 
   /// Flag indicating if we're initializing a global variable.
   bool GlobalDecl = false;
+
+  /// Type of the expression returned by the function.
+  std::optional<PrimType> ReturnType;
+
+  /// Switch case mapping.
+  CaseMap CaseLabels;
+
+  /// Point to break to.
+  OptLabelTy BreakLabel;
+  /// Point to continue to.
+  OptLabelTy ContinueLabel;
+  /// Default case label.
+  OptLabelTy DefaultLabel;
 };
 
 extern template class ByteCodeExprGen<ByteCodeEmitter>;
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
deleted file mode 100644
index 6ee7898f228de..0000000000000
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ /dev/null
@@ -1,731 +0,0 @@
-//===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "ByteCodeStmtGen.h"
-#include "ByteCodeEmitter.h"
-#include "Context.h"
-#include "Function.h"
-#include "PrimType.h"
-
-using namespace clang;
-using namespace clang::interp;
-
-namespace clang {
-namespace interp {
-
-/// Scope managing label targets.
-template <class Emitter> class LabelScope {
-public:
-  virtual ~LabelScope() {  }
-
-protected:
-  LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {}
-  /// ByteCodeStmtGen instance.
-  ByteCodeStmtGen<Emitter> *Ctx;
-};
-
-/// Sets the context for break/continue statements.
-template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
-public:
-  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
-  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
-
-  LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel,
-            LabelTy ContinueLabel)
-      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
-        OldContinueLabel(Ctx->ContinueLabel) {
-    this->Ctx->BreakLabel = BreakLabel;
-    this->Ctx->ContinueLabel = ContinueLabel;
-  }
-
-  ~LoopScope() {
-    this->Ctx->BreakLabel = OldBreakLabel;
-    this->Ctx->ContinueLabel = OldContinueLabel;
-  }
-
-private:
-  OptLabelTy OldBreakLabel;
-  OptLabelTy OldContinueLabel;
-};
-
-// Sets the context for a switch scope, mapping labels.
-template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
-public:
-  using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy;
-  using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy;
-  using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap;
-
-  SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels,
-              LabelTy BreakLabel, OptLabelTy DefaultLabel)
-      : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
-        OldDefaultLabel(this->Ctx->DefaultLabel),
-        OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
-    this->Ctx->BreakLabel = BreakLabel;
-    this->Ctx->DefaultLabel = DefaultLabel;
-    this->Ctx->CaseLabels = std::move(CaseLabels);
-  }
-
-  ~SwitchScope() {
-    this->Ctx->BreakLabel = OldBreakLabel;
-    this->Ctx->DefaultLabel = OldDefaultLabel;
-    this->Ctx->CaseLabels = std::move(OldCaseLabels);
-  }
-
-private:
-  OptLabelTy OldBreakLabel;
-  OptLabelTy OldDefaultLabel;
-  CaseMap OldCaseLabels;
-};
-
-} // namespace interp
-} // namespace clang
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::emitLambdaStaticInvokerBody(
-    const CXXMethodDecl *MD) {
-  assert(MD->isLambdaStaticInvoker());
-  assert(MD->hasBody());
-  assert(cast<CompoundStmt>(MD->getBody())->body_empty());
-
-  const CXXRecordDecl *ClosureClass = MD->getParent();
-  const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator();
-  assert(ClosureClass->captures_begin() == ClosureClass->captures_end());
-  const Function *Func = this->getFunction(LambdaCallOp);
-  if (!Func)
-    return false;
-  assert(Func->hasThisPointer());
-  assert(Func->getNumParams() == (MD->getNumParams() + 1 + Func->hasRVO()));
-
-  if (Func->hasRVO()) {
-    if (!this->emitRVOPtr(MD))
-      return false;
-  }
-
-  // The lambda call operator needs an instance pointer, but we don't have
-  // one here, and we don't need one either because the lambda cannot have
-  // any captures, as verified above. Emit a null pointer. This is then
-  // special-cased when interpreting to not emit any misleading diagnostics.
-  if (!this->emitNullPtr(nullptr, MD))
-    return false;
-
-  // Forward all arguments from the static invoker to the lambda call operator.
-  for (const ParmVarDecl *PVD : MD->parameters()) {
-    auto It = this->Params.find(PVD);
-    assert(It != this->Params.end());
-
-    // We do the lvalue-to-rvalue conversion manually here, so no need
-    // to care about references.
-    PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr);
-    if (!this->emitGetParam(ParamType, It->second.Offset, MD))
-      return false;
-  }
-
-  if (!this->emitCall(Func, 0, LambdaCallOp))
-    return false;
-
-  this->emitCleanup();
-  if (ReturnType)
-    return this->emitRet(*ReturnType, MD);
-
-  // Nothing to do, since we emitted the RVO pointer above.
-  return this->emitRetVoid(MD);
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) {
-  // Classify the return type.
-  ReturnType = this->classify(F->getReturnType());
-
-  auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset,
-                                  const Expr *InitExpr) -> bool {
-    // We don't know what to do with these, so just return false.
-    if (InitExpr->getType().isNull())
-      return false;
-
-    if (std::optional<PrimType> T = this->classify(InitExpr)) {
-      if (!this->visit(InitExpr))
-        return false;
-
-      if (F->isBitField())
-        return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr);
-      return this->emitInitThisField(*T, FieldOffset, InitExpr);
-    }
-    // Non-primitive case. Get a pointer to the field-to-initialize
-    // on the stack and call visitInitialzer() for it.
-    if (!this->emitGetPtrThisField(FieldOffset, InitExpr))
-      return false;
-
-    if (!this->visitInitializer(InitExpr))
-      return false;
-
-    return this->emitPopPtr(InitExpr);
-  };
-
-  // Emit custom code if this is a lambda static invoker.
-  if (const auto *MD = dyn_cast<CXXMethodDecl>(F);
-      MD && MD->isLambdaStaticInvoker())
-    return this->emitLambdaStaticInvokerBody(MD);
-
-  // Constructor. Set up field initializers.
-  if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(F)) {
-    const RecordDecl *RD = Ctor->getParent();
-    const Record *R = this->getRecord(RD);
-    if (!R)
-      return false;
-
-    for (const auto *Init : Ctor->inits()) {
-      // Scope needed for the initializers.
-      BlockScope<Emitter> Scope(this);
-
-      const Expr *InitExpr = Init->getInit();
-      if (const FieldDecl *Member = Init->getMember()) {
-        const Record::Field *F = R->getField(Member);
-
-        if (!emitFieldInitializer(F, F->Offset, InitExpr))
-          return false;
-      } else if (const Type *Base = Init->getBaseClass()) {
-        const auto *BaseDecl = Base->getAsCXXRecordDecl();
-        assert(BaseDecl);
-
-        if (Init->isBaseVirtual()) {
-          assert(R->getVirtualBase(BaseDecl));
-          if (!this->emitGetPtrThisVirtBase(BaseDecl, InitExpr))
-            return false;
-
-        } else {
-          // Base class initializer.
-          // Get This Base and call initializer on it.
-          const Record::Base *B = R->getBase(BaseDecl);
-          assert(B);
-          if (!this->emitGetPtrThisBase(B->Offset, InitExpr))
-            return false;
-        }
-
-        if (!this->visitInitializer(InitExpr))
-          return false;
-        if (!this->emitFinishInitPop(InitExpr))
-          return false;
-      } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) {
-        assert(IFD->getChainingSize() >= 2);
-
-        unsigned NestedFieldOffset = 0;
-        const Record::Field *NestedField = nullptr;
-        for (const NamedDecl *ND : IFD->chain()) {
-          const auto *FD = cast<FieldDecl>(ND);
-          const Record *FieldRecord =
-              this->P.getOrCreateRecord(FD->getParent());
-          assert(FieldRecord);
-
-          NestedField = FieldRecord->getField(FD);
-          assert(NestedField);
-
-          NestedFieldOffset += NestedField->Offset;
-        }
-        assert(NestedField);
-
-        if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr))
-          return false;
-      } else {
-        assert(Init->isDelegatingInitializer());
-        if (!this->emitThis(InitExpr))
-          return false;
-        if (!this->visitInitializer(Init->getInit()))
-          return false;
-        if (!this->emitPopPtr(InitExpr))
-          return false;
-      }
-    }
-  }
-
-  if (const auto *Body = F->getBody())
-    if (!visitStmt(Body))
-      return false;
-
-  // Emit a guard return to protect against a code path missing one.
-  if (F->getReturnType()->isVoidType())
-    return this->emitRetVoid(SourceInfo{});
-  else
-    return this->emitNoRet(SourceInfo{});
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) {
-  switch (S->getStmtClass()) {
-  case Stmt::CompoundStmtClass:
-    return visitCompoundStmt(cast<CompoundStmt>(S));
-  case Stmt::DeclStmtClass:
-    return visitDeclStmt(cast<DeclStmt>(S));
-  case Stmt::ReturnStmtClass:
-    return visitReturnStmt(cast<ReturnStmt>(S));
-  case Stmt::IfStmtClass:
-    return visitIfStmt(cast<IfStmt>(S));
-  case Stmt::WhileStmtClass:
-    return visitWhileStmt(cast<WhileStmt>(S));
-  case Stmt::DoStmtClass:
-    return visitDoStmt(cast<DoStmt>(S));
-  case Stmt::ForStmtClass:
-    return visitForStmt(cast<ForStmt>(S));
-  case Stmt::CXXForRangeStmtClass:
-    return visitCXXForRangeStmt(cast<CXXForRangeStmt>(S));
-  case Stmt::BreakStmtClass:
-    return visitBreakStmt(cast<BreakStmt>(S));
-  case Stmt::ContinueStmtClass:
-    return visitContinueStmt(cast<ContinueStmt>(S));
-  case Stmt::SwitchStmtClass:
-    return visitSwitchStmt(cast<SwitchStmt>(S));
-  case Stmt::CaseStmtClass:
-    return visitCaseStmt(cast<CaseStmt>(S));
-  case Stmt::DefaultStmtClass:
-    return visitDefaultStmt(cast<DefaultStmt>(S));
-  case Stmt::AttributedStmtClass:
-    return visitAttributedStmt(cast<AttributedStmt>(S));
-  case Stmt::CXXTryStmtClass:
-    return visitCXXTryStmt(cast<CXXTryStmt>(S));
-  case Stmt::NullStmtClass:
-    return true;
-  // Always invalid statements.
-  case Stmt::GCCAsmStmtClass:
-  case Stmt::MSAsmStmtClass:
-  case Stmt::GotoStmtClass:
-    return this->emitInvalid(S);
-  case Stmt::LabelStmtClass:
-    return this->visitStmt(cast<LabelStmt>(S)->getSubStmt());
-  default: {
-    if (auto *Exp = dyn_cast<Expr>(S))
-      return this->discard(Exp);
-    return false;
-  }
-  }
-}
-
-/// Visits the given statment without creating a variable
-/// scope for it in case it is a compound statement.
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitLoopBody(const Stmt *S) {
-  if (isa<NullStmt>(S))
-    return true;
-
-  if (const auto *CS = dyn_cast<CompoundStmt>(S)) {
-    for (auto *InnerStmt : CS->body())
-      if (!visitStmt(InnerStmt))
-        return false;
-    return true;
-  }
-
-  return this->visitStmt(S);
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitCompoundStmt(
-    const CompoundStmt *CompoundStmt) {
-  BlockScope<Emitter> Scope(this);
-  for (auto *InnerStmt : CompoundStmt->body())
-    if (!visitStmt(InnerStmt))
-      return false;
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
-  for (auto *D : DS->decls()) {
-    if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl,
-            FunctionDecl>(D))
-      continue;
-
-    const auto *VD = dyn_cast<VarDecl>(D);
-    if (!VD)
-      return false;
-    if (!this->visitVarDecl(VD))
-      return false;
-  }
-
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
-  if (const Expr *RE = RS->getRetValue()) {
-    ExprScope<Emitter> RetScope(this);
-    if (ReturnType) {
-      // Primitive types are simply returned.
-      if (!this->visit(RE))
-        return false;
-      this->emitCleanup();
-      return this->emitRet(*ReturnType, RS);
-    } else if (RE->getType()->isVoidType()) {
-      if (!this->visit(RE))
-        return false;
-    } else {
-      // RVO - construct the value in the return location.
-      if (!this->emitRVOPtr(RE))
-        return false;
-      if (!this->visitInitializer(RE))
-        return false;
-      if (!this->emitPopPtr(RE))
-        return false;
-
-      this->emitCleanup();
-      return this->emitRetVoid(RS);
-    }
-  }
-
-  // Void return.
-  this->emitCleanup();
-  return this->emitRetVoid(RS);
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) {
-  BlockScope<Emitter> IfScope(this);
-
-  if (IS->isNonNegatedConsteval())
-    return visitStmt(IS->getThen());
-  if (IS->isNegatedConsteval())
-    return IS->getElse() ? visitStmt(IS->getElse()) : true;
-
-  if (auto *CondInit = IS->getInit())
-    if (!visitStmt(CondInit))
-      return false;
-
-  if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt())
-    if (!visitDeclStmt(CondDecl))
-      return false;
-
-  if (!this->visitBool(IS->getCond()))
-    return false;
-
-  if (const Stmt *Else = IS->getElse()) {
-    LabelTy LabelElse = this->getLabel();
-    LabelTy LabelEnd = this->getLabel();
-    if (!this->jumpFalse(LabelElse))
-      return false;
-    if (!visitStmt(IS->getThen()))
-      return false;
-    if (!this->jump(LabelEnd))
-      return false;
-    this->emitLabel(LabelElse);
-    if (!visitStmt(Else))
-      return false;
-    this->emitLabel(LabelEnd);
-  } else {
-    LabelTy LabelEnd = this->getLabel();
-    if (!this->jumpFalse(LabelEnd))
-      return false;
-    if (!visitStmt(IS->getThen()))
-      return false;
-    this->emitLabel(LabelEnd);
-  }
-
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
-  const Expr *Cond = S->getCond();
-  const Stmt *Body = S->getBody();
-
-  LabelTy CondLabel = this->getLabel(); // Label before the condition.
-  LabelTy EndLabel = this->getLabel();  // Label after the loop.
-  LoopScope<Emitter> LS(this, EndLabel, CondLabel);
-
-  this->emitLabel(CondLabel);
-
-  if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
-    if (!visitDeclStmt(CondDecl))
-      return false;
-
-  if (!this->visitBool(Cond))
-    return false;
-  if (!this->jumpFalse(EndLabel))
-    return false;
-
-  LocalScope<Emitter> Scope(this);
-  {
-    DestructorScope<Emitter> DS(Scope);
-    if (!this->visitLoopBody(Body))
-      return false;
-  }
-
-  if (!this->jump(CondLabel))
-    return false;
-  this->emitLabel(EndLabel);
-
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitDoStmt(const DoStmt *S) {
-  const Expr *Cond = S->getCond();
-  const Stmt *Body = S->getBody();
-
-  LabelTy StartLabel = this->getLabel();
-  LabelTy EndLabel = this->getLabel();
-  LabelTy CondLabel = this->getLabel();
-  LoopScope<Emitter> LS(this, EndLabel, CondLabel);
-  LocalScope<Emitter> Scope(this);
-
-  this->emitLabel(StartLabel);
-  {
-    DestructorScope<Emitter> DS(Scope);
-
-    if (!this->visitLoopBody(Body))
-      return false;
-    this->emitLabel(CondLabel);
-    if (!this->visitBool(Cond))
-      return false;
-  }
-  if (!this->jumpTrue(StartLabel))
-    return false;
-
-  this->emitLabel(EndLabel);
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitForStmt(const ForStmt *S) {
-  // for (Init; Cond; Inc) { Body }
-  const Stmt *Init = S->getInit();
-  const Expr *Cond = S->getCond();
-  const Expr *Inc = S->getInc();
-  const Stmt *Body = S->getBody();
-
-  LabelTy EndLabel = this->getLabel();
-  LabelTy CondLabel = this->getLabel();
-  LabelTy IncLabel = this->getLabel();
-  LoopScope<Emitter> LS(this, EndLabel, IncLabel);
-  LocalScope<Emitter> Scope(this);
-
-  if (Init && !this->visitStmt(Init))
-    return false;
-  this->emitLabel(CondLabel);
-
-  if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
-    if (!visitDeclStmt(CondDecl))
-      return false;
-  if (Cond) {
-    if (!this->visitBool(Cond))
-      return false;
-    if (!this->jumpFalse(EndLabel))
-      return false;
-  }
-
-  {
-    DestructorScope<Emitter> DS(Scope);
-
-    if (Body && !this->visitLoopBody(Body))
-      return false;
-    this->emitLabel(IncLabel);
-    if (Inc && !this->discard(Inc))
-      return false;
-  }
-
-  if (!this->jump(CondLabel))
-    return false;
-  this->emitLabel(EndLabel);
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
-  const Stmt *Init = S->getInit();
-  const Expr *Cond = S->getCond();
-  const Expr *Inc = S->getInc();
-  const Stmt *Body = S->getBody();
-  const Stmt *BeginStmt = S->getBeginStmt();
-  const Stmt *RangeStmt = S->getRangeStmt();
-  const Stmt *EndStmt = S->getEndStmt();
-  const VarDecl *LoopVar = S->getLoopVariable();
-
-  LabelTy EndLabel = this->getLabel();
-  LabelTy CondLabel = this->getLabel();
-  LabelTy IncLabel = this->getLabel();
-  LoopScope<Emitter> LS(this, EndLabel, IncLabel);
-
-  // Emit declarations needed in the loop.
-  if (Init && !this->visitStmt(Init))
-    return false;
-  if (!this->visitStmt(RangeStmt))
-    return false;
-  if (!this->visitStmt(BeginStmt))
-    return false;
-  if (!this->visitStmt(EndStmt))
-    return false;
-
-  // Now the condition as well as the loop variable assignment.
-  this->emitLabel(CondLabel);
-  if (!this->visitBool(Cond))
-    return false;
-  if (!this->jumpFalse(EndLabel))
-    return false;
-
-  if (!this->visitVarDecl(LoopVar))
-    return false;
-
-  // Body.
-  LocalScope<Emitter> Scope(this);
-  {
-    DestructorScope<Emitter> DS(Scope);
-
-    if (!this->visitLoopBody(Body))
-      return false;
-    this->emitLabel(IncLabel);
-    if (!this->discard(Inc))
-      return false;
-  }
-  if (!this->jump(CondLabel))
-    return false;
-
-  this->emitLabel(EndLabel);
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
-  if (!BreakLabel)
-    return false;
-
-  this->VarScope->emitDestructors();
-  return this->jump(*BreakLabel);
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
-  if (!ContinueLabel)
-    return false;
-
-  this->VarScope->emitDestructors();
-  return this->jump(*ContinueLabel);
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
-  const Expr *Cond = S->getCond();
-
-  LabelTy EndLabel = this->getLabel();
-  OptLabelTy DefaultLabel = std::nullopt;
-
-  if (const auto *CondInit = S->getInit())
-    if (!visitStmt(CondInit))
-      return false;
-
-  if (const DeclStmt *CondDecl = S->getConditionVariableDeclStmt())
-    if (!visitDeclStmt(CondDecl))
-      return false;
-
-  // Initialize condition variable.
-  PrimType CondT = this->classifyPrim(Cond->getType());
-  unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false);
-  if (!this->visit(Cond))
-    return false;
-  if (!this->emitSetLocal(CondT, CondVar, S))
-    return false;
-
-  CaseMap CaseLabels;
-  // Create labels and comparison ops for all case statements.
-  for (const SwitchCase *SC = S->getSwitchCaseList(); SC;
-       SC = SC->getNextSwitchCase()) {
-    if (const auto *CS = dyn_cast<CaseStmt>(SC)) {
-      // FIXME: Implement ranges.
-      if (CS->caseStmtIsGNURange())
-        return false;
-      CaseLabels[SC] = this->getLabel();
-
-      const Expr *Value = CS->getLHS();
-      PrimType ValueT = this->classifyPrim(Value->getType());
-
-      // Compare the case statement's value to the switch condition.
-      if (!this->emitGetLocal(CondT, CondVar, CS))
-        return false;
-      if (!this->visit(Value))
-        return false;
-
-      // Compare and jump to the case label.
-      if (!this->emitEQ(ValueT, S))
-        return false;
-      if (!this->jumpTrue(CaseLabels[CS]))
-        return false;
-    } else {
-      assert(!DefaultLabel);
-      DefaultLabel = this->getLabel();
-    }
-  }
-
-  // If none of the conditions above were true, fall through to the default
-  // statement or jump after the switch statement.
-  if (DefaultLabel) {
-    if (!this->jump(*DefaultLabel))
-      return false;
-  } else {
-    if (!this->jump(EndLabel))
-      return false;
-  }
-
-  SwitchScope<Emitter> SS(this, std::move(CaseLabels), EndLabel, DefaultLabel);
-  if (!this->visitStmt(S->getBody()))
-    return false;
-  this->emitLabel(EndLabel);
-  return true;
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitCaseStmt(const CaseStmt *S) {
-  this->emitLabel(CaseLabels[S]);
-  return this->visitStmt(S->getSubStmt());
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) {
-  this->emitLabel(*DefaultLabel);
-  return this->visitStmt(S->getSubStmt());
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
-
-  if (this->Ctx.getLangOpts().CXXAssumptions &&
-      !this->Ctx.getLangOpts().MSVCCompat) {
-    for (const Attr *A : S->getAttrs()) {
-      auto *AA = dyn_cast<CXXAssumeAttr>(A);
-      if (!AA)
-        continue;
-
-      assert(isa<NullStmt>(S->getSubStmt()));
-
-      const Expr *Assumption = AA->getAssumption();
-      if (Assumption->isValueDependent())
-        return false;
-
-      if (Assumption->HasSideEffects(this->Ctx.getASTContext()))
-        continue;
-
-      // Evaluate assumption.
-      if (!this->visitBool(Assumption))
-        return false;
-
-      if (!this->emitAssume(Assumption))
-        return false;
-    }
-  }
-
-  // Ignore other attributes.
-  return this->visitStmt(S->getSubStmt());
-}
-
-template <class Emitter>
-bool ByteCodeStmtGen<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) {
-  // Ignore all handlers.
-  return this->visitStmt(S->getTryBlock());
-}
-
-namespace clang {
-namespace interp {
-
-template class ByteCodeStmtGen<ByteCodeEmitter>;
-
-} // namespace interp
-} // namespace clang
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h
deleted file mode 100644
index d7e6e5042c274..0000000000000
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.h
+++ /dev/null
@@ -1,91 +0,0 @@
-//===--- ByteCodeStmtGen.h - Code generator for expressions -----*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Defines the constexpr bytecode compiler.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H
-#define LLVM_CLANG_AST_INTERP_BYTECODESTMTGEN_H
-
-#include "ByteCodeEmitter.h"
-#include "ByteCodeExprGen.h"
-#include "EvalEmitter.h"
-#include "PrimType.h"
-#include "clang/AST/StmtVisitor.h"
-
-namespace clang {
-namespace interp {
-
-template <class Emitter> class LoopScope;
-template <class Emitter> class SwitchScope;
-template <class Emitter> class LabelScope;
-
-/// Compilation context for statements.
-template <class Emitter>
-class ByteCodeStmtGen final : public ByteCodeExprGen<Emitter> {
-  using LabelTy = typename Emitter::LabelTy;
-  using AddrTy = typename Emitter::AddrTy;
-  using OptLabelTy = std::optional<LabelTy>;
-  using CaseMap = llvm::DenseMap<const SwitchCase *, LabelTy>;
-
-public:
-  template<typename... Tys>
-  ByteCodeStmtGen(Tys&&... Args)
-      : ByteCodeExprGen<Emitter>(std::forward<Tys>(Args)...) {}
-
-protected:
-  bool visitFunc(const FunctionDecl *F) override;
-
-private:
-  friend class LabelScope<Emitter>;
-  friend class LoopScope<Emitter>;
-  friend class SwitchScope<Emitter>;
-
-  // Statement visitors.
-  bool visitStmt(const Stmt *S);
-  bool visitCompoundStmt(const CompoundStmt *S);
-  bool visitLoopBody(const Stmt *S);
-  bool visitDeclStmt(const DeclStmt *DS);
-  bool visitReturnStmt(const ReturnStmt *RS);
-  bool visitIfStmt(const IfStmt *IS);
-  bool visitWhileStmt(const WhileStmt *S);
-  bool visitDoStmt(const DoStmt *S);
-  bool visitForStmt(const ForStmt *S);
-  bool visitCXXForRangeStmt(const CXXForRangeStmt *S);
-  bool visitBreakStmt(const BreakStmt *S);
-  bool visitContinueStmt(const ContinueStmt *S);
-  bool visitSwitchStmt(const SwitchStmt *S);
-  bool visitCaseStmt(const CaseStmt *S);
-  bool visitDefaultStmt(const DefaultStmt *S);
-  bool visitAttributedStmt(const AttributedStmt *S);
-  bool visitCXXTryStmt(const CXXTryStmt *S);
-
-  bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD);
-
-  /// Type of the expression returned by the function.
-  std::optional<PrimType> ReturnType;
-
-  /// Switch case mapping.
-  CaseMap CaseLabels;
-
-  /// Point to break to.
-  OptLabelTy BreakLabel;
-  /// Point to continue to.
-  OptLabelTy ContinueLabel;
-  /// Default case label.
-  OptLabelTy DefaultLabel;
-};
-
-extern template class ByteCodeStmtGen<ByteCodeEmitter>;
-extern template class ByteCodeExprGen<EvalEmitter>;
-
-} // namespace interp
-} // namespace clang
-
-#endif
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 98d1837204ebc..338165e03586a 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -9,7 +9,6 @@
 #include "Context.h"
 #include "ByteCodeEmitter.h"
 #include "ByteCodeExprGen.h"
-#include "ByteCodeStmtGen.h"
 #include "EvalEmitter.h"
 #include "Interp.h"
 #include "InterpFrame.h"
@@ -30,7 +29,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
   assert(Stk.empty());
   Function *Func = P->getFunction(FD);
   if (!Func || !Func->hasBody())
-    Func = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD);
+    Func = ByteCodeExprGen<ByteCodeEmitter>(*this, *P).compileFunc(FD);
 
   APValue DummyResult;
   if (!Run(Parent, Func, DummyResult))
@@ -261,7 +260,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {
     return Func;
 
   if (!Func || WasNotDefined) {
-    if (auto F = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD))
+    if (auto F = ByteCodeExprGen<ByteCodeEmitter>(*this, *P).compileFunc(FD))
       Func = F;
   }
 
diff --git a/clang/lib/AST/Interp/EvalEmitter.h b/clang/lib/AST/Interp/EvalEmitter.h
index 98d6026bbcce4..d9da2dc447759 100644
--- a/clang/lib/AST/Interp/EvalEmitter.h
+++ b/clang/lib/AST/Interp/EvalEmitter.h
@@ -56,6 +56,7 @@ class EvalEmitter : public SourceMapper {
   /// Methods implemented by the compiler.
   virtual bool visitExpr(const Expr *E) = 0;
   virtual bool visitDecl(const VarDecl *VD) = 0;
+  virtual bool visitFunc(const FunctionDecl *F) = 0;
 
   /// Emits jumps.
   bool jumpTrue(const LabelTy &Label);
diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp
index 7b1f719779e90..caff9d01cdfee 100644
--- a/clang/lib/AST/Interp/Program.cpp
+++ b/clang/lib/AST/Interp/Program.cpp
@@ -7,7 +7,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "Program.h"
-#include "ByteCodeStmtGen.h"
 #include "Context.h"
 #include "Function.h"
 #include "Integral.h"

>From b7f80c752528c291300885fd9f916f82bd2496ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 2 Mar 2024 17:12:54 +0100
Subject: [PATCH 2/3] [clang][Interp] Rename ByteCodeExprGen to Compiler

---
 clang/lib/AST/CMakeLists.txt                  |   2 +-
 .../{ByteCodeExprGen.cpp => Compiler.cpp}     | 354 ++++++++----------
 .../Interp/{ByteCodeExprGen.h => Compiler.h}  |  36 +-
 clang/lib/AST/Interp/Context.cpp              |  12 +-
 4 files changed, 189 insertions(+), 215 deletions(-)
 rename clang/lib/AST/Interp/{ByteCodeExprGen.cpp => Compiler.cpp} (92%)
 rename clang/lib/AST/Interp/{ByteCodeExprGen.h => Compiler.h} (94%)

diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt
index c5196fbf7ef74..9eae6cc499a4a 100644
--- a/clang/lib/AST/CMakeLists.txt
+++ b/clang/lib/AST/CMakeLists.txt
@@ -65,7 +65,7 @@ add_clang_library(clangAST
   FormatString.cpp
   InheritViz.cpp
   Interp/ByteCodeEmitter.cpp
-  Interp/ByteCodeExprGen.cpp
+  Interp/Compiler.cpp
   Interp/Context.cpp
   Interp/Descriptor.cpp
   Interp/Disasm.cpp
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/Compiler.cpp
similarity index 92%
rename from clang/lib/AST/Interp/ByteCodeExprGen.cpp
rename to clang/lib/AST/Interp/Compiler.cpp
index 3e06e25c02559..4f424b2a60871 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -1,4 +1,4 @@
-//===--- ByteCodeExprGen.cpp - Code generator for expressions ---*- C++ -*-===//
+//===--- Compiler.cpp - Code generator for expressions ---*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "ByteCodeExprGen.h"
+#include "Compiler.h"
 #include "ByteCodeEmitter.h"
 #include "Context.h"
 #include "Floating.h"
@@ -27,7 +27,7 @@ namespace interp {
 /// Scope used to handle temporaries in toplevel variable declarations.
 template <class Emitter> class DeclScope final : public VariableScope<Emitter> {
 public:
-  DeclScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
+  DeclScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
       : VariableScope<Emitter>(Ctx, nullptr), Scope(Ctx->P, VD),
         OldGlobalDecl(Ctx->GlobalDecl),
         OldInitializingDecl(Ctx->InitializingDecl) {
@@ -35,6 +35,10 @@ template <class Emitter> class DeclScope final : public VariableScope<Emitter> {
     Ctx->InitializingDecl = VD;
   }
 
+  void addExtended(const Scope::Local &Local) override {
+    return this->addLocal(Local);
+  }
+
   ~DeclScope() {
     this->Ctx->GlobalDecl = OldGlobalDecl;
     this->Ctx->InitializingDecl = OldInitializingDecl;
@@ -50,7 +54,7 @@ template <class Emitter> class DeclScope final : public VariableScope<Emitter> {
 template <class Emitter> class OptionScope final {
 public:
   /// Root constructor, compiling or discarding primitives.
-  OptionScope(ByteCodeExprGen<Emitter> *Ctx, bool NewDiscardResult,
+  OptionScope(Compiler<Emitter> *Ctx, bool NewDiscardResult,
               bool NewInitializing)
       : Ctx(Ctx), OldDiscardResult(Ctx->DiscardResult),
         OldInitializing(Ctx->Initializing) {
@@ -65,7 +69,7 @@ template <class Emitter> class OptionScope final {
 
 private:
   /// Parent context.
-  ByteCodeExprGen<Emitter> *Ctx;
+  Compiler<Emitter> *Ctx;
   /// Old discard flag to restore.
   bool OldDiscardResult;
   bool OldInitializing;
@@ -77,19 +81,18 @@ template <class Emitter> class LabelScope {
   virtual ~LabelScope() {}
 
 protected:
-  LabelScope(ByteCodeExprGen<Emitter> *Ctx) : Ctx(Ctx) {}
-  /// ByteCodeExprGen instance.
-  ByteCodeExprGen<Emitter> *Ctx;
+  LabelScope(Compiler<Emitter> *Ctx) : Ctx(Ctx) {}
+  /// Compiler instance.
+  Compiler<Emitter> *Ctx;
 };
 
 /// Sets the context for break/continue statements.
 template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
 public:
-  using LabelTy = typename ByteCodeExprGen<Emitter>::LabelTy;
-  using OptLabelTy = typename ByteCodeExprGen<Emitter>::OptLabelTy;
+  using LabelTy = typename Compiler<Emitter>::LabelTy;
+  using OptLabelTy = typename Compiler<Emitter>::OptLabelTy;
 
-  LoopScope(ByteCodeExprGen<Emitter> *Ctx, LabelTy BreakLabel,
-            LabelTy ContinueLabel)
+  LoopScope(Compiler<Emitter> *Ctx, LabelTy BreakLabel, LabelTy ContinueLabel)
       : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
         OldContinueLabel(Ctx->ContinueLabel) {
     this->Ctx->BreakLabel = BreakLabel;
@@ -109,12 +112,12 @@ template <class Emitter> class LoopScope final : public LabelScope<Emitter> {
 // Sets the context for a switch scope, mapping labels.
 template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
 public:
-  using LabelTy = typename ByteCodeExprGen<Emitter>::LabelTy;
-  using OptLabelTy = typename ByteCodeExprGen<Emitter>::OptLabelTy;
-  using CaseMap = typename ByteCodeExprGen<Emitter>::CaseMap;
+  using LabelTy = typename Compiler<Emitter>::LabelTy;
+  using OptLabelTy = typename Compiler<Emitter>::OptLabelTy;
+  using CaseMap = typename Compiler<Emitter>::CaseMap;
 
-  SwitchScope(ByteCodeExprGen<Emitter> *Ctx, CaseMap &&CaseLabels,
-              LabelTy BreakLabel, OptLabelTy DefaultLabel)
+  SwitchScope(Compiler<Emitter> *Ctx, CaseMap &&CaseLabels, LabelTy BreakLabel,
+              OptLabelTy DefaultLabel)
       : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel),
         OldDefaultLabel(this->Ctx->DefaultLabel),
         OldCaseLabels(std::move(this->Ctx->CaseLabels)) {
@@ -139,7 +142,7 @@ template <class Emitter> class SwitchScope final : public LabelScope<Emitter> {
 } // namespace clang
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
+bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {
   const Expr *SubExpr = CE->getSubExpr();
   switch (CE->getCastKind()) {
 
@@ -577,7 +580,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
+bool Compiler<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
   if (DiscardResult)
     return true;
 
@@ -585,7 +588,7 @@ bool ByteCodeExprGen<Emitter>::VisitIntegerLiteral(const IntegerLiteral *LE) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) {
+bool Compiler<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) {
   if (DiscardResult)
     return true;
 
@@ -593,8 +596,7 @@ bool ByteCodeExprGen<Emitter>::VisitFloatingLiteral(const FloatingLiteral *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitImaginaryLiteral(
-    const ImaginaryLiteral *E) {
+bool Compiler<Emitter>::VisitImaginaryLiteral(const ImaginaryLiteral *E) {
   assert(E->getType()->isAnyComplexType());
   if (DiscardResult)
     return true;
@@ -618,12 +620,12 @@ bool ByteCodeExprGen<Emitter>::VisitImaginaryLiteral(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitParenExpr(const ParenExpr *E) {
+bool Compiler<Emitter>::VisitParenExpr(const ParenExpr *E) {
   return this->delegate(E->getSubExpr());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
+bool Compiler<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
   // Need short-circuiting for these.
   if (BO->isLogicalOp())
     return this->VisitLogicalBinOp(BO);
@@ -795,7 +797,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
 /// Perform addition/subtraction of a pointer and an integer or
 /// subtraction of two pointers.
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
+bool Compiler<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
   BinaryOperatorKind Op = E->getOpcode();
   const Expr *LHS = E->getLHS();
   const Expr *RHS = E->getRHS();
@@ -843,7 +845,7 @@ bool ByteCodeExprGen<Emitter>::VisitPointerArithBinOp(const BinaryOperator *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
+bool Compiler<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
   assert(E->isLogicalOp());
   BinaryOperatorKind Op = E->getOpcode();
   const Expr *LHS = E->getLHS();
@@ -904,7 +906,7 @@ bool ByteCodeExprGen<Emitter>::VisitLogicalBinOp(const BinaryOperator *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
+bool Compiler<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
   // Prepare storage for result.
   if (!Initializing) {
     std::optional<unsigned> LocalIndex = allocateLocal(E);
@@ -1048,7 +1050,8 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) {
+bool Compiler<Emitter>::VisitImplicitValueInitExpr(
+    const ImplicitValueInitExpr *E) {
   QualType QT = E->getType();
 
   if (std::optional<PrimType> T = classify(QT))
@@ -1131,8 +1134,7 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr(
-    const ArraySubscriptExpr *E) {
+bool Compiler<Emitter>::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
   const Expr *Base = E->getBase();
   const Expr *Index = E->getIdx();
 
@@ -1152,9 +1154,9 @@ bool ByteCodeExprGen<Emitter>::VisitArraySubscriptExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
+bool Compiler<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
                                              const Expr *ArrayFiller,
-                                             const Expr *E) {
+                                      const Expr *E) {
   if (E->getType()->isVoidType())
     return this->emitInvalid(E);
 
@@ -1390,8 +1392,8 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
 /// Pointer to the array(not the element!) must be on the stack when calling
 /// this.
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitArrayElemInit(unsigned ElemIndex,
-                                                  const Expr *Init) {
+bool Compiler<Emitter>::visitArrayElemInit(unsigned ElemIndex,
+                                           const Expr *Init) {
   if (std::optional<PrimType> T = classify(Init->getType())) {
     // Visit the primitive element like normal.
     if (!this->visit(Init))
@@ -1411,24 +1413,24 @@ bool ByteCodeExprGen<Emitter>::visitArrayElemInit(unsigned ElemIndex,
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
+bool Compiler<Emitter>::VisitInitListExpr(const InitListExpr *E) {
   return this->visitInitList(E->inits(), E->getArrayFiller(), E);
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXParenListInitExpr(
+bool Compiler<Emitter>::VisitCXXParenListInitExpr(
     const CXXParenListInitExpr *E) {
   return this->visitInitList(E->getInitExprs(), E->getArrayFiller(), E);
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitSubstNonTypeTemplateParmExpr(
+bool Compiler<Emitter>::VisitSubstNonTypeTemplateParmExpr(
     const SubstNonTypeTemplateParmExpr *E) {
   return this->delegate(E->getReplacement());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
+bool Compiler<Emitter>::VisitConstantExpr(const ConstantExpr *E) {
   std::optional<PrimType> T = classify(E->getType());
   if (T && E->hasAPValueResult()) {
     // Try to emit the APValue directly, without visiting the subexpr.
@@ -1467,7 +1469,7 @@ static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx,
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
+bool Compiler<Emitter>::VisitUnaryExprOrTypeTraitExpr(
     const UnaryExprOrTypeTraitExpr *E) {
   UnaryExprOrTypeTrait Kind = E->getKind();
   const ASTContext &ASTCtx = Ctx.getASTContext();
@@ -1559,7 +1561,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryExprOrTypeTraitExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
+bool Compiler<Emitter>::VisitMemberExpr(const MemberExpr *E) {
   // 'Base.Member'
   const Expr *Base = E->getBase();
   const ValueDecl *Member = E->getMemberDecl();
@@ -1611,8 +1613,7 @@ bool ByteCodeExprGen<Emitter>::VisitMemberExpr(const MemberExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
-    const ArrayInitIndexExpr *E) {
+bool Compiler<Emitter>::VisitArrayInitIndexExpr(const ArrayInitIndexExpr *E) {
   // ArrayIndex might not be set if a ArrayInitIndexExpr is being evaluated
   // stand-alone, e.g. via EvaluateAsInt().
   if (!ArrayIndex)
@@ -1621,8 +1622,7 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitIndexExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr(
-    const ArrayInitLoopExpr *E) {
+bool Compiler<Emitter>::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
   assert(Initializing);
   assert(!DiscardResult);
 
@@ -1650,7 +1650,7 @@ bool ByteCodeExprGen<Emitter>::VisitArrayInitLoopExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
+bool Compiler<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
   const Expr *SourceExpr = E->getSourceExpr();
   if (!SourceExpr)
     return false;
@@ -1686,7 +1686,7 @@ bool ByteCodeExprGen<Emitter>::VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator(
+bool Compiler<Emitter>::VisitAbstractConditionalOperator(
     const AbstractConditionalOperator *E) {
   const Expr *Condition = E->getCond();
   const Expr *TrueExpr = E->getTrueExpr();
@@ -1718,7 +1718,7 @@ bool ByteCodeExprGen<Emitter>::VisitAbstractConditionalOperator(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) {
+bool Compiler<Emitter>::VisitStringLiteral(const StringLiteral *E) {
   if (DiscardResult)
     return true;
 
@@ -1775,13 +1775,13 @@ bool ByteCodeExprGen<Emitter>::VisitStringLiteral(const StringLiteral *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitObjCStringLiteral(
+bool Compiler<Emitter>::VisitObjCStringLiteral(
     const ObjCStringLiteral *E) {
   return this->delegate(E->getString());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
+bool Compiler<Emitter>::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
   auto &A = Ctx.getASTContext();
   std::string Str;
   A.getObjCEncodingForType(E->getEncodedType(), Str);
@@ -1792,7 +1792,7 @@ bool ByteCodeExprGen<Emitter>::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitSYCLUniqueStableNameExpr(
+bool Compiler<Emitter>::VisitSYCLUniqueStableNameExpr(
     const SYCLUniqueStableNameExpr *E) {
   if (DiscardResult)
     return true;
@@ -1816,7 +1816,7 @@ bool ByteCodeExprGen<Emitter>::VisitSYCLUniqueStableNameExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCharacterLiteral(
+bool Compiler<Emitter>::VisitCharacterLiteral(
     const CharacterLiteral *E) {
   if (DiscardResult)
     return true;
@@ -1824,7 +1824,7 @@ bool ByteCodeExprGen<Emitter>::VisitCharacterLiteral(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitFloatCompoundAssignOperator(
+bool Compiler<Emitter>::VisitFloatCompoundAssignOperator(
     const CompoundAssignOperator *E) {
 
   const Expr *LHS = E->getLHS();
@@ -1898,7 +1898,7 @@ bool ByteCodeExprGen<Emitter>::VisitFloatCompoundAssignOperator(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitPointerCompoundAssignOperator(
+bool Compiler<Emitter>::VisitPointerCompoundAssignOperator(
     const CompoundAssignOperator *E) {
   BinaryOperatorKind Op = E->getOpcode();
   const Expr *LHS = E->getLHS();
@@ -1935,7 +1935,7 @@ bool ByteCodeExprGen<Emitter>::VisitPointerCompoundAssignOperator(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
+bool Compiler<Emitter>::VisitCompoundAssignOperator(
     const CompoundAssignOperator *E) {
 
   const Expr *LHS = E->getLHS();
@@ -2056,8 +2056,7 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundAssignOperator(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups(
-    const ExprWithCleanups *E) {
+bool Compiler<Emitter>::VisitExprWithCleanups(const ExprWithCleanups *E) {
   ExprScope<Emitter> ES(this);
   const Expr *SubExpr = E->getSubExpr();
 
@@ -2067,7 +2066,7 @@ bool ByteCodeExprGen<Emitter>::VisitExprWithCleanups(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
+bool Compiler<Emitter>::VisitMaterializeTemporaryExpr(
     const MaterializeTemporaryExpr *E) {
   const Expr *SubExpr = E->getSubExpr();
 
@@ -2139,14 +2138,13 @@ bool ByteCodeExprGen<Emitter>::VisitMaterializeTemporaryExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXBindTemporaryExpr(
+bool Compiler<Emitter>::VisitCXXBindTemporaryExpr(
     const CXXBindTemporaryExpr *E) {
   return this->delegate(E->getSubExpr());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(
-    const CompoundLiteralExpr *E) {
+bool Compiler<Emitter>::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
   const Expr *Init = E->getInitializer();
   if (Initializing) {
     // We already have a value, just initialize that.
@@ -2211,7 +2209,7 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) {
+bool Compiler<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) {
   if (DiscardResult)
     return true;
   if (E->getType()->isBooleanType())
@@ -2220,15 +2218,14 @@ bool ByteCodeExprGen<Emitter>::VisitTypeTraitExpr(const TypeTraitExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitArrayTypeTraitExpr(
-    const ArrayTypeTraitExpr *E) {
+bool Compiler<Emitter>::VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
   if (DiscardResult)
     return true;
   return this->emitConst(E->getValue(), E);
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
+bool Compiler<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
   if (DiscardResult)
     return true;
 
@@ -2267,7 +2264,7 @@ bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) {
+bool Compiler<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) {
   if (DiscardResult)
     return true;
 
@@ -2275,7 +2272,7 @@ bool ByteCodeExprGen<Emitter>::VisitPredefinedExpr(const PredefinedExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) {
+bool Compiler<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) {
   if (E->getSubExpr() && !this->discard(E->getSubExpr()))
     return false;
 
@@ -2283,7 +2280,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXReinterpretCastExpr(
+bool Compiler<Emitter>::VisitCXXReinterpretCastExpr(
     const CXXReinterpretCastExpr *E) {
   if (!this->discard(E->getSubExpr()))
     return false;
@@ -2292,7 +2289,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXReinterpretCastExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
+bool Compiler<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
   assert(E->getType()->isBooleanType());
 
   if (DiscardResult)
@@ -2301,8 +2298,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
-    const CXXConstructExpr *E) {
+bool Compiler<Emitter>::VisitCXXConstructExpr(const CXXConstructExpr *E) {
   QualType T = E->getType();
   assert(!classify(T));
 
@@ -2414,7 +2410,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) {
+bool Compiler<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) {
   if (DiscardResult)
     return true;
 
@@ -2470,7 +2466,7 @@ bool ByteCodeExprGen<Emitter>::VisitSourceLocExpr(const SourceLocExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) {
+bool Compiler<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) {
   unsigned N = E->getNumComponents();
   if (N == 0)
     return false;
@@ -2505,7 +2501,7 @@ bool ByteCodeExprGen<Emitter>::VisitOffsetOfExpr(const OffsetOfExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXScalarValueInitExpr(
+bool Compiler<Emitter>::VisitCXXScalarValueInitExpr(
     const CXXScalarValueInitExpr *E) {
   QualType Ty = E->getType();
 
@@ -2564,24 +2560,23 @@ bool ByteCodeExprGen<Emitter>::VisitCXXScalarValueInitExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {
+bool Compiler<Emitter>::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {
   return this->emitConst(E->getPackLength(), E);
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitGenericSelectionExpr(
+bool Compiler<Emitter>::VisitGenericSelectionExpr(
     const GenericSelectionExpr *E) {
   return this->delegate(E->getResultExpr());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitChooseExpr(const ChooseExpr *E) {
+bool Compiler<Emitter>::VisitChooseExpr(const ChooseExpr *E) {
   return this->delegate(E->getChosenSubExpr());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitObjCBoolLiteralExpr(
-    const ObjCBoolLiteralExpr *E) {
+bool Compiler<Emitter>::VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E) {
   if (DiscardResult)
     return true;
 
@@ -2589,7 +2584,7 @@ bool ByteCodeExprGen<Emitter>::VisitObjCBoolLiteralExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr(
+bool Compiler<Emitter>::VisitCXXInheritedCtorInitExpr(
     const CXXInheritedCtorInitExpr *E) {
   const CXXConstructorDecl *Ctor = E->getConstructor();
   assert(!Ctor->isTrivial() &&
@@ -2620,14 +2615,13 @@ bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitExpressionTraitExpr(
-    const ExpressionTraitExpr *E) {
+bool Compiler<Emitter>::VisitExpressionTraitExpr(const ExpressionTraitExpr *E) {
   assert(Ctx.getLangOpts().CPlusPlus);
   return this->emitConstBool(E->getValue(), E);
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
+bool Compiler<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
   if (DiscardResult)
     return true;
   assert(!Initializing);
@@ -2653,7 +2647,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitRequiresExpr(const RequiresExpr *E) {
+bool Compiler<Emitter>::VisitRequiresExpr(const RequiresExpr *E) {
   assert(classifyPrim(E->getType()) == PT_Bool);
   if (DiscardResult)
     return true;
@@ -2661,7 +2655,7 @@ bool ByteCodeExprGen<Emitter>::VisitRequiresExpr(const RequiresExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitConceptSpecializationExpr(
+bool Compiler<Emitter>::VisitConceptSpecializationExpr(
     const ConceptSpecializationExpr *E) {
   assert(classifyPrim(E->getType()) == PT_Bool);
   if (DiscardResult)
@@ -2670,14 +2664,13 @@ bool ByteCodeExprGen<Emitter>::VisitConceptSpecializationExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXRewrittenBinaryOperator(
+bool Compiler<Emitter>::VisitCXXRewrittenBinaryOperator(
     const CXXRewrittenBinaryOperator *E) {
   return this->delegate(E->getSemanticForm());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitPseudoObjectExpr(
-    const PseudoObjectExpr *E) {
+bool Compiler<Emitter>::VisitPseudoObjectExpr(const PseudoObjectExpr *E) {
 
   for (const Expr *SemE : E->semantics()) {
     if (auto *OVE = dyn_cast<OpaqueValueExpr>(SemE)) {
@@ -2701,18 +2694,17 @@ bool ByteCodeExprGen<Emitter>::VisitPseudoObjectExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitPackIndexingExpr(
-    const PackIndexingExpr *E) {
+bool Compiler<Emitter>::VisitPackIndexingExpr(const PackIndexingExpr *E) {
   return this->delegate(E->getSelectedExpr());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitRecoveryExpr(const RecoveryExpr *E) {
+bool Compiler<Emitter>::VisitRecoveryExpr(const RecoveryExpr *E) {
   return this->emitError(E);
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) {
+bool Compiler<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) {
   assert(E->getType()->isVoidPointerType());
 
   unsigned Offset = allocateLocalPrimitive(
@@ -2722,7 +2714,7 @@ bool ByteCodeExprGen<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitConvertVectorExpr(
+bool Compiler<Emitter>::VisitConvertVectorExpr(
     const ConvertVectorExpr *E) {
   assert(Initializing);
   const auto *VT = E->getType()->castAs<VectorType>();
@@ -2755,7 +2747,7 @@ bool ByteCodeExprGen<Emitter>::VisitConvertVectorExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitShuffleVectorExpr(
+bool Compiler<Emitter>::VisitShuffleVectorExpr(
     const ShuffleVectorExpr *E) {
   assert(Initializing);
   assert(E->getNumSubExprs() > 2);
@@ -2798,28 +2790,30 @@ bool ByteCodeExprGen<Emitter>::VisitShuffleVectorExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
+bool Compiler<Emitter>::VisitObjCBoxedExpr(const ObjCBoxedExpr *E) {
   if (!E->isExpressibleAsConstantInitializer())
     return this->emitInvalid(E);
 
   return this->delegate(E->getSubExpr());
 }
 
-template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
+template <class Emitter> bool Compiler<Emitter>::discard(const Expr *E) {
   OptionScope<Emitter> Scope(this, /*NewDiscardResult=*/true,
                              /*NewInitializing=*/false);
   return this->Visit(E);
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::delegate(const Expr *E) {
+template <class Emitter> bool Compiler<Emitter>::delegate(const Expr *E) {
+  if (E->containsErrors())
+    return this->emitError(E);
+
   // We're basically doing:
   // OptionScope<Emitter> Scope(this, DicardResult, Initializing);
   // but that's unnecessary of course.
   return this->Visit(E);
 }
 
-template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
+template <class Emitter> bool Compiler<Emitter>::visit(const Expr *E) {
   if (E->getType().isNull())
     return false;
 
@@ -2846,7 +2840,7 @@ template <class Emitter> bool ByteCodeExprGen<Emitter>::visit(const Expr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) {
+bool Compiler<Emitter>::visitInitializer(const Expr *E) {
   assert(!classify(E->getType()));
 
   if (E->containsErrors())
@@ -2857,8 +2851,7 @@ bool ByteCodeExprGen<Emitter>::visitInitializer(const Expr *E) {
   return this->Visit(E);
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
+template <class Emitter> bool Compiler<Emitter>::visitBool(const Expr *E) {
   std::optional<PrimType> T = classify(E->getType());
   if (!T) {
     // Convert complex values to bool.
@@ -2892,8 +2885,8 @@ bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
-                                                    const Expr *E) {
+bool Compiler<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
+                                             const Expr *E) {
   switch (T) {
   case PT_Bool:
     return this->emitZeroBool(E);
@@ -2931,8 +2924,8 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
-                                                          const Expr *E) {
+bool Compiler<Emitter>::visitZeroRecordInitializer(const Record *R,
+                                                   const Expr *E) {
   assert(E);
   assert(R);
   // Fields
@@ -3000,7 +2993,7 @@ bool ByteCodeExprGen<Emitter>::visitZeroRecordInitializer(const Record *R,
 
 template <class Emitter>
 template <typename T>
-bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
+bool Compiler<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
   switch (Ty) {
   case PT_Sint8:
     return this->emitConstSint8(Value, E);
@@ -3034,13 +3027,13 @@ bool ByteCodeExprGen<Emitter>::emitConst(T Value, PrimType Ty, const Expr *E) {
 
 template <class Emitter>
 template <typename T>
-bool ByteCodeExprGen<Emitter>::emitConst(T Value, const Expr *E) {
+bool Compiler<Emitter>::emitConst(T Value, const Expr *E) {
   return this->emitConst(Value, classifyPrim(E->getType()), E);
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, PrimType Ty,
-                                         const Expr *E) {
+bool Compiler<Emitter>::emitConst(const APSInt &Value, PrimType Ty,
+                                  const Expr *E) {
   if (Ty == PT_IntAPS)
     return this->emitConstIntAPS(Value, E);
   if (Ty == PT_IntAP)
@@ -3052,15 +3045,14 @@ bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, PrimType Ty,
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
+bool Compiler<Emitter>::emitConst(const APSInt &Value, const Expr *E) {
   return this->emitConst(Value, classifyPrim(E->getType()), E);
 }
 
 template <class Emitter>
-unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
-                                                          PrimType Ty,
-                                                          bool IsConst,
-                                                          bool IsExtended) {
+unsigned Compiler<Emitter>::allocateLocalPrimitive(DeclTy &&Src, PrimType Ty,
+                                                   bool IsConst,
+                                                   bool IsExtended) {
   // Make sure we don't accidentally register the same decl twice.
   if (const auto *VD =
           dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
@@ -3082,11 +3074,10 @@ unsigned ByteCodeExprGen<Emitter>::allocateLocalPrimitive(DeclTy &&Src,
 }
 
 template <class Emitter>
-std::optional<unsigned>
-ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src,
-                                        const ValueDecl *ExtendingDecl) {
+std::optional<unsigned> Compiler<Emitter>::allocateLocal(DeclTy &&Src,
+    const ValueDecl *ExtendingDecl) {
   // Make sure we don't accidentally register the same decl twice.
-  if ([[maybe_unused]]  const auto *VD =
+  if ([[maybe_unused]] const auto *VD =
           dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>())) {
     assert(!P.getGlobal(VD));
     assert(!Locals.contains(VD));
@@ -3125,31 +3116,29 @@ ByteCodeExprGen<Emitter>::allocateLocal(DeclTy &&Src,
 }
 
 template <class Emitter>
-const RecordType *ByteCodeExprGen<Emitter>::getRecordTy(QualType Ty) {
+const RecordType *Compiler<Emitter>::getRecordTy(QualType Ty) {
   if (const PointerType *PT = dyn_cast<PointerType>(Ty))
     return PT->getPointeeType()->getAs<RecordType>();
   return Ty->getAs<RecordType>();
 }
 
-template <class Emitter>
-Record *ByteCodeExprGen<Emitter>::getRecord(QualType Ty) {
+template <class Emitter> Record *Compiler<Emitter>::getRecord(QualType Ty) {
   if (const auto *RecordTy = getRecordTy(Ty))
     return getRecord(RecordTy->getDecl());
   return nullptr;
 }
 
 template <class Emitter>
-Record *ByteCodeExprGen<Emitter>::getRecord(const RecordDecl *RD) {
+Record *Compiler<Emitter>::getRecord(const RecordDecl *RD) {
   return P.getOrCreateRecord(RD);
 }
 
 template <class Emitter>
-const Function *ByteCodeExprGen<Emitter>::getFunction(const FunctionDecl *FD) {
+const Function *Compiler<Emitter>::getFunction(const FunctionDecl *FD) {
   return Ctx.getOrCreateFunction(FD);
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) {
+template <class Emitter> bool Compiler<Emitter>::visitExpr(const Expr *E) {
   ExprScope<Emitter> RootScope(this);
   // Void expressions.
   if (E->getType()->isVoidType()) {
@@ -3190,8 +3179,7 @@ bool ByteCodeExprGen<Emitter>::visitExpr(const Expr *E) {
 /// Toplevel visitDecl().
 /// We get here from evaluateAsInitializer().
 /// We need to evaluate the initializer and return its value.
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
+template <class Emitter> bool Compiler<Emitter>::visitDecl(const VarDecl *VD) {
   assert(!VD->isInvalidDecl() && "Trying to constant evaluate an invalid decl");
 
   // If we've seen the global variable already and the initializer failed,
@@ -3254,7 +3242,7 @@ bool ByteCodeExprGen<Emitter>::visitDecl(const VarDecl *VD) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
+bool Compiler<Emitter>::visitVarDecl(const VarDecl *VD) {
   // We don't know what to do with these, so just return false.
   if (VD->getType().isNull())
     return false;
@@ -3317,8 +3305,8 @@ bool ByteCodeExprGen<Emitter>::visitVarDecl(const VarDecl *VD) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
-                                            PrimType ValType, const Expr *E) {
+bool Compiler<Emitter>::visitAPValue(const APValue &Val, PrimType ValType,
+                                     const Expr *E) {
   assert(!DiscardResult);
   if (Val.isInt())
     return this->emitConst(Val.getInt(), ValType, E);
@@ -3344,7 +3332,7 @@ bool ByteCodeExprGen<Emitter>::visitAPValue(const APValue &Val,
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
+bool Compiler<Emitter>::visitAPValueInitializer(const APValue &Val,
                                                        const Expr *E) {
 
   if (Val.isStruct()) {
@@ -3407,7 +3395,7 @@ bool ByteCodeExprGen<Emitter>::visitAPValueInitializer(const APValue &Val,
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
+bool Compiler<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
   const Function *Func = getFunction(E->getDirectCallee());
   if (!Func)
     return false;
@@ -3444,7 +3432,7 @@ bool ByteCodeExprGen<Emitter>::VisitBuiltinCallExpr(const CallExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
+bool Compiler<Emitter>::VisitCallExpr(const CallExpr *E) {
   if (E->getBuiltinCallee())
     return VisitBuiltinCallExpr(E);
 
@@ -3604,15 +3592,13 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXDefaultInitExpr(
-    const CXXDefaultInitExpr *E) {
+bool Compiler<Emitter>::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
   SourceLocScope<Emitter> SLS(this, E);
   return this->delegate(E->getExpr());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr(
-    const CXXDefaultArgExpr *E) {
+bool Compiler<Emitter>::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
   SourceLocScope<Emitter> SLS(this, E);
 
   const Expr *SubExpr = E->getExpr();
@@ -3624,8 +3610,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXDefaultArgExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr(
-    const CXXBoolLiteralExpr *E) {
+bool Compiler<Emitter>::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) {
   if (DiscardResult)
     return true;
 
@@ -3633,7 +3618,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXBoolLiteralExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
+bool Compiler<Emitter>::VisitCXXNullPtrLiteralExpr(
     const CXXNullPtrLiteralExpr *E) {
   if (DiscardResult)
     return true;
@@ -3642,7 +3627,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitGNUNullExpr(const GNUNullExpr *E) {
+bool Compiler<Emitter>::VisitGNUNullExpr(const GNUNullExpr *E) {
   if (DiscardResult)
     return true;
 
@@ -3653,7 +3638,7 @@ bool ByteCodeExprGen<Emitter>::VisitGNUNullExpr(const GNUNullExpr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
+bool Compiler<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
   if (DiscardResult)
     return true;
 
@@ -3666,8 +3651,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXThisExpr(const CXXThisExpr *E) {
   return this->emitThis(E);
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitStmt(const Stmt *S) {
+template <class Emitter> bool Compiler<Emitter>::visitStmt(const Stmt *S) {
   switch (S->getStmtClass()) {
   case Stmt::CompoundStmtClass:
     return visitCompoundStmt(cast<CompoundStmt>(S));
@@ -3718,8 +3702,7 @@ bool ByteCodeExprGen<Emitter>::visitStmt(const Stmt *S) {
 
 /// Visits the given statment without creating a variable
 /// scope for it in case it is a compound statement.
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitLoopBody(const Stmt *S) {
+template <class Emitter> bool Compiler<Emitter>::visitLoopBody(const Stmt *S) {
   if (isa<NullStmt>(S))
     return true;
 
@@ -3734,7 +3717,7 @@ bool ByteCodeExprGen<Emitter>::visitLoopBody(const Stmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitCompoundStmt(const CompoundStmt *S) {
+bool Compiler<Emitter>::visitCompoundStmt(const CompoundStmt *S) {
   BlockScope<Emitter> Scope(this);
   for (auto *InnerStmt : S->body())
     if (!visitStmt(InnerStmt))
@@ -3743,7 +3726,7 @@ bool ByteCodeExprGen<Emitter>::visitCompoundStmt(const CompoundStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
+bool Compiler<Emitter>::visitDeclStmt(const DeclStmt *DS) {
   for (auto *D : DS->decls()) {
     if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl, UsingEnumDecl,
             FunctionDecl>(D))
@@ -3760,7 +3743,7 @@ bool ByteCodeExprGen<Emitter>::visitDeclStmt(const DeclStmt *DS) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
+bool Compiler<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
   if (const Expr *RE = RS->getRetValue()) {
     ExprScope<Emitter> RetScope(this);
     if (ReturnType) {
@@ -3791,8 +3774,7 @@ bool ByteCodeExprGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) {
   return this->emitRetVoid(RS);
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitIfStmt(const IfStmt *IS) {
+template <class Emitter> bool Compiler<Emitter>::visitIfStmt(const IfStmt *IS) {
   BlockScope<Emitter> IfScope(this);
 
   if (IS->isNonNegatedConsteval())
@@ -3837,7 +3819,7 @@ bool ByteCodeExprGen<Emitter>::visitIfStmt(const IfStmt *IS) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
+bool Compiler<Emitter>::visitWhileStmt(const WhileStmt *S) {
   const Expr *Cond = S->getCond();
   const Stmt *Body = S->getBody();
 
@@ -3870,8 +3852,7 @@ bool ByteCodeExprGen<Emitter>::visitWhileStmt(const WhileStmt *S) {
   return true;
 }
 
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitDoStmt(const DoStmt *S) {
+template <class Emitter> bool Compiler<Emitter>::visitDoStmt(const DoStmt *S) {
   const Expr *Cond = S->getCond();
   const Stmt *Body = S->getBody();
 
@@ -3899,7 +3880,7 @@ bool ByteCodeExprGen<Emitter>::visitDoStmt(const DoStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitForStmt(const ForStmt *S) {
+bool Compiler<Emitter>::visitForStmt(const ForStmt *S) {
   // for (Init; Cond; Inc) { Body }
   const Stmt *Init = S->getInit();
   const Expr *Cond = S->getCond();
@@ -3944,7 +3925,7 @@ bool ByteCodeExprGen<Emitter>::visitForStmt(const ForStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
+bool Compiler<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
   const Stmt *Init = S->getInit();
   const Expr *Cond = S->getCond();
   const Expr *Inc = S->getInc();
@@ -3998,7 +3979,7 @@ bool ByteCodeExprGen<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
+bool Compiler<Emitter>::visitBreakStmt(const BreakStmt *S) {
   if (!BreakLabel)
     return false;
 
@@ -4007,7 +3988,7 @@ bool ByteCodeExprGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
+bool Compiler<Emitter>::visitContinueStmt(const ContinueStmt *S) {
   if (!ContinueLabel)
     return false;
 
@@ -4016,7 +3997,7 @@ bool ByteCodeExprGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
+bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
   const Expr *Cond = S->getCond();
   PrimType CondT = this->classifyPrim(Cond->getType());
 
@@ -4086,19 +4067,19 @@ bool ByteCodeExprGen<Emitter>::visitSwitchStmt(const SwitchStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitCaseStmt(const CaseStmt *S) {
+bool Compiler<Emitter>::visitCaseStmt(const CaseStmt *S) {
   this->emitLabel(CaseLabels[S]);
   return this->visitStmt(S->getSubStmt());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) {
+bool Compiler<Emitter>::visitDefaultStmt(const DefaultStmt *S) {
   this->emitLabel(*DefaultLabel);
   return this->visitStmt(S->getSubStmt());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
+bool Compiler<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
   if (this->Ctx.getLangOpts().CXXAssumptions &&
       !this->Ctx.getLangOpts().MSVCCompat) {
     for (const Attr *A : S->getAttrs()) {
@@ -4129,14 +4110,13 @@ bool ByteCodeExprGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) {
+bool Compiler<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) {
   // Ignore all handlers.
   return this->visitStmt(S->getTryBlock());
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitLambdaStaticInvokerBody(
-    const CXXMethodDecl *MD) {
+bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
   assert(MD->isLambdaStaticInvoker());
   assert(MD->hasBody());
   assert(cast<CompoundStmt>(MD->getBody())->body_empty());
@@ -4186,8 +4166,7 @@ bool ByteCodeExprGen<Emitter>::emitLambdaStaticInvokerBody(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitFunc(const FunctionDecl *F) {
-
+bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
   // Classify the return type.
   ReturnType = this->classify(F->getReturnType());
 
@@ -4303,7 +4282,7 @@ bool ByteCodeExprGen<Emitter>::visitFunc(const FunctionDecl *F) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
+bool Compiler<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
   const Expr *SubExpr = E->getSubExpr();
   if (SubExpr->getType()->isAnyComplexType())
     return this->VisitComplexUnaryOperator(E);
@@ -4463,7 +4442,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     if (!this->visit(SubExpr))
       return false;
     return DiscardResult ? this->emitPop(*T, E) : this->emitNeg(*T, E);
-  case UO_Plus:  // +x
+  case UO_Plus:                // +x
     if (!this->visit(SubExpr)) // noop
       return false;
     return DiscardResult ? this->emitPop(*T, E) : true;
@@ -4475,11 +4454,11 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
     }
     // We should already have a pointer when we get here.
     return this->delegate(SubExpr);
-  case UO_Deref:  // *x
+  case UO_Deref: // *x
     if (DiscardResult)
       return this->discard(SubExpr);
     return this->visit(SubExpr);
-  case UO_Not:    // ~x
+  case UO_Not: // ~x
     if (!this->visit(SubExpr))
       return false;
     return DiscardResult ? this->emitPop(*T, E) : this->emitComp(*T, E);
@@ -4502,8 +4481,7 @@ bool ByteCodeExprGen<Emitter>::VisitUnaryOperator(const UnaryOperator *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitComplexUnaryOperator(
-    const UnaryOperator *E) {
+bool Compiler<Emitter>::VisitComplexUnaryOperator(const UnaryOperator *E) {
   const Expr *SubExpr = E->getSubExpr();
   assert(SubExpr->getType()->isAnyComplexType());
 
@@ -4610,7 +4588,7 @@ bool ByteCodeExprGen<Emitter>::VisitComplexUnaryOperator(
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
+bool Compiler<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
   if (DiscardResult)
     return true;
 
@@ -4733,20 +4711,19 @@ bool ByteCodeExprGen<Emitter>::visitDeclRef(const ValueDecl *D, const Expr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
+bool Compiler<Emitter>::VisitDeclRefExpr(const DeclRefExpr *E) {
   const auto *D = E->getDecl();
   return this->visitDeclRef(D, E);
 }
 
-template <class Emitter>
-void ByteCodeExprGen<Emitter>::emitCleanup() {
+template <class Emitter> void Compiler<Emitter>::emitCleanup() {
   for (VariableScope<Emitter> *C = VarScope; C; C = C->getParent())
     C->emitDestruction();
 }
 
 template <class Emitter>
 unsigned
-ByteCodeExprGen<Emitter>::collectBaseOffset(const QualType BaseType,
+Compiler<Emitter>::collectBaseOffset(const QualType BaseType,
                                             const QualType DerivedType) {
   const auto extractRecordDecl = [](QualType Ty) -> const CXXRecordDecl * {
     if (const auto *PT = dyn_cast<PointerType>(Ty))
@@ -4761,8 +4738,8 @@ ByteCodeExprGen<Emitter>::collectBaseOffset(const QualType BaseType,
 
 /// Emit casts from a PrimType to another PrimType.
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
-                                            QualType ToQT, const Expr *E) {
+bool Compiler<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
+                                     QualType ToQT, const Expr *E) {
 
   if (FromT == PT_Float) {
     // Floating to floating.
@@ -4804,7 +4781,7 @@ bool ByteCodeExprGen<Emitter>::emitPrimCast(PrimType FromT, PrimType ToT,
 
 /// Emits __real(SubExpr)
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) {
+bool Compiler<Emitter>::emitComplexReal(const Expr *SubExpr) {
   assert(SubExpr->getType()->isAnyComplexType());
 
   if (DiscardResult)
@@ -4824,7 +4801,7 @@ bool ByteCodeExprGen<Emitter>::emitComplexReal(const Expr *SubExpr) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
+bool Compiler<Emitter>::emitComplexBoolCast(const Expr *E) {
   assert(!DiscardResult);
   PrimType ElemT = classifyComplexElementType(E->getType());
   // We emit the expression (__real(E) != 0 || __imag(E) != 0)
@@ -4870,9 +4847,8 @@ bool ByteCodeExprGen<Emitter>::emitComplexBoolCast(const Expr *E) {
 }
 
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitComplexComparison(const Expr *LHS,
-                                                     const Expr *RHS,
-                                                     const BinaryOperator *E) {
+bool Compiler<Emitter>::emitComplexComparison(const Expr *LHS, const Expr *RHS,
+                                              const BinaryOperator *E) {
   assert(E->isComparisonOp());
   assert(!Initializing);
   assert(!DiscardResult);
@@ -4969,7 +4945,7 @@ bool ByteCodeExprGen<Emitter>::emitComplexComparison(const Expr *LHS,
 /// on the stack.
 /// Emit destruction of record types (or arrays of record types).
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Record *R) {
+bool Compiler<Emitter>::emitRecordDestruction(const Record *R) {
   assert(R);
   // First, destroy all fields.
   for (const Record::Field &Field : llvm::reverse(R->fields())) {
@@ -5017,7 +4993,7 @@ bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Record *R) {
 /// on the stack.
 /// Emit destruction of record types (or arrays of record types).
 template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitDestruction(const Descriptor *Desc) {
+bool Compiler<Emitter>::emitDestruction(const Descriptor *Desc) {
   assert(Desc);
   assert(!Desc->isPrimitive());
   assert(!Desc->isPrimitiveArray());
@@ -5060,8 +5036,8 @@ bool ByteCodeExprGen<Emitter>::emitDestruction(const Descriptor *Desc) {
 namespace clang {
 namespace interp {
 
-template class ByteCodeExprGen<ByteCodeEmitter>;
-template class ByteCodeExprGen<EvalEmitter>;
+template class Compiler<ByteCodeEmitter>;
+template class Compiler<EvalEmitter>;
 
 } // namespace interp
 } // namespace clang
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/Compiler.h
similarity index 94%
rename from clang/lib/AST/Interp/ByteCodeExprGen.h
rename to clang/lib/AST/Interp/Compiler.h
index 40955dd43a907..cdc416b569500 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/Compiler.h
@@ -1,4 +1,4 @@
-//===--- ByteCodeExprGen.h - Code generator for expressions -----*- C++ -*-===//
+//===--- Compiler.h - Code generator for expressions -----*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -41,8 +41,8 @@ template <class Emitter> class SwitchScope;
 
 /// Compilation context for expressions.
 template <class Emitter>
-class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
-                        public Emitter {
+class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
+                 public Emitter {
 protected:
   // Aliases for types defined in the emitter.
   using LabelTy = typename Emitter::LabelTy;
@@ -58,7 +58,7 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
 public:
   /// Initializes the compiler and the backend emitter.
   template <typename... Tys>
-  ByteCodeExprGen(Context &Ctx, Program &P, Tys &&... Args)
+  Compiler(Context &Ctx, Program &P, Tys &&...Args)
       : Emitter(Ctx, P, Args...), Ctx(Ctx), P(P) {}
 
   // Expressions.
@@ -369,13 +369,13 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
   OptLabelTy DefaultLabel;
 };
 
-extern template class ByteCodeExprGen<ByteCodeEmitter>;
-extern template class ByteCodeExprGen<EvalEmitter>;
+extern template class Compiler<ByteCodeEmitter>;
+extern template class Compiler<EvalEmitter>;
 
 /// Scope chain managing the variable lifetimes.
 template <class Emitter> class VariableScope {
 public:
-  VariableScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
+  VariableScope(Compiler<Emitter> *Ctx, const ValueDecl *VD)
       : Ctx(Ctx), Parent(Ctx->VarScope), ValDecl(VD) {
     Ctx->VarScope = this;
   }
@@ -422,8 +422,8 @@ template <class Emitter> class VariableScope {
   VariableScope *getParent() const { return Parent; }
 
 protected:
-  /// ByteCodeExprGen instance.
-  ByteCodeExprGen<Emitter> *Ctx;
+  /// Compiler instance.
+  Compiler<Emitter> *Ctx;
   /// Link to the parent scope.
   VariableScope *Parent;
   const ValueDecl *ValDecl = nullptr;
@@ -432,7 +432,7 @@ template <class Emitter> class VariableScope {
 /// Generic scope for local variables.
 template <class Emitter> class LocalScope : public VariableScope<Emitter> {
 public:
-  LocalScope(ByteCodeExprGen<Emitter> *Ctx)
+  LocalScope(Compiler<Emitter> *Ctx)
       : VariableScope<Emitter>(Ctx, nullptr) {}
 
   /// Emit a Destroy op for this scope.
@@ -527,8 +527,7 @@ template <class Emitter> class DestructorScope final {
 /// variables are automatically emitted when the AutoScope is destroyed.
 template <class Emitter> class AutoScope : public LocalScope<Emitter> {
 public:
-  AutoScope(ByteCodeExprGen<Emitter> *Ctx)
-      : LocalScope<Emitter>(Ctx), DS(*this) {}
+  AutoScope(Compiler<Emitter> *Ctx) : LocalScope<Emitter>(Ctx), DS(*this) {}
 
 private:
   DestructorScope<Emitter> DS;
@@ -537,7 +536,7 @@ template <class Emitter> class AutoScope : public LocalScope<Emitter> {
 /// Scope for storage declared in a compound statement.
 template <class Emitter> class BlockScope final : public AutoScope<Emitter> {
 public:
-  BlockScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
+  BlockScope(Compiler<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
 
   void addExtended(const Scope::Local &Local) override {
     // If we to this point, just add the variable as a normal local
@@ -549,12 +548,12 @@ template <class Emitter> class BlockScope final : public AutoScope<Emitter> {
 
 template <class Emitter> class ExprScope final : public AutoScope<Emitter> {
 public:
-  ExprScope(ByteCodeExprGen<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
+  ExprScope(Compiler<Emitter> *Ctx) : AutoScope<Emitter>(Ctx) {}
 };
 
 template <class Emitter> class ArrayIndexScope final {
 public:
-  ArrayIndexScope(ByteCodeExprGen<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
+  ArrayIndexScope(Compiler<Emitter> *Ctx, uint64_t Index) : Ctx(Ctx) {
     OldArrayIndex = Ctx->ArrayIndex;
     Ctx->ArrayIndex = Index;
   }
@@ -562,14 +561,13 @@ template <class Emitter> class ArrayIndexScope final {
   ~ArrayIndexScope() { Ctx->ArrayIndex = OldArrayIndex; }
 
 private:
-  ByteCodeExprGen<Emitter> *Ctx;
+  Compiler<Emitter> *Ctx;
   std::optional<uint64_t> OldArrayIndex;
 };
 
 template <class Emitter> class SourceLocScope final {
 public:
-  SourceLocScope(ByteCodeExprGen<Emitter> *Ctx, const Expr *DefaultExpr)
-      : Ctx(Ctx) {
+  SourceLocScope(Compiler<Emitter> *Ctx, const Expr *DefaultExpr) : Ctx(Ctx) {
     assert(DefaultExpr);
     // We only switch if the current SourceLocDefaultExpr is null.
     if (!Ctx->SourceLocDefaultExpr) {
@@ -584,7 +582,7 @@ template <class Emitter> class SourceLocScope final {
   }
 
 private:
-  ByteCodeExprGen<Emitter> *Ctx;
+  Compiler<Emitter> *Ctx;
   bool Enabled = false;
 };
 
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 338165e03586a..22ccae4fa30f8 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -8,7 +8,7 @@
 
 #include "Context.h"
 #include "ByteCodeEmitter.h"
-#include "ByteCodeExprGen.h"
+#include "Compiler.h"
 #include "EvalEmitter.h"
 #include "Interp.h"
 #include "InterpFrame.h"
@@ -29,7 +29,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
   assert(Stk.empty());
   Function *Func = P->getFunction(FD);
   if (!Func || !Func->hasBody())
-    Func = ByteCodeExprGen<ByteCodeEmitter>(*this, *P).compileFunc(FD);
+    Func = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD);
 
   APValue DummyResult;
   if (!Run(Parent, Func, DummyResult))
@@ -40,7 +40,7 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) {
 
 bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
   bool Recursing = !Stk.empty();
-  ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk);
+  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
 
   auto Res = C.interpretExpr(E, /*ConvertResultToRValue=*/E->isGLValue());
 
@@ -66,7 +66,7 @@ bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) {
 
 bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) {
   bool Recursing = !Stk.empty();
-  ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk);
+  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
 
   auto Res = C.interpretExpr(E);
   if (Res.isInvalid()) {
@@ -91,7 +91,7 @@ bool Context::evaluate(State &Parent, const Expr *E, APValue &Result) {
 bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD,
                                     APValue &Result) {
   bool Recursing = !Stk.empty();
-  ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk);
+  Compiler<EvalEmitter> C(*this, *P, Parent, Stk);
 
   bool CheckGlobalInitialized =
       shouldBeGloballyIndexed(VD) &&
@@ -260,7 +260,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FD) {
     return Func;
 
   if (!Func || WasNotDefined) {
-    if (auto F = ByteCodeExprGen<ByteCodeEmitter>(*this, *P).compileFunc(FD))
+    if (auto F = Compiler<ByteCodeEmitter>(*this, *P).compileFunc(FD))
       Func = F;
   }
 

>From 8da09ef0e9ff71d84333f420ae1df1bd016aedc9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 2 Mar 2024 17:25:45 +0100
Subject: [PATCH 3/3] [clang][Interp] Implement StmtExprs

---
 clang/lib/AST/Interp/Compiler.cpp  | 26 ++++++++++++++++++++++++++
 clang/lib/AST/Interp/Compiler.h    |  1 +
 clang/test/AST/Interp/literals.cpp | 12 ++++++++++++
 3 files changed, 39 insertions(+)

diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 4f424b2a60871..a361198182e90 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -2746,6 +2746,32 @@ bool Compiler<Emitter>::VisitConvertVectorExpr(
   return true;
 }
 
+template <class Emitter>
+bool Compiler<Emitter>::VisitStmtExpr(const StmtExpr *E) {
+  BlockScope<Emitter> BS(this);
+
+  const CompoundStmt *CS = E->getSubStmt();
+  const Stmt *Result = CS->getStmtExprResult();
+  for (const Stmt *S : CS->body()) {
+    if (S != Result) {
+      if (!this->visitStmt(S))
+        return false;
+      continue;
+    }
+
+    assert(S == Result);
+    // This better produces a value (i.e. is an expression).
+    if (const Expr *ResultExpr = dyn_cast<Expr>(S)) {
+      if (DiscardResult)
+        return this->discard(ResultExpr);
+      return this->delegate(ResultExpr);
+    }
+    return false;
+  }
+
+  return true;
+}
+
 template <class Emitter>
 bool Compiler<Emitter>::VisitShuffleVectorExpr(
     const ShuffleVectorExpr *E) {
diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h
index cdc416b569500..797580837515d 100644
--- a/clang/lib/AST/Interp/Compiler.h
+++ b/clang/lib/AST/Interp/Compiler.h
@@ -134,6 +134,7 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, bool>,
   bool VisitConvertVectorExpr(const ConvertVectorExpr *E);
   bool VisitShuffleVectorExpr(const ShuffleVectorExpr *E);
   bool VisitObjCBoxedExpr(const ObjCBoxedExpr *E);
+  bool VisitStmtExpr(const StmtExpr *E);
 
   // Statements.
   bool visitCompoundStmt(const CompoundStmt *S);
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index 5a29013a053a2..9a8eb1e44ce54 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -1211,6 +1211,18 @@ constexpr int externvar1() { // both-error {{never produces a constant expressio
    return arr[0]; // ref-note {{read of non-constexpr variable 'arr'}} \
                   // expected-note {{indexing of array without known bound}}
 }
+
+namespace StmtExprs {
+  constexpr int foo() {
+     ({
+       int i;
+       for (i = 0; i < 76; i++) {}
+       i; // both-warning {{expression result unused}}
+    });
+    return 76;
+  }
+  static_assert(foo() == 76, "");
+}
 #endif
 
 namespace Extern {



More information about the cfe-commits mailing list