Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for wasm exception handling to Emscripten target #131830

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_codegen_llvm/src/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"
});
}

Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_passes/src/weak_lang_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_session/src/config/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
hoodmane marked this conversation as resolved.
Show resolved Hide resolved
_ => {}
}
}
Expand Down Expand Up @@ -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
}

Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ symbols! {
cfg_autodiff_fallback,
cfg_boolean_literals,
cfg_doctest,
cfg_emscripten_wasm_eh,
cfg_eval,
cfg_fmt_debug,
cfg_hide,
Expand Down Expand Up @@ -823,6 +824,7 @@ symbols! {
emit_enum_variant_arg,
emit_struct,
emit_struct_field,
emscripten_wasm_eh,
enable,
encode,
end,
Expand Down
2 changes: 1 addition & 1 deletion library/panic_unwind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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)']
3 changes: 2 additions & 1 deletion library/panic_unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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))]
hoodmane marked this conversation as resolved.
Show resolved Hide resolved

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")] {
Expand Down
2 changes: 1 addition & 1 deletion library/unwind/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ system-llvm-libunwind = []

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = []
check-cfg = ['cfg(emscripten_wasm_eh)']
3 changes: 2 additions & 1 deletion library/unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)),
hoodmane marked this conversation as resolved.
Show resolved Hide resolved
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")))]
Expand Down
Original file line number Diff line number Diff line change
@@ -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`.
65 changes: 65 additions & 0 deletions tests/codegen/emscripten-catch-unwind-wasm-eh.rs
Original file line number Diff line number Diff line change
@@ -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)
}
8 changes: 8 additions & 0 deletions tests/ui/cfg/disallowed-cli-cfgs.emscripten_wasm_eh_.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 2 additions & 0 deletions tests/ui/cfg/disallowed-cli-cfgs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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() {}
4 changes: 4 additions & 0 deletions tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.rs
Original file line number Diff line number Diff line change
@@ -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() {}
12 changes: 12 additions & 0 deletions tests/ui/feature-gates/feature-gate-cfg-emscripten-wasm-eh.stderr
Original file line number Diff line number Diff line change
@@ -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`.
Loading