Add support for wasm exception handling to Emscripten target
Gated behind an unstable `-Z emscripten-wasm-eh` flag
This commit is contained in:
parent
bf6f8a4d32
commit
49c74234a7
@ -109,7 +109,10 @@ unsafe fn configure_llvm(sess: &Session) {
|
|||||||
add("-wasm-enable-eh", false);
|
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);
|
add("-enable-emscripten-cxx-exceptions", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2466,10 +2466,12 @@ fn add_order_independent_options(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sess.target.os == "emscripten" {
|
if sess.target.os == "emscripten" {
|
||||||
cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
cmd.cc_arg(if sess.panic_strategy() == PanicStrategy::Abort {
|
||||||
"DISABLE_EXCEPTION_CATCHING=1"
|
"-sDISABLE_EXCEPTION_CATCHING=1"
|
||||||
|
} else if sess.opts.unstable_opts.emscripten_wasm_eh {
|
||||||
|
"-fwasm-exceptions"
|
||||||
} else {
|
} else {
|
||||||
"DISABLE_EXCEPTION_CATCHING=0"
|
"-sDISABLE_EXCEPTION_CATCHING=0"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
// exceptions. This means that the VM does the unwinding for
|
||||||
// us
|
// us
|
||||||
pub fn wants_wasm_eh(sess: &Session) -> bool {
|
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.
|
/// Returns `true` if this session's target will use SEH-based unwinding.
|
||||||
|
@ -37,6 +37,7 @@ const GATED_CFGS: &[GatedCfg] = &[
|
|||||||
(sym::sanitizer_cfi_normalize_integers, sym::cfg_sanitizer_cfi, Features::cfg_sanitizer_cfi),
|
(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
|
// this is consistent with naming of the compiler flag it's for
|
||||||
(sym::fmt_debug, sym::fmt_debug, Features::fmt_debug),
|
(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.
|
/// Find a gated cfg determined by the `pred`icate which is given the cfg's name.
|
||||||
|
@ -202,6 +202,8 @@ declare_features! (
|
|||||||
(internal, allow_internal_unstable, "1.0.0", None),
|
(internal, allow_internal_unstable, "1.0.0", None),
|
||||||
/// Allows using anonymous lifetimes in argument-position impl-trait.
|
/// Allows using anonymous lifetimes in argument-position impl-trait.
|
||||||
(unstable, anonymous_lifetime_in_impl_trait, "1.63.0", None),
|
(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.
|
/// Allows identifying the `compiler_builtins` crate.
|
||||||
(internal, compiler_builtins, "1.13.0", None),
|
(internal, compiler_builtins, "1.13.0", None),
|
||||||
/// Allows writing custom MIR
|
/// Allows writing custom MIR
|
||||||
|
@ -782,6 +782,7 @@ fn test_unstable_options_tracking_hash() {
|
|||||||
tracked!(dwarf_version, Some(5));
|
tracked!(dwarf_version, Some(5));
|
||||||
tracked!(embed_source, true);
|
tracked!(embed_source, true);
|
||||||
tracked!(emit_thin_lto, false);
|
tracked!(emit_thin_lto, false);
|
||||||
|
tracked!(emscripten_wasm_eh, true);
|
||||||
tracked!(export_executable_symbols, true);
|
tracked!(export_executable_symbols, true);
|
||||||
tracked!(fewer_names, Some(true));
|
tracked!(fewer_names, Some(true));
|
||||||
tracked!(fixed_x18, true);
|
tracked!(fixed_x18, true);
|
||||||
|
@ -26,7 +26,10 @@ pub(crate) fn check_crate(
|
|||||||
if items.eh_personality().is_none() {
|
if items.eh_personality().is_none() {
|
||||||
items.missing.push(LangItem::EhPersonality);
|
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);
|
items.missing.push(LangItem::EhCatchTypeinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,6 +143,7 @@ pub(crate) fn disallow_cfgs(sess: &Session, user_cfgs: &Cfg) {
|
|||||||
| (sym::target_has_atomic_load_store, Some(_))
|
| (sym::target_has_atomic_load_store, Some(_))
|
||||||
| (sym::target_thread_local, None) => disallow(cfg, "--target"),
|
| (sym::target_thread_local, None) => disallow(cfg, "--target"),
|
||||||
(sym::fmt_debug, None | Some(_)) => disallow(cfg, "-Z fmt-debug"),
|
(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);
|
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
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1771,6 +1771,8 @@ options! {
|
|||||||
"emit a section containing stack size metadata (default: no)"),
|
"emit a section containing stack size metadata (default: no)"),
|
||||||
emit_thin_lto: bool = (true, parse_bool, [TRACKED],
|
emit_thin_lto: bool = (true, parse_bool, [TRACKED],
|
||||||
"emit the bc module with thin LTO info (default: yes)"),
|
"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_type_length_limit: bool = (false, parse_bool, [TRACKED],
|
||||||
"enforce the type length limit when monomorphizing instances in codegen"),
|
"enforce the type length limit when monomorphizing instances in codegen"),
|
||||||
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
|
export_executable_symbols: bool = (false, parse_bool, [TRACKED],
|
||||||
|
@ -570,6 +570,7 @@ symbols! {
|
|||||||
cfg_autodiff_fallback,
|
cfg_autodiff_fallback,
|
||||||
cfg_boolean_literals,
|
cfg_boolean_literals,
|
||||||
cfg_doctest,
|
cfg_doctest,
|
||||||
|
cfg_emscripten_wasm_eh,
|
||||||
cfg_eval,
|
cfg_eval,
|
||||||
cfg_fmt_debug,
|
cfg_fmt_debug,
|
||||||
cfg_hide,
|
cfg_hide,
|
||||||
@ -823,6 +824,7 @@ symbols! {
|
|||||||
emit_enum_variant_arg,
|
emit_enum_variant_arg,
|
||||||
emit_struct,
|
emit_struct,
|
||||||
emit_struct_field,
|
emit_struct_field,
|
||||||
|
emscripten_wasm_eh,
|
||||||
enable,
|
enable,
|
||||||
encode,
|
encode,
|
||||||
end,
|
end,
|
||||||
|
@ -23,4 +23,4 @@ libc = { version = "0.2", default-features = false }
|
|||||||
|
|
||||||
[lints.rust.unexpected_cfgs]
|
[lints.rust.unexpected_cfgs]
|
||||||
level = "warn"
|
level = "warn"
|
||||||
check-cfg = []
|
check-cfg = ['cfg(emscripten_wasm_eh)']
|
||||||
|
@ -25,13 +25,14 @@
|
|||||||
// `real_imp` is unused with Miri, so silence warnings.
|
// `real_imp` is unused with Miri, so silence warnings.
|
||||||
#![cfg_attr(miri, allow(dead_code))]
|
#![cfg_attr(miri, allow(dead_code))]
|
||||||
#![allow(internal_features)]
|
#![allow(internal_features)]
|
||||||
|
#![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))]
|
||||||
|
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
use core::panic::PanicPayload;
|
use core::panic::PanicPayload;
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(target_os = "emscripten")] {
|
if #[cfg(all(target_os = "emscripten", not(emscripten_wasm_eh)))] {
|
||||||
#[path = "emcc.rs"]
|
#[path = "emcc.rs"]
|
||||||
mod imp;
|
mod imp;
|
||||||
} else if #[cfg(target_os = "hermit")] {
|
} else if #[cfg(target_os = "hermit")] {
|
||||||
|
@ -37,4 +37,4 @@ system-llvm-libunwind = []
|
|||||||
|
|
||||||
[lints.rust.unexpected_cfgs]
|
[lints.rust.unexpected_cfgs]
|
||||||
level = "warn"
|
level = "warn"
|
||||||
check-cfg = []
|
check-cfg = ['cfg(emscripten_wasm_eh)']
|
||||||
|
@ -4,10 +4,11 @@
|
|||||||
#![feature(staged_api)]
|
#![feature(staged_api)]
|
||||||
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
|
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
|
||||||
#![cfg_attr(
|
#![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)
|
feature(simd_wasm64, wasm_exception_handling_intrinsics)
|
||||||
)]
|
)]
|
||||||
#![allow(internal_features)]
|
#![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.
|
// Force libc to be included even if unused. This is required by many platforms.
|
||||||
#[cfg(not(all(windows, target_env = "msvc")))]
|
#[cfg(not(all(windows, target_env = "msvc")))]
|
||||||
|
@ -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
tests/codegen/emscripten-catch-unwind-wasm-eh.rs
Normal file
65
tests/codegen/emscripten-catch-unwind-wasm-eh.rs
Normal file
@ -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)
|
||||||
|
}
|
@ -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
|
||||||
|
|
@ -7,6 +7,7 @@
|
|||||||
//@ revisions: target_has_atomic_equal_alignment_ target_has_atomic_load_store_
|
//@ revisions: target_has_atomic_equal_alignment_ target_has_atomic_load_store_
|
||||||
//@ revisions: target_thread_local_ relocation_model_
|
//@ revisions: target_thread_local_ relocation_model_
|
||||||
//@ revisions: fmt_debug_
|
//@ revisions: fmt_debug_
|
||||||
|
//@ revisions: emscripten_wasm_eh_
|
||||||
|
|
||||||
//@ [overflow_checks_]compile-flags: --cfg overflow_checks
|
//@ [overflow_checks_]compile-flags: --cfg overflow_checks
|
||||||
//@ [debug_assertions_]compile-flags: --cfg debug_assertions
|
//@ [debug_assertions_]compile-flags: --cfg debug_assertions
|
||||||
@ -33,5 +34,6 @@
|
|||||||
//@ [target_thread_local_]compile-flags: --cfg target_thread_local
|
//@ [target_thread_local_]compile-flags: --cfg target_thread_local
|
||||||
//@ [relocation_model_]compile-flags: --cfg relocation_model="a"
|
//@ [relocation_model_]compile-flags: --cfg relocation_model="a"
|
||||||
//@ [fmt_debug_]compile-flags: --cfg fmt_debug="shallow"
|
//@ [fmt_debug_]compile-flags: --cfg fmt_debug="shallow"
|
||||||
|
//@ [emscripten_wasm_eh_]compile-flags: --cfg emscripten_wasm_eh
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
@ -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() {}
|
@ -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…
x
Reference in New Issue
Block a user