https://github.com/arsenm updated 
https://github.com/llvm/llvm-project/pull/221443

>From c90321a6400d1eb168fc2ba03abe0dcd5f11c9ac Mon Sep 17 00:00:00 2001
From: Matt Arsenault <[email protected]>
Date: Sat, 5 Sep 2026 15:24:05 +0200
Subject: [PATCH 1/2] WebAssembly: Introduce ExceptionHandling::EmscriptenEH
 model

Add a dedicated EmscriptenEH exception model so the control uses
the standard exception model control, instead of relying on a backend
specific cl::opt. This will later migrate to a module flag and
remove -enable-emscripten-cxx-exceptions

Co-authored-by: Claude (Claude-Opus-4.8) <[email protected]>
---
 clang/include/clang/Basic/CodeGenOptions.h    | 13 +++++++-
 .../clang/Basic/DiagnosticFrontendKinds.td    |  2 +-
 clang/include/clang/Options/Options.td        |  4 +--
 clang/lib/CodeGen/BackendUtil.cpp             |  2 ++
 clang/lib/Driver/ToolChains/Clang.cpp         |  5 ++-
 clang/lib/Driver/ToolChains/WebAssembly.cpp   |  6 ----
 ...asm-exception-model-flag-parse-ir-input.ll |  2 +-
 clang/test/Driver/ir-exception-model.c        |  2 ++
 clang/test/Driver/wasm-toolchain.c            |  6 ++--
 llvm/include/llvm/Support/CodeGen.h           | 15 +++++----
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    |  2 ++
 llvm/lib/CodeGen/CommandFlags.cpp             |  4 ++-
 llvm/lib/CodeGen/TargetPassConfig.cpp         |  3 ++
 llvm/lib/Passes/CodeGenPassBuilder.cpp        |  3 ++
 llvm/lib/Target/WebAssembly/WebAssembly.h     |  6 +++-
 .../WebAssembly/WebAssemblyAsmPrinter.cpp     |  1 +
 .../WebAssemblyCodeGenPassBuilder.cpp         |  9 ++++--
 .../WebAssemblyLowerEmscriptenEHSjLj.cpp      | 17 ++++++----
 .../WebAssembly/WebAssemblyTargetMachine.cpp  | 32 ++++++++++++-------
 .../CodeGen/WebAssembly/eh-option-errors.ll   | 13 +++-----
 20 files changed, 94 insertions(+), 53 deletions(-)

diff --git a/clang/include/clang/Basic/CodeGenOptions.h 
b/clang/include/clang/Basic/CodeGenOptions.h
index 17f367bc02607..8b65a5bc920a5 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -199,7 +199,14 @@ class CodeGenOptions : public CodeGenOptionsBase {
   }
 
   /// Possible exception handling behavior.
