[clang] clang: Set the exception model module flag for IR inputs (PR #228372)

Matt Arsenault via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 2 02:42:17 PDT 2026


https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/228372

Previously the -exception-model cc1 flag did nothing for IR inputs. Record the
module flag in the IR input path too, next to the existing triple override. A
 model contradicting one the input module already records is rejected matching
err_data_layout_mismatch and the conflict llc reports for the same pair of
inputs.

This is to keep the wasm-eh.ll test passing when the TargetOptions field for
ExecptionModel is removed. I'm not sure if this behavior really needs to be
preserved given the bitcode producers should now materialize the flag in the
IR.

Co-authored-by: Claude Opus 5 <noreply at anthropic.com>

>From 77888757b800d2457015261de582af0d7d2636d8 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Wed, 30 Sep 2026 15:14:50 +0200
Subject: [PATCH] clang: Set the exception model module flag for IR inputs

Previously the -exception-model cc1 flag did nothing for IR inputs. Record the
module flag in the IR input path too, next to the existing triple override. A
 model contradicting one the input module already records is rejected matching
err_data_layout_mismatch and the conflict llc reports for the same pair of
inputs.

This is to keep the wasm-eh.ll test passing when the TargetOptions field for
ExecptionModel is removed. I'm not sure if this behavior really needs to be
preserved given the bitcode producers should now materialize the flag in the
IR.

Co-authored-by: Claude Opus 5 <noreply at anthropic.com>
---
 .../clang/Basic/DiagnosticFrontendKinds.td    |  3 +++
 clang/lib/CodeGen/CodeGenAction.cpp           | 18 +++++++++++++++++
 ...-exception-model-flag-ir-input-mismatch.ll | 20 +++++++++++++++++++
 ...asm-exception-model-flag-parse-ir-input.ll |  8 ++++++--
 4 files changed, 47 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-ir-input-mismatch.ll

diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 840bade066430..c8ade96ae3d50 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -505,6 +505,9 @@ def warn_hlsl_failed_to_embed_source
 
 def err_data_layout_mismatch : Error<"backend data layout '%0' does not match "
                                      "expected target description '%1'">;
+def err_fe_exception_model_mismatch
+    : Error<"'-exception-model=%0' does not match the module's exception "
+            "model '%1'">;
 def err_failed_to_open_for_embedding
     : Error<"could not open '%0' for embedding">;
 def err_unsupported_cxx_abi_feature
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp
index 7b2d39069702a..de677a385d832 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -575,6 +575,24 @@ void CodeGenAction::ExecuteAction() {
     TheModule->setTargetTriple(Triple(TargetOpts.Triple));
   }
 
+  llvm::ExceptionHandling ExceptionModel =
+      CodeGenOptions::toExceptionHandling(CodeGenOpts.getExceptionHandling());
+  if (ExceptionModel != llvm::ExceptionHandling::Default) {
+    StringRef ModelName = llvm::getExceptionModelName(ExceptionModel);
+    if (auto *Existing = cast_or_null<llvm::MDString>(
+            TheModule->getModuleFlag("exception-model"))) {
+      if (Existing->getString() != ModelName) {
+        Diagnostics.Report(diag::err_fe_exception_model_mismatch)
+            << ModelName << Existing->getString();
+        return;
+      }
+    } else {
+      TheModule->addModuleFlag(
+          llvm::Module::Error, "exception-model",
+          llvm::MDString::get(TheModule->getContext(), ModelName));
+    }
+  }
+
   EmbedObject(TheModule.get(), CodeGenOpts, CI.getVirtualFileSystem(),
               Diagnostics);
   EmbedBitcode(TheModule.get(), CodeGenOpts, *MainFile);
diff --git a/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-ir-input-mismatch.ll b/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-ir-input-mismatch.ll
new file mode 100644
index 0000000000000..c8aef1d31b0aa
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-ir-input-mismatch.ll
@@ -0,0 +1,20 @@
+; REQUIRES: webassembly-registered-target
+
+; An -exception-model= matching the input module's flag is accepted.
+; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=wasm %s | FileCheck %s
+
+; A contradicting one is rejected.
+; RUN: not %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=none %s 2>&1 | FileCheck -check-prefix=NONE %s
+; RUN: not %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=emscripten %s 2>&1 | FileCheck -check-prefix=EM %s
+
+; CHECK: !{i32 1, !"exception-model", !"wasm"}
+
+; NONE: error: '-exception-model=none' does not match the module's exception model 'wasm'
+; EM: error: '-exception-model=emscripten' does not match the module's exception model 'wasm'
+
+define void @test() {
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"exception-model", !"wasm"}
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 1410de231660a..b3ac28b472267 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
@@ -1,8 +1,8 @@
 ; REQUIRES: webassembly-registered-target
 
 ; Check all the options parse
-; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=none %s | FileCheck %s
-; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=wasm %s | FileCheck %s
+; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=none %s | FileCheck -check-prefixes=CHECK,NONE %s
+; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=wasm %s | FileCheck -check-prefixes=CHECK,WASM %s
 
 ; RUN: not %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=invalid %s 2>&1 | FileCheck -check-prefix=ERR %s
 ; RUN: not %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=dwarf %s 2>&1 | FileCheck -check-prefix=ERR-BE %s
@@ -10,6 +10,10 @@
 
 ; CHECK-LABEL: define void @test(
 
+; The model is recorded on the module, as it is for source input.
+; NONE: !{i32 1, !"exception-model", !"none"}
+; WASM: !{i32 1, !"exception-model", !"wasm"}
+
 ; ERR: error: invalid value 'invalid' in '-exception-model=invalid'
 ; ERR-BE: fatal error: error in backend: -exception-model should be either 'none', 'wasm', or 'emscripten'
 define void @test() {



More information about the cfe-commits mailing list