about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJacob Pratt <jacob@jhpratt.dev>2025-01-06 22:04:13 -0500
committerGitHub <noreply@github.com>2025-01-06 22:04:13 -0500
commit4e4a93c2dd4bae8472924d03c37f387fbf3b074c (patch)
treec8db61e78f14c45c4121735e00d7d6d7c8e5d35d
parent0f1e965fec3bc2f97b932e9dd8e85fca6d7faadc (diff)
parent49c74234a79107afa7f86ca947708c3abef07674 (diff)
downloadrust-4e4a93c2dd4bae8472924d03c37f387fbf3b074c.tar.gz
rust-4e4a93c2dd4bae8472924d03c37f387fbf3b074c.zip
Rollup merge of #131830 - hoodmane:emscripten-wasm-eh, r=workingjubilee
Add support for wasm exception handling to Emscripten target

This is a draft because we need some additional setting for the Emscripten target to select between the old exception handling and the new exception handling. I don't know how to add a setting like that, would appreciate advice from Rust folks. We could maybe choose to use the new exception handling if `Ctarget-feature=+exception-handling` is passed? I tried this but I get errors from llvm so I'm not doing it right.
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs3
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs1
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_passes/src/weak_lang_items.rs5
-rw-r--r--compiler/rustc_session/src/config/cfg.rs5
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--library/panic_unwind/Cargo.toml2
-rw-r--r--library/panic_unwind/src/lib.rs3
-rw-r--r--library/unwind/Cargo.toml2
-rw-r--r--library/unwind/src/lib.rs3
-rw-r--r--src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md6
-rw-r--r--tests/codegen/emscripten-catch-unwind-js-eh.rs (renamed from tests/codegen/emcripten-catch-unwind.rs)0
-rw-r--r--tests/codegen/emscripten-catch-unwind-wasm-eh.rs65
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr8
-rw-r--r--tests/ui/cfg/disallowed-cli-cfgs.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr12
21 files changed, 131 insertions, 10 deletions
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index e18e91e569f..c3d7c217861 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -109,7 +109,10 @@ unsafe fn configure_llvm(sess: &Session) {
             add("-wasm-enable-eh", false);
         }
 
-        if sess.target.os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind {
+        if sess.target.os == "emscripten"
+            && !sess.opts.unstable_opts.emscripten_wasm_eh
+            && sess.panic_strategy() == PanicStrategy::Unwind
+        {
             add("-enable-emscripten-cxx-exceptions", false);
         }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 2587d6dfdc4..e4b3ad19801 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2451,10 +2451,12 @@ fn add_order_independent_options(
     }
 
     if sess.target.os == "emscripten" {
-        cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
-            "DISABLE_EXCEPTION_CATCHING=1"
+        cmd.cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
+            "-sDISABLE_EXCEPTION_CATCHING=1"
+        } else if sess.opts.unstable_opts.emscripten_wasm_eh {
+            "-fwasm-exceptions"
         } else {
-            "DISABLE_EXCEPTION_CATCHING=0"
+            "-sDISABLE_EXCEPTION_CATCHING=0"
         });
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 77e1fed720d..544578b29f1 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -388,7 +388,8 @@ pub(crate) fn build_shift_expr_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 // exceptions. This means that the VM does the unwinding for
 // us
 pub fn wants_wasm_eh(sess: &Session) -> bool {
-    sess.target.is_like_wasm && sess.target.os != "emscripten"
+    sess.target.is_like_wasm
+        && (sess.target.os != "emscripten" || sess.opts.unstable_opts.emscripten_wasm_eh)
 }
 
 /// Returns `true` if this session's target will use SEH-based unwinding.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 00bb4d65579..5421517046d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -37,6 +37,7 @@ const GATED_CFGS: &[GatedCfg] = &[
     (sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
     // this is consistent with naming of the compiler flag it's for
     (sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
+    (sym::emscripten_wasm_eh, sym::cfg_emscripten_wasm_eh, Features::cfg_emscripten_wasm_eh),
 ];
 
 /// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index d40823d2ed6..8cc4c18c02a 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -202,6 +202,8 @@ declare_features! (
     (internal, allow_internal_unstable, "1.0.0", None),
     /// Allows using anonymous lifetimes in argument-position impl-trait.
     (unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
+    /// Allows access to the emscripten_wasm_eh config, used by panic_unwind and unwind
+    (internal, cfg_emscripten_wasm_eh, "CURRENT_RUSTC_VERSION", None),
     /// Allows identifying the `compiler_builtins` crate.
     (internal, compiler_builtins, "1.13.0", None),
     /// Allows writing custom MIR
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 9ad69039914..b50f3b38f2e 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -782,6 +782,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(dwarf_version, Some(5));
     tracked!(embed_source, true);
     tracked!(emit_thin_lto, false);
+    tracked!(emscripten_wasm_eh, true);
     tracked!(export_executable_symbols, true);
     tracked!(fewer_names, Some(true));
     tracked!(fixed_x18, true);
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index 020128f29c5..701f500e4f6 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -26,7 +26,10 @@ pub(crate) fn check_crate(
     if items.eh_personality().is_none() {
         items.missing.push(LangItem::EhPersonality);
     }
-    if tcx.sess.target.os == "emscripten" && items.eh_catch_typeinfo().is_none() {
+    if tcx.sess.target.os == "emscripten"
+        && items.eh_catch_typeinfo().is_none()
+        && !tcx.sess.opts.unstable_opts.emscripten_wasm_eh
+    {
         items.missing.push(LangItem::EhCatchTypeinfo);
     }
 
diff --git a/compiler/rustc_session/src/config/cfg.rs b/compiler/rustc_session/src/config/cfg.rs
index b68dfeffa34..d586f913335 100644
--- a/compiler/rustc_session/src/config/cfg.rs
+++ b/compiler/rustc_session/src/config/cfg.rs
@@ -143,6 +143,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
             | (sym::target_has_atomic_load_store, Some(_))
             | (sym::target_thread_local, None) => disallow(cfg, "--target"),
             (sym::fmt_debug, None | Some(_)) => disallow(cfg, "-Z fmt-debug"),
+            (sym::emscripten_wasm_eh, None | Some(_)) => disallow(cfg, "-Z emscripten_wasm_eh"),
             _ => {}
         }
     }
@@ -295,6 +296,10 @@ pub(crate) fn default_configuration(sess: &Session) -> Cfg {
         ins_none!(sym::ub_checks);
     }
 
+    // Nightly-only implementation detail for the `panic_unwind` and `unwind` crates.
+    if sess.is_nightly_build() && sess.opts.unstable_opts.emscripten_wasm_eh {
+        ins_none!(sym::emscripten_wasm_eh);
+    }
     ret
 }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 3772a4a08af..a344ec94a26 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1771,6 +1771,8 @@ options! {
         "emit a section containing stack size metadata (default: no)"),
     emit_thin_lto: bool = (true, parse_bool, [TRACKED],
         "emit the bc module with thin LTO info (default: yes)"),
+    emscripten_wasm_eh: bool = (false, parse_bool, [TRACKED],
+        "Use WebAssembly error handling for wasm32-unknown-emscripten"),
     enforce_type_length_limit: bool = (false, parse_bool, [TRACKED],
         "enforce the type length limit when monomorphizing instances in codegen"),
     export_executable_symbols: bool = (false, parse_bool, [TRACKED],
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index bdfbfb1e38d..0dcf38e3493 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -570,6 +570,7 @@ symbols! {
         cfg_autodiff_fallback,
         cfg_boolean_literals,
         cfg_doctest,
+        cfg_emscripten_wasm_eh,
         cfg_eval,
         cfg_fmt_debug,
         cfg_hide,
@@ -823,6 +824,7 @@ symbols! {
         emit_enum_variant_arg,
         emit_struct,
         emit_struct_field,
+        emscripten_wasm_eh,
         enable,
         encode,
         end,
diff --git a/library/panic_unwind/Cargo.toml b/library/panic_unwind/Cargo.toml
index 252f118fecf..c2abb79192e 100644
--- a/library/panic_unwind/Cargo.toml
+++ b/library/panic_unwind/Cargo.toml
@@ -23,4 +23,4 @@ libc = { version = "0.2", default-features = false }
 
 [lints.rust.unexpected_cfgs]
 level = "warn"
-check-cfg = []
+check-cfg = ['cfg(emscripten_wasm_eh)']
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index 8c28bb5c5b0..dc78be76cb4 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -25,13 +25,14 @@
 // `real_imp` is unused with Miri, so silence warnings.
 #![cfg_attr(miri, allow(dead_code))]
 #![allow(internal_features)]
+#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))]
 
 use alloc::boxed::Box;
 use core::any::Any;
 use core::panic::PanicPayload;
 
 cfg_if::cfg_if! {
-    if #[cfg(target_os = "emscripten")] {
+    if #[cfg(all(target_os = "emscripten", not(emscripten_wasm_eh)))] {
         #[path = "emcc.rs"]
         mod imp;
     } else if #[cfg(target_os = "hermit")] {
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index e13c9a06c05..66e8d1a3ffe 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -37,4 +37,4 @@ system-llvm-libunwind = []
 
 [lints.rust.unexpected_cfgs]
 level = "warn"
-check-cfg = []
+check-cfg = ['cfg(emscripten_wasm_eh)']
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 7af1882ab73..e4ba2bc1ed8 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -4,10 +4,11 @@
 #![feature(staged_api)]
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 #![cfg_attr(
-    all(target_family = "wasm", not(target_os = "emscripten")),
+    all(target_family = "wasm", any(not(target_os = "emscripten"), emscripten_wasm_eh)),
     feature(simd_wasm64, wasm_exception_handling_intrinsics)
 )]
 #![allow(internal_features)]
+#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))]
 
 // Force libc to be included even if unused. This is required by many platforms.
 #[cfg(not(all(windows, target_env = "msvc")))]
diff --git a/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md b/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md
new file mode 100644
index 00000000000..eab29a1744b
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/emscripten-wasm-eh.md
@@ -0,0 +1,6 @@
+# `emscripten-wasm-eh`
+
+Use the WebAssembly exception handling ABI to unwind for the
+`wasm32-unknown-emscripten`. If compiling with this setting, the `emcc` linker
+should be invoked with `-fwasm-exceptions`. If linking with C/C++ files, the
+C/C++ files should also be compiled with `-fwasm-exceptions`.
diff --git a/tests/codegen/emcripten-catch-unwind.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs
index b15fb40b68f..b15fb40b68f 100644
--- a/tests/codegen/emcripten-catch-unwind.rs
+++ b/tests/codegen/emscripten-catch-unwind-js-eh.rs
diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
new file mode 100644
index 00000000000..72395f432d5
--- /dev/null
+++ b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
@@ -0,0 +1,65 @@
+//@ compile-flags: -O --target wasm32-unknown-emscripten -Z emscripten-wasm-eh
+//@ needs-llvm-components: webassembly
+
+// Emscripten catch_unwind using wasm exceptions
+
+#![feature(no_core, lang_items, intrinsics, rustc_attrs)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "freeze"]
+trait Freeze {}
+#[lang = "copy"]
+trait Copy {}
+
+impl<T> Copy for *mut T {}
+
+#[rustc_intrinsic]
+fn size_of<T>() -> usize {
+    loop {}
+}
+
+extern "rust-intrinsic" {
+    fn catch_unwind(
+        try_fn: fn(_: *mut u8),
+        data: *mut u8,
+        catch_fn: fn(_: *mut u8, _: *mut u8),
+    ) -> i32;
+}
+
+// CHECK-LABEL: @ptr_size
+#[no_mangle]
+pub fn ptr_size() -> usize {
+    // CHECK: ret [[PTR_SIZE:.*]]
+    size_of::<*mut u8>()
+}
+
+// CHECK-LABEL: @test_catch_unwind
+#[no_mangle]
+pub unsafe fn test_catch_unwind(
+    try_fn: fn(_: *mut u8),
+    data: *mut u8,
+    catch_fn: fn(_: *mut u8, _: *mut u8),
+) -> i32 {
+    // CHECK: start:
+    // CHECK: invoke void %try_fn(ptr %data)
+    // CHECK:         to label %__rust_try.exit unwind label %catchswitch.i
+    // CHECK:   catchswitch.i:                                    ; preds = %start
+    // CHECK:   %catchswitch1.i = catchswitch within none [label %catchpad.i] unwind to caller
+
+    // CHECK: catchpad.i:                                       ; preds = %catchswitch.i
+    // CHECK:   %catchpad2.i = catchpad within %catchswitch1.i [ptr null]
+    // CHECK:   %0 = tail call ptr @llvm.wasm.get.exception(token %catchpad2.i)
+    // CHECK:   %1 = tail call i32 @llvm.wasm.get.ehselector(token %catchpad2.i)
+    // CHECK:   call void %catch_fn(ptr %data, ptr %0) [ "funclet"(token %catchpad2.i) ]
+    // CHECK:   catchret from %catchpad2.i to label %__rust_try.exit
+
+    // CHECK: __rust_try.exit:                                  ; preds = %start, %catchpad.i
+    // CHECK:   %common.ret.op.i = phi i32 [ 0, %start ], [ 1, %catchpad.i ]
+    // CHECK:   ret i32 %common.ret.op.i
+
+    catch_unwind(try_fn, data, catch_fn)
+}
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr b/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr
new file mode 100644
index 00000000000..8b2ee0e5c0c
--- /dev/null
+++ b/tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr
@@ -0,0 +1,8 @@
+error: unexpected `--cfg emscripten_wasm_eh` flag
+   |
+   = note: config `emscripten_wasm_eh` is only supposed to be controlled by `-Z emscripten_wasm_eh`
+   = note: manually setting a built-in cfg can and does create incoherent behaviors
+   = note: `#[deny(explicit_builtin_cfgs_in_flags)]` on by default
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/cfg/disallowed-cli-cfgs.rs b/tests/ui/cfg/disallowed-cli-cfgs.rs
index 3c9ee87f28a..cae9c65cb45 100644
--- a/tests/ui/cfg/disallowed-cli-cfgs.rs
+++ b/tests/ui/cfg/disallowed-cli-cfgs.rs
@@ -7,6 +7,7 @@
 //@ revisions: target_has_atomic_equal_alignment_ target_has_atomic_load_store_
 //@ revisions: target_thread_local_ relocation_model_
 //@ revisions: fmt_debug_
+//@ revisions: emscripten_wasm_eh_
 
 //@ [overflow_checks_]compile-flags: --cfg overflow_checks
 //@ [debug_assertions_]compile-flags: --cfg debug_assertions
@@ -33,5 +34,6 @@
 //@ [target_thread_local_]compile-flags: --cfg target_thread_local
 //@ [relocation_model_]compile-flags: --cfg relocation_model="a"
 //@ [fmt_debug_]compile-flags: --cfg fmt_debug="shallow"
+//@ [emscripten_wasm_eh_]compile-flags: --cfg emscripten_wasm_eh
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs
new file mode 100644
index 00000000000..cff98b43fe7
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs
@@ -0,0 +1,4 @@
+//@ compile-flags: --check-cfg=cfg(emscripten_wasm_eh)
+#[cfg(not(emscripten_wasm_eh))]
+//~^ `cfg(emscripten_wasm_eh)` is experimental
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr
new file mode 100644
index 00000000000..67769e3c758
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr
@@ -0,0 +1,12 @@
+error[E0658]: `cfg(emscripten_wasm_eh)` is experimental and subject to change
+  --> $DIR/feature-gate-cfg-emscripten-wasm-eh.rs:2:11
+   |
+LL | #[cfg(not(emscripten_wasm_eh))]
+   |           ^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(cfg_emscripten_wasm_eh)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.