diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 628c0b1c29c44..b3e1210632fe2 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 4bc064528f3f0..0a941a8960946 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2466,10 +2466,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 77e1fed720dfb..544578b29f107 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 4112ae8098075..09c8a8a06ec76 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 d40823d2ed627..8cc4c18c02abf 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 9ad690399140e..b50f3b38f2e18 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 020128f29c59b..701f500e4f60b 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 3426858495b71..40016cb76d6d4 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 3772a4a08af01..a344ec94a263b 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 4ecc4201f89d5..e62107c450ef3 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 252f118fecfbb..c2abb79192e9f 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 1981675f40922..085c07591d2aa 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 e13c9a06c05d1..66e8d1a3ffe5f 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 40d409310ffab..9b93f0b3da0a5 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 0000000000000..eab29a1744b67 --- /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 similarity index 100% rename from tests/codegen/emcripten-catch-unwind.rs rename to 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 0000000000000..72395f432d5f8 --- /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 Copy for *mut T {} + +#[rustc_intrinsic] +fn size_of() -> 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 0000000000000..8b2ee0e5c0c3d --- /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 3c9ee87f28ab8..cae9c65cb45ac 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 0000000000000..cff98b43fe745 --- /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 0000000000000..67769e3c7586b --- /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`.