-  enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm };
+  enum class ExceptionHandlingKind {
+    None,
+    SjLj,
+    WinEH,
+    DwarfCFI,
+    Wasm,
+    EmscriptenEH
+  };
 
   enum class SwiftAsyncFramePointerKind {
     Auto, // Choose Swift async extended frame info based on deployment target.
@@ -634,6 +641,10 @@ class CodeGenOptions : public CodeGenOptionsBase {
     return getExceptionHandling() == ExceptionHandlingKind::Wasm;
   }
 
+  bool hasEmscriptenExceptions() const {
+    return getExceptionHandling() == ExceptionHandlingKind::EmscriptenEH;
+  }
+
   /// Check if Clang profile instrumenation is on.
   bool hasProfileClangInstr() const {
     return getProfileInstr() ==
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index a10f10502a702..de38915bd8985 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -151,7 +151,7 @@ def err_fe_invalid_multiple_actions : Error<
 def err_fe_invalid_alignment : Error<
     "invalid value '%1' in '%0'; alignment must be a power of 2">;
 def err_fe_invalid_exception_model
-   : Error<"invalid exception model '%select{none|sjlj|seh|dwarf|wasm}0' for 
target '%1'">;
+   : Error<"invalid exception model 
'%select{none|sjlj|seh|dwarf|wasm|emscripten}0' for target '%1'">;
 def err_fe_invalid_source_date_epoch : Error<
     "environment variable 'SOURCE_DATE_EPOCH' ('%0') must be a non-negative 
decimal integer <= %1">;
 
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 32b12beba880b..c0c89c691683a 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2460,9 +2460,9 @@ def femscripten_exceptions : Flag<["-"], 
"femscripten-exceptions">,
   HelpText<"Use Emscripten JavaScript-based C++ exceptions">;
 def exception_model : Separate<["-"], "exception-model">,
   Visibility<[CC1Option]>, HelpText<"The exception model">,
-  Values<"dwarf,sjlj,seh,wasm,none">,
+  Values<"dwarf,sjlj,seh,wasm,emscripten,none">,
   NormalizedValuesScope<"CodeGenOptions::ExceptionHandlingKind">,
-  NormalizedValues<["DwarfCFI", "SjLj", "WinEH", "Wasm", "None"]>,
+  NormalizedValues<["DwarfCFI", "SjLj", "WinEH", "Wasm", "EmscriptenEH", 
"None"]>,
   MarshallingInfoEnum<CodeGenOpts<"ExceptionHandling">, "None">;
 def exception_model_EQ : Joined<["-"], "exception-model=">,
   Visibility<[CC1Option]>, Alias<exception_model>;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp 
b/clang/lib/CodeGen/BackendUtil.cpp
index 9d8fd319f6f17..dcc77f7aa4d58 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -404,6 +404,8 @@ static bool initTargetOptions(const CompilerInstance &CI,
     Options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI;
   if (CodeGenOpts.hasWasmExceptions())
     Options.ExceptionModel = llvm::ExceptionHandling::Wasm;
+  if (CodeGenOpts.hasEmscriptenExceptions())
+    Options.ExceptionModel = llvm::ExceptionHandling::EmscriptenEH;
 
   Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
 
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index e445e61f8a23f..9009ce7ec9556 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7891,7 +7891,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
   // Handle exception personalities
   Arg *A = Args.getLastArg(
       options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions,
-      options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions);
+      options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions,
+      options::OPT_femscripten_exceptions);
   if (A) {
     const Option &Opt = A->getOption();
     if (Opt.matches(options::OPT_fsjlj_exceptions))
@@ -7902,6 +7903,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
       CmdArgs.push_back("-exception-model=dwarf");
     if (Opt.matches(options::OPT_fwasm_exceptions))
       CmdArgs.push_back("-exception-model=wasm");
+    if (Opt.matches(options::OPT_femscripten_exceptions))
+      CmdArgs.push_back("-exception-model=emscripten");
   } else {
     switch (TC.GetExceptionModel(Args)) {
     default:
diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp 
b/clang/lib/Driver/ToolChains/WebAssembly.cpp
index 23ae184105f8d..b683fcd506a44 100644
--- a/clang/lib/Driver/ToolChains/WebAssembly.cpp
+++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp
@@ -462,12 +462,6 @@ void WebAssembly::addClangTargetOptions(const ArgList 
&DriverArgs,
     CC1Args.push_back("-wasm-enable-eh");
   }
 
-  if (DriverArgs.getLastArg(options::OPT_femscripten_exceptions)) {
-    // Backend needs -enable-emscripten-cxx-exceptions to enable Emscripten EH
-    CC1Args.push_back("-mllvm");
-    CC1Args.push_back("-enable-emscripten-cxx-exceptions");
-  }
-
   for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) {
     StringRef Opt = A->getValue(0);
     if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) {
diff --git 
a/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll 
b/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll
index 85bfc7f74daed..8263c98670aab 100644
--- a/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll
+++ b/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll
@@ -11,7 +11,7 @@
 ; CHECK-LABEL: define void @test(
 
 ; ERR: error: invalid value 'invalid' in '-exception-model=invalid'
-; ERR-BE: fatal error: error in backend: -exception-model should be either 
'none' or 'wasm'
+; ERR-BE: fatal error: error in backend: -exception-model should be either 
'none', 'wasm', or 'emscripten'
 define void @test() {
   ret void
 }
diff --git a/clang/test/Driver/ir-exception-model.c 
b/clang/test/Driver/ir-exception-model.c
index 9e8f998de0d6b..b5d68c644e1b7 100644
--- a/clang/test/Driver/ir-exception-model.c
+++ b/clang/test/Driver/ir-exception-model.c
@@ -1,5 +1,6 @@
 // RUN: %clang -### -target wasm32-unknown-unknown -fwasm-exceptions -c -S -o 
- %S/Inputs/file.ll 2>&1 | FileCheck %s
 // RUN: %clang -### -target wasm32-unknown-unknown -Xclang 
-exception-model=wasm -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck %s
+// RUN: %clang -### -target wasm32-unknown-emscripten -femscripten-exceptions 
-c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck -check-prefix=EMSCRIPTEN %s
 // RUN: %clang -### -target wasm32-unknown-unknown -Xclang 
-exception-model=dwarf -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck 
-check-prefix=DWARF %s
 // RUN: %clang -### -target wasm32-unknown-unknown -Xclang 
-exception-model=sjlj -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck 
-check-prefix=SJLJ %s
 // RUN: %clang -### -target wasm32-unknown-unknown -Xclang 
-exception-model=wineh -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck 
-check-prefix=WINEH %s
@@ -8,6 +9,7 @@
 // Check that -fwasm-exceptions propagates -exception-model to cc1
 
 // CHECK: "-exception-model=wasm"
+// EMSCRIPTEN: "-exception-model=emscripten"
 // DWARF: "-exception-model=dwarf"
 // SJLJ: "-exception-model=sjlj"
 // WINEH: "-exception-model=wineh"
diff --git a/clang/test/Driver/wasm-toolchain.c 
b/clang/test/Driver/wasm-toolchain.c
index 083773e8e8197..665cf4d1a667b 100644
--- a/clang/test/Driver/wasm-toolchain.c
+++ b/clang/test/Driver/wasm-toolchain.c
@@ -123,7 +123,7 @@
 // '-mllvm -emscripten-cxx-exceptions-allowed=foo,bar' sets
 // '-mllvm --force-attribute=foo:noinline -mllvm 
--force-attribute=bar:noinline'
 // RUN: %clang -### --target=wasm32-unknown-unknown \
-// RUN:    --sysroot=/foo %s -mllvm -enable-emscripten-cxx-exceptions \
+// RUN:    --sysroot=/foo %s -femscripten-exceptions \
 // RUN:    -mllvm -emscripten-cxx-exceptions-allowed=foo,bar 2>&1 \
 // RUN:  | FileCheck -check-prefix=EMSCRIPTEN_EH_ALLOWED_NOINLINE %s
 // EMSCRIPTEN_EH_ALLOWED_NOINLINE: "-cc1" {{.*}} "-mllvm" 
"--force-attribute=foo:noinline" "-mllvm" "--force-attribute=bar:noinline"
@@ -135,11 +135,11 @@
 // RUN:   | FileCheck -check-prefix=EMSCRIPTEN_EH_ALLOWED_WO_ENABLE %s
 // EMSCRIPTEN_EH_ALLOWED_WO_ENABLE: invalid argument '-mllvm 
-emscripten-cxx-exceptions-allowed' only allowed with '-femscripten-exceptions'
 
-// '-femscripten-exceptions' sets '-mllvm -enable-emscripten-cxx-exceptions'
+// '-femscripten-exceptions' sets '-exception-model=emscripten'
 // RUN: %clang -### --target=wasm32-unknown-unknown \
 // RUN:    --sysroot=/foo %s -femscripten-exceptions 2>&1 \
 // RUN:  | FileCheck -check-prefix=EMSCRIPTEN_EXCEPTIONS %s
-// EMSCRIPTEN_EXCEPTIONS: "-cc1" {{.*}} "-mllvm" 
"-enable-emscripten-cxx-exceptions"
+// EMSCRIPTEN_EXCEPTIONS: "-cc1" {{.*}} "-exception-model=emscripten"
 
 // '-femscripten-exceptions' satisfies the '-emscripten-cxx-exceptions-allowed'
 // companion requirement.
diff --git a/llvm/include/llvm/Support/CodeGen.h 
b/llvm/include/llvm/Support/CodeGen.h
index 22b168597be99..a6c276a6a15b2 100644
--- a/llvm/include/llvm/Support/CodeGen.h
+++ b/llvm/include/llvm/Support/CodeGen.h
@@ -52,13 +52,14 @@ namespace llvm {
   }
 
   enum class ExceptionHandling : int {
-    None,     ///< No exception support
-    DwarfCFI, ///< DWARF-like instruction based exceptions
-    SjLj,     ///< setjmp/longjmp based exceptions
-    ARM,      ///< ARM EHABI
-    WinEH,    ///< Windows Exception Handling
-    Wasm,     ///< WebAssembly Exception Handling
-    AIX,      ///< AIX Exception Handling
+    None,         ///< No exception support
+    DwarfCFI,     ///< DWARF-like instruction based exceptions
+    SjLj,         ///< setjmp/longjmp based exceptions
+    ARM,          ///< ARM EHABI
+    WinEH,        ///< Windows Exception Handling
+    Wasm,         ///< WebAssembly Exception Handling
+    EmscriptenEH, ///< Emscripten JavaScript-based C++ exception handling
+    AIX,          ///< AIX Exception Handling
     ZOS, ///< z/OS MVS Exception Handling. Very similar to DwarfCFI, but the
          ///< PPA1 is used instead of an .eh_frame section.
   };
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp 
b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 5440e1a3cdbae..ef0f74a1cf802 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -669,6 +669,8 @@ bool AsmPrinter::doInitialization(Module &M) {
   EHStreamer *ES = nullptr;
   switch (MAI.getExceptionHandlingType()) {
   case ExceptionHandling::None:
+  case ExceptionHandling::EmscriptenEH:
+    // Emscripten EH is handled in JS glue code and emits no EH tables here.
     if (!usesCFIWithoutEH())
       break;
     [[fallthrough]];
diff --git a/llvm/lib/CodeGen/CommandFlags.cpp 
b/llvm/lib/CodeGen/CommandFlags.cpp
index 8410c10843bd4..56f191a5972e6 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -195,7 +195,9 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
           clEnumValN(ExceptionHandling::WinEH, "wineh",
                      "Windows exception model"),
           clEnumValN(ExceptionHandling::Wasm, "wasm",
-                     "WebAssembly exception handling")));
+                     "WebAssembly exception handling"),
+          clEnumValN(ExceptionHandling::EmscriptenEH, "emscripten",
+                     "Emscripten JavaScript-based C++ exception handling")));
   CGBINDOPT(ExceptionModel);
 
   static cl::opt<CodeGenFileType> FileType(
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp 
b/llvm/lib/CodeGen/TargetPassConfig.cpp
index e390db16aa63d..3d8883a8a2049 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -961,6 +961,9 @@ void TargetPassConfig::addPassesToHandleExceptions() {
     addPass(createWasmEHPass());
     break;
   case ExceptionHandling::None:
+  case ExceptionHandling::EmscriptenEH:
+    // Emscripten EH is lowered earlier by WebAssemblyLowerEmscriptenEHSjLj, so
+    // by this point it needs no generic EH preparation, like the None case.
     addPass(createLowerInvokePass());
 
     // The lower invoke pass may create unreachable code. Remove it.
diff --git a/llvm/lib/Passes/CodeGenPassBuilder.cpp 
b/llvm/lib/Passes/CodeGenPassBuilder.cpp
index 63e161965820e..57d4b74c4e24c 100644
--- a/llvm/lib/Passes/CodeGenPassBuilder.cpp
+++ b/llvm/lib/Passes/CodeGenPassBuilder.cpp
@@ -473,6 +473,9 @@ void 
CodeGenPassBuilder::addPassesToHandleExceptions(PassManagerWrapper &PMW) {
     addFunctionPass(WasmEHPreparePass(), PMW);
     break;
   case ExceptionHandling::None:
+  case ExceptionHandling::EmscriptenEH:
+    // Emscripten EH is lowered earlier by WebAssemblyLowerEmscriptenEHSjLj, so
+    // by this point it needs no generic EH preparation, like the None case.
     addFunctionPass(LowerInvokePass(), PMW);
 
     // The lower invoke pass may create unreachable code. Remove it.
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h 
b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 94628d0944f8d..e6aefc2ba43e9 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -35,11 +35,15 @@ class FunctionPass;
 // LLVM IR passes.
 class WebAssemblyLowerEmscriptenEHSjLjPass
     : public RequiredPassInfoMixin<WebAssemblyLowerEmscriptenEHSjLjPass> {
+  bool EnableEmEH;
+
 public:
+  WebAssemblyLowerEmscriptenEHSjLjPass(bool EnableEmEH = false)
+      : EnableEmEH(EnableEmEH) {}
   PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
 };
 
-ModulePass *createWebAssemblyLowerEmscriptenEHSjLjLegacyPass();
+ModulePass *createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(bool EnableEmEH);
 
 class WebAssemblyAddMissingPrototypesPass
     : public RequiredPassInfoMixin<WebAssemblyAddMissingPrototypesPass> {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 69a0f97253f3e..d64f03c24b11c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -166,6 +166,7 @@ MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(
   MCSymbolWasm *WasmSym = nullptr;
 
   const bool EnableEmEH =
+      TM.Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
       WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj;
   if (EnableEmEH && isEmscriptenInvokeName(F->getName())) {
     assert(Sig);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
index 7fecb163625cf..653080fd81582 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
@@ -127,7 +127,10 @@ void 
WebAssemblyCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) {
   // TargetPassConfig::addPassesToHandleExceptions, but that runs after these 
IR
   // passes and Emscripten SjLj handling expects all invokes to be lowered
   // before.
-  if (!WasmEnableEmEH && !WasmEnableEH) {
+  bool EnableEmEH =
+      TM.Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
+      WasmEnableEmEH;
+  if (!EnableEmEH && !WasmEnableEH) {
     addFunctionPass(LowerInvokePass(), PMW);
     // The lower invoke pass may create unreachable code. Remove it in order 
not
     // to process dead blocks in setjmp/longjmp handling.
@@ -138,9 +141,9 @@ void 
WebAssemblyCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) {
   // done in WasmEHPrepare pass, Wasm SjLj preparation shares libraries and
   // transformation algorithms with Emscripten SjLj, so we run
   // LowerEmscriptenEHSjLj pass also when Wasm SjLj is enabled.
-  if (WasmEnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj) {
+  if (EnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj) {
     flushFPMsToMPM(PMW);
-    addModulePass(WebAssemblyLowerEmscriptenEHSjLjPass(), PMW);
+    addModulePass(WebAssemblyLowerEmscriptenEHSjLjPass(EnableEmEH), PMW);
   }
 
   // Expand indirectbr instructions to switches.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index c21d6386ea15d..eb58ff53bee4b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -359,8 +359,9 @@ class WebAssemblyLowerEmscriptenEHSjLjImpl {
 
 public:
   WebAssemblyLowerEmscriptenEHSjLjImpl(
+      bool EnableEmEH,
       std::function<DominatorTree &(Function &F)> GetDominatorTree)
-      : EnableEmEH(WebAssembly::WasmEnableEmEH),
+      : EnableEmEH(EnableEmEH || WebAssembly::WasmEnableEmEH),
         EnableEmSjLj(WebAssembly::WasmEnableEmSjLj),
         EnableWasmSjLj(WebAssembly::WasmEnableSjLj),
         GetDominatorTree(GetDominatorTree) {
@@ -375,6 +376,8 @@ class WebAssemblyLowerEmscriptenEHSjLjImpl {
 };
 
 class WebAssemblyLowerEmscriptenEHSjLjLegacy final : public ModulePass {
+  bool EnableEmEH;
+
   StringRef getPassName() const override {
     return "WebAssembly Lower Emscripten Exceptions";
   }
@@ -382,7 +385,8 @@ class WebAssemblyLowerEmscriptenEHSjLjLegacy final : public 
ModulePass {
 public:
   static char ID;
 
-  WebAssemblyLowerEmscriptenEHSjLjLegacy() : ModulePass(ID) {}
+  WebAssemblyLowerEmscriptenEHSjLjLegacy(bool EnableEmEH = false)
+      : ModulePass(ID), EnableEmEH(EnableEmEH) {}
   bool runOnModule(Module &M) override;
 
   void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -396,8 +400,9 @@ INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLjLegacy, 
DEBUG_TYPE,
                 "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
                 false, false)
 
-ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLjLegacyPass() {
-  return new WebAssemblyLowerEmscriptenEHSjLjLegacy();
+ModulePass *
+llvm::createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(bool EnableEmEH) {
+  return new WebAssemblyLowerEmscriptenEHSjLjLegacy(EnableEmEH);
 }
 
 static bool canThrow(const Value *V) {
@@ -1868,7 +1873,7 @@ void 
WebAssemblyLowerEmscriptenEHSjLjImpl::handleLongjmpableCallsForWasmSjLj(
 
 bool WebAssemblyLowerEmscriptenEHSjLjLegacy::runOnModule(Module &M) {
   WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
-      [&](Function &F) -> DominatorTree & {
+      EnableEmEH, [&](Function &F) -> DominatorTree & {
         return getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
       });
   return Impl.runOnModule(M);
@@ -1878,7 +1883,7 @@ PreservedAnalyses
 WebAssemblyLowerEmscriptenEHSjLjPass::run(Module &M,
                                           ModuleAnalysisManager &MAM) {
   WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
-      [&](Function &F) -> DominatorTree & {
+      EnableEmEH, [&](Function &F) -> DominatorTree & {
         return MAM.getResult<FunctionAnalysisManagerModuleProxy>(M)
             .getManager()
             .getResult<DominatorTreeAnalysis>(F);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 964b67edde3e0..a9a905b6698c0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -141,18 +141,24 @@ using WebAssembly::WasmEnableSjLj;
 
 static void basicCheckForEHAndSjLj(TargetMachine *TM) {
 
+  // Emscripten EH is selected by the exception model. WasmEnableEmEH is a
+  // deprecated cl::opt alias, OR-ed in here until it is removed.
+  bool EnableEmEH =
+      TM->Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
+      WasmEnableEmEH;
+
   // You can't enable two modes of EH at the same time
-  if (WasmEnableEmEH && WasmEnableEH)
+  if (EnableEmEH && WasmEnableEH)
     report_fatal_error(
-        "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-eh");
+        "-exception-model=emscripten not allowed with -wasm-enable-eh");
   // You can't enable two modes of SjLj at the same time
   if (WasmEnableEmSjLj && WasmEnableSjLj)
     report_fatal_error(
         "-enable-emscripten-sjlj not allowed with -wasm-enable-sjlj");
   // You can't mix Emscripten EH with Wasm SjLj.
-  if (WasmEnableEmEH && WasmEnableSjLj)
+  if (EnableEmEH && WasmEnableSjLj)
     report_fatal_error(
-        "-enable-emscripten-cxx-exceptions not allowed with 
-wasm-enable-sjlj");
+        "-exception-model=emscripten not allowed with -wasm-enable-sjlj");
 
   if (TM->Options.ExceptionModel == ExceptionHandling::None) {
     // FIXME: These flags should be removed in favor of directly using the
@@ -163,11 +169,10 @@ static void basicCheckForEHAndSjLj(TargetMachine *TM) {
 
   // Basic Correctness checking related to -exception-model
   if (TM->Options.ExceptionModel != ExceptionHandling::None &&
-      TM->Options.ExceptionModel != ExceptionHandling::Wasm)
-    report_fatal_error("-exception-model should be either 'none' or 'wasm'");
-  if (WasmEnableEmEH && TM->Options.ExceptionModel == ExceptionHandling::Wasm)
-    report_fatal_error("-exception-model=wasm not allowed with "
-                       "-enable-emscripten-cxx-exceptions");
+      TM->Options.ExceptionModel != ExceptionHandling::Wasm &&
+      TM->Options.ExceptionModel != ExceptionHandling::EmscriptenEH)
+    report_fatal_error(
+        "-exception-model should be either 'none', 'wasm', or 'emscripten'");
   if (WasmEnableEH && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
     report_fatal_error(
         "-wasm-enable-eh only allowed with -exception-model=wasm");
@@ -337,7 +342,10 @@ void WebAssemblyPassConfig::addIRPasses() {
   // TargetPassConfig::addPassesToHandleExceptions, but that runs after these 
IR
   // passes and Emscripten SjLj handling expects all invokes to be lowered
   // before.
-  if (!WasmEnableEmEH && !WasmEnableEH) {
+  bool EnableEmEH =
+      TM->Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
+      WasmEnableEmEH;
+  if (!EnableEmEH && !WasmEnableEH) {
     addPass(createLowerInvokePass());
     // The lower invoke pass may create unreachable code. Remove it in order 
not
     // to process dead blocks in setjmp/longjmp handling.
@@ -348,8 +356,8 @@ void WebAssemblyPassConfig::addIRPasses() {
   // done in WasmEHPrepare pass, Wasm SjLj preparation shares libraries and
   // transformation algorithms with Emscripten SjLj, so we run
   // LowerEmscriptenEHSjLj pass also when Wasm SjLj is enabled.
-  if (WasmEnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj)
-    addPass(createWebAssemblyLowerEmscriptenEHSjLjLegacyPass());
+  if (EnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj)
+    addPass(createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(EnableEmEH));
 
   // Expand indirectbr instructions to switches.
   addPass(createIndirectBrExpandPass());
diff --git a/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll 
b/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll
index 74d02ddc405d3..010c06a2283d5 100644
--- a/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll
+++ b/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll
@@ -1,19 +1,16 @@
 target triple = "wasm32-unknown-unknown"
 
-; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions -wasm-enable-eh 
2>&1 | FileCheck %s --check-prefix=EM_EH_W_WASM_EH
-; EM_EH_W_WASM_EH: LLVM ERROR: -enable-emscripten-cxx-exceptions not allowed 
with -wasm-enable-eh
+; RUN: not --crash llc < %s -exception-model=emscripten -wasm-enable-eh 2>&1 | 
FileCheck %s --check-prefix=EM_EH_W_WASM_EH
+; EM_EH_W_WASM_EH: LLVM ERROR: -exception-model=emscripten not allowed with 
-wasm-enable-eh
 
 ; RUN: not --crash llc < %s -enable-emscripten-sjlj -wasm-enable-sjlj 2>&1 | 
FileCheck %s --check-prefix=EM_SJLJ_W_WASM_SJLJ
 ; EM_SJLJ_W_WASM_SJLJ: LLVM ERROR: -enable-emscripten-sjlj not allowed with 
-wasm-enable-sjlj
 
-; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions 
-wasm-enable-sjlj 2>&1 | FileCheck %s --check-prefix=EM_EH_W_WASM_SJLJ
-; EM_EH_W_WASM_SJLJ: LLVM ERROR: -enable-emscripten-cxx-exceptions not allowed 
with -wasm-enable-sjlj
+; RUN: not --crash llc < %s -exception-model=emscripten -wasm-enable-sjlj 2>&1 
| FileCheck %s --check-prefix=EM_EH_W_WASM_SJLJ
+; EM_EH_W_WASM_SJLJ: LLVM ERROR: -exception-model=emscripten not allowed with 
-wasm-enable-sjlj
 
 ; RUN: not --crash llc < %s -wasm-enable-eh -exception-model=dwarf 2>&1 | 
FileCheck %s --check-prefix=EH_MODEL_DWARF
-; EH_MODEL_DWARF: LLVM ERROR: -exception-model should be either 'none' or 
'wasm'
-
-; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions 
-exception-model=wasm 2>&1 | FileCheck %s --check-prefix=EM_EH_W_MODEL_WASM
-; EM_EH_W_MODEL_WASM: LLVM ERROR: -exception-model=wasm not allowed with 
-enable-emscripten-cxx-exceptions
+; EH_MODEL_DWARF: LLVM ERROR: -exception-model should be either 'none', 
'wasm', or 'emscripten'
 
 ; RUN: not --crash llc < %s -exception-model=wasm 2>&1 | FileCheck %s 
--check-prefix=MODEL_WASM_WO_WASM_EH_SJLJ
 ; MODEL_WASM_WO_WASM_EH_SJLJ: LLVM ERROR: -exception-model=wasm only allowed 
with at least one of -wasm-enable-eh or -wasm-enable-sjlj

>From 178e6dd3fe35dc2143de18dca4de651f5e578b46 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <[email protected]>
Date: Mon, 14 Sep 2026 14:35:57 +0200
Subject: [PATCH 2/2] Rename enum

---
 clang/include/clang/Basic/CodeGenOptions.h                  | 4 ++--
 clang/include/clang/Options/Options.td                      | 2 +-
 clang/lib/CodeGen/BackendUtil.cpp                           | 2 +-
 llvm/include/llvm/Support/CodeGen.h                         | 2 +-
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp                  | 2 +-
 llvm/lib/CodeGen/CommandFlags.cpp                           | 4 ++--
 llvm/lib/CodeGen/TargetPassConfig.cpp                       | 2 +-
 llvm/lib/Passes/CodeGenPassBuilder.cpp                      | 2 +-
 llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp       | 2 +-
 .../Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp    | 2 +-
 llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp    | 6 +++---
 11 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/clang/include/clang/Basic/CodeGenOptions.h 
b/clang/include/clang/Basic/CodeGenOptions.h
index 8b65a5bc920a5..4632d79cd551a 100644
--- a/clang/include/clang/Basic/CodeGenOptions.h
+++ b/clang/include/clang/Basic/CodeGenOptions.h
@@ -205,7 +205,7 @@ class CodeGenOptions : public CodeGenOptionsBase {
     WinEH,
     DwarfCFI,
     Wasm,
-    EmscriptenEH
+    Emscripten
   };
 
   enum class SwiftAsyncFramePointerKind {
@@ -642,7 +642,7 @@ class CodeGenOptions : public CodeGenOptionsBase {
   }
 
   bool hasEmscriptenExceptions() const {
-    return getExceptionHandling() == ExceptionHandlingKind::EmscriptenEH;
+    return getExceptionHandling() == ExceptionHandlingKind::Emscripten;
   }
 
   /// Check if Clang profile instrumenation is on.
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index c0c89c691683a..c109b385350f3 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2462,7 +2462,7 @@ def exception_model : Separate<["-"], "exception-model">,
   Visibility<[CC1Option]>, HelpText<"The exception model">,
   Values<"dwarf,sjlj,seh,wasm,emscripten,none">,
   NormalizedValuesScope<"CodeGenOptions::ExceptionHandlingKind">,
-  NormalizedValues<["DwarfCFI", "SjLj", "WinEH", "Wasm", "EmscriptenEH", 
"None"]>,
+  NormalizedValues<["DwarfCFI", "SjLj", "WinEH", "Wasm", "Emscripten", 
"None"]>,
   MarshallingInfoEnum<CodeGenOpts<"ExceptionHandling">, "None">;
 def exception_model_EQ : Joined<["-"], "exception-model=">,
   Visibility<[CC1Option]>, Alias<exception_model>;
diff --git a/clang/lib/CodeGen/BackendUtil.cpp 
b/clang/lib/CodeGen/BackendUtil.cpp
index dcc77f7aa4d58..fc6ff147a41a4 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -405,7 +405,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
   if (CodeGenOpts.hasWasmExceptions())
     Options.ExceptionModel = llvm::ExceptionHandling::Wasm;
   if (CodeGenOpts.hasEmscriptenExceptions())
-    Options.ExceptionModel = llvm::ExceptionHandling::EmscriptenEH;
+    Options.ExceptionModel = llvm::ExceptionHandling::Emscripten;
 
   Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS;
 
diff --git a/llvm/include/llvm/Support/CodeGen.h 
b/llvm/include/llvm/Support/CodeGen.h
index a6c276a6a15b2..40b4dc98d19ba 100644
--- a/llvm/include/llvm/Support/CodeGen.h
+++ b/llvm/include/llvm/Support/CodeGen.h
@@ -58,7 +58,7 @@ namespace llvm {
     ARM,          ///< ARM EHABI
     WinEH,        ///< Windows Exception Handling
     Wasm,         ///< WebAssembly Exception Handling
-    EmscriptenEH, ///< Emscripten JavaScript-based C++ exception handling
+    Emscripten,   ///< Emscripten JavaScript-based exception handling
     AIX,          ///< AIX Exception Handling
     ZOS, ///< z/OS MVS Exception Handling. Very similar to DwarfCFI, but the
          ///< PPA1 is used instead of an .eh_frame section.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp 
b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index ef0f74a1cf802..5ca684a2c016c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -669,7 +669,7 @@ bool AsmPrinter::doInitialization(Module &M) {
   EHStreamer *ES = nullptr;
   switch (MAI.getExceptionHandlingType()) {
   case ExceptionHandling::None:
-  case ExceptionHandling::EmscriptenEH:
+  case ExceptionHandling::Emscripten:
     // Emscripten EH is handled in JS glue code and emits no EH tables here.
     if (!usesCFIWithoutEH())
       break;
diff --git a/llvm/lib/CodeGen/CommandFlags.cpp 
b/llvm/lib/CodeGen/CommandFlags.cpp
index 56f191a5972e6..cdd286b562163 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -196,8 +196,8 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() {
                      "Windows exception model"),
           clEnumValN(ExceptionHandling::Wasm, "wasm",
                      "WebAssembly exception handling"),
-          clEnumValN(ExceptionHandling::EmscriptenEH, "emscripten",
-                     "Emscripten JavaScript-based C++ exception handling")));
+          clEnumValN(ExceptionHandling::Emscripten, "emscripten",
+                     "Emscripten JavaScript-based exception handling")));
   CGBINDOPT(ExceptionModel);
 
   static cl::opt<CodeGenFileType> FileType(
diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp 
b/llvm/lib/CodeGen/TargetPassConfig.cpp
index 3d8883a8a2049..75fba01042c8d 100644
--- a/llvm/lib/CodeGen/TargetPassConfig.cpp
+++ b/llvm/lib/CodeGen/TargetPassConfig.cpp
@@ -961,7 +961,7 @@ void TargetPassConfig::addPassesToHandleExceptions() {
     addPass(createWasmEHPass());
     break;
   case ExceptionHandling::None:
-  case ExceptionHandling::EmscriptenEH:
+  case ExceptionHandling::Emscripten:
     // Emscripten EH is lowered earlier by WebAssemblyLowerEmscriptenEHSjLj, so
     // by this point it needs no generic EH preparation, like the None case.
     addPass(createLowerInvokePass());
diff --git a/llvm/lib/Passes/CodeGenPassBuilder.cpp 
b/llvm/lib/Passes/CodeGenPassBuilder.cpp
index 57d4b74c4e24c..e67377d7c6b3d 100644
--- a/llvm/lib/Passes/CodeGenPassBuilder.cpp
+++ b/llvm/lib/Passes/CodeGenPassBuilder.cpp
@@ -473,7 +473,7 @@ void 
CodeGenPassBuilder::addPassesToHandleExceptions(PassManagerWrapper &PMW) {
     addFunctionPass(WasmEHPreparePass(), PMW);
     break;
   case ExceptionHandling::None:
-  case ExceptionHandling::EmscriptenEH:
+  case ExceptionHandling::Emscripten:
     // Emscripten EH is lowered earlier by WebAssemblyLowerEmscriptenEHSjLj, so
     // by this point it needs no generic EH preparation, like the None case.
     addFunctionPass(LowerInvokePass(), PMW);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index d64f03c24b11c..5929b0f77359c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -166,7 +166,7 @@ MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction(
   MCSymbolWasm *WasmSym = nullptr;
 
   const bool EnableEmEH =
-      TM.Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
+      TM.Options.ExceptionModel == ExceptionHandling::Emscripten ||
       WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj;
   if (EnableEmEH && isEmscriptenInvokeName(F->getName())) {
     assert(Sig);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
index 653080fd81582..82f7fdd2b7079 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
@@ -128,7 +128,7 @@ void 
WebAssemblyCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) {
   // passes and Emscripten SjLj handling expects all invokes to be lowered
   // before.
   bool EnableEmEH =
-      TM.Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
+      TM.Options.ExceptionModel == ExceptionHandling::Emscripten ||
       WasmEnableEmEH;
   if (!EnableEmEH && !WasmEnableEH) {
     addFunctionPass(LowerInvokePass(), PMW);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp 
b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index a9a905b6698c0..61a14c852ca4b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -144,7 +144,7 @@ static void basicCheckForEHAndSjLj(TargetMachine *TM) {
   // Emscripten EH is selected by the exception model. WasmEnableEmEH is a
   // deprecated cl::opt alias, OR-ed in here until it is removed.
   bool EnableEmEH =
-      TM->Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
+      TM->Options.ExceptionModel == ExceptionHandling::Emscripten ||
       WasmEnableEmEH;
 
   // You can't enable two modes of EH at the same time
@@ -170,7 +170,7 @@ static void basicCheckForEHAndSjLj(TargetMachine *TM) {
   // Basic Correctness checking related to -exception-model
   if (TM->Options.ExceptionModel != ExceptionHandling::None &&
       TM->Options.ExceptionModel != ExceptionHandling::Wasm &&
-      TM->Options.ExceptionModel != ExceptionHandling::EmscriptenEH)
+      TM->Options.ExceptionModel != ExceptionHandling::Emscripten)
     report_fatal_error(
         "-exception-model should be either 'none', 'wasm', or 'emscripten'");
   if (WasmEnableEH && TM->Options.ExceptionModel != ExceptionHandling::Wasm)
@@ -343,7 +343,7 @@ void WebAssemblyPassConfig::addIRPasses() {
   // passes and Emscripten SjLj handling expects all invokes to be lowered
   // before.
   bool EnableEmEH =
-      TM->Options.ExceptionModel == ExceptionHandling::EmscriptenEH ||
+      TM->Options.ExceptionModel == ExceptionHandling::Emscripten ||
       WasmEnableEmEH;
   if (!EnableEmEH && !WasmEnableEH) {
     addPass(createLowerInvokePass());

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to