diff options
| author | Jacob Pratt <jacob@jhpratt.dev> | 2025-09-29 21:37:50 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-29 21:37:50 -0400 |
| commit | b310eb91ab6fcf5619112a560f4266f42fe46c66 (patch) | |
| tree | 0f603570f56bc70d18ef50c6bff4e2259ddc4a1f /tests | |
| parent | c3e118b4db2d16aefb24fa9d9a597307a96200af (diff) | |
| parent | 88d7d20122e45f4167e262e6eda03fbf5383fb18 (diff) | |
| download | rust-b310eb91ab6fcf5619112a560f4266f42fe46c66.tar.gz rust-b310eb91ab6fcf5619112a560f4266f42fe46c66.zip | |
Rollup merge of #146457 - alexcrichton:wasm-no-exn-instructions, r=bjorn3
Skip cleanups on unsupported targets This commit is an update to the `AbortUnwindingCalls` MIR pass in the compiler. Specifically a new boolean is added for "can this target possibly unwind" and if that's `false` then terminators are all adjusted to be unreachable/not present. The end result is that this fixes rust-lang/rust#140293 for wasm targets. The motivation for this PR is that currently on WebAssembly targets the usage of the `C-unwind` ABI can lead LLVM to either (a) emit exception-handling instructions or (b) hit a LLVM-ICE-style codegen error. WebAssembly as a base instruction set does not support unwinding at all, and a later proposal to WebAssembly, the exception-handling proposal, was what enabled this. This means that the current intent of WebAssembly targets is that they maintain the baseline of "don't emit exception-handling instructions unless enabled". The commit here is intended to restore this behavior by skipping these instructions even when `C-unwind` is present. Exception-handling is a relatively tricky and also murky topic in WebAssembly, however. There are two sets of instructions LLVM can emit for WebAssembly exceptions, Rust's Emscripten target supports exceptions, WASI targets do not, the LLVM flags to enable this are not always obvious, and additionally this all touches on "changing exception-handling behavior should be a target-level concern, not a feature". Effectively WebAssembly's exception-handling integration into Rust is not finalized at this time. The best idea at this time is that a parallel set of targets will eventually be added which support exceptions, but it's not clear if/when to do this. In the meantime the goal is to keep existing targets working while still enabling experimentation with exception-handling with `-Zbuild-std` and various permutations of LLVM flags. To that extent this commit does not blanket disable these landing pads and cleanup routines for WebAssembly but instead checks to see if panic=unwind is enabled or if `+exception-handling` is enabled. Tests are updated here as well to account for this where, by default, using a `C-unwind` ABI won't affect Rust codegen at all. If `+exception-handling` is enabled, however, then Rust codegen will look like native platforms where exceptions are caught and the program aborts. More-or-less I've done my best to keep exceptions working on wasm where it's possible to have them work, but turned them off where they're not supposed to be emitted. Closes rust-lang/rust#140293
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs | 9 | ||||
| -rw-r--r-- | tests/codegen-llvm/unwind-and-panic-abort.rs | 9 | ||||
| -rw-r--r-- | tests/codegen-llvm/wasm_exceptions.rs | 57 |
3 files changed, 56 insertions, 19 deletions
diff --git a/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs index 8d2745ba2f7..2ce1d1b2e00 100644 --- a/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs +++ b/tests/codegen-llvm/unwind-abis/c-unwind-abi-panic-abort.rs @@ -1,4 +1,9 @@ //@ compile-flags: -C panic=abort +//@ revisions: NONWASM WASM WASMEXN +//@ [NONWASM] ignore-wasm32 +//@ [WASM] only-wasm32 +//@ [WASMEXN] only-wasm32 +//@ [WASMEXN] compile-flags: -Ctarget-feature=+exception-handling // Test that `nounwind` attributes are also applied to extern `C-unwind` Rust functions // when the code is compiled with `panic=abort`. @@ -9,7 +14,9 @@ #[no_mangle] pub unsafe extern "C-unwind" fn rust_item_that_can_unwind() { // Handle both legacy and v0 symbol mangling. - // CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} + // NONWASM: call void @{{.*core9panicking19panic_cannot_unwind}} + // WASMEXN: call void @{{.*core9panicking19panic_cannot_unwind}} + // WASM-NOT: call void @{{.*core9panicking19panic_cannot_unwind}} may_unwind(); } diff --git a/tests/codegen-llvm/unwind-and-panic-abort.rs b/tests/codegen-llvm/unwind-and-panic-abort.rs index 8efa140058a..c2838be00af 100644 --- a/tests/codegen-llvm/unwind-and-panic-abort.rs +++ b/tests/codegen-llvm/unwind-and-panic-abort.rs @@ -1,4 +1,9 @@ //@ compile-flags: -C panic=abort +//@ revisions: NONWASM WASM WASMEXN +//@ [NONWASM] ignore-wasm32 +//@ [WASM] only-wasm32 +//@ [WASMEXN] only-wasm32 +//@ [WASMEXN] compile-flags: -Ctarget-feature=+exception-handling #![crate_type = "lib"] @@ -9,7 +14,9 @@ extern "C-unwind" { // CHECK: Function Attrs:{{.*}}nounwind // CHECK-NEXT: define{{.*}}void @foo // Handle both legacy and v0 symbol mangling. -// CHECK: call void @{{.*core9panicking19panic_cannot_unwind}} +// NONWASM: call void @{{.*core9panicking19panic_cannot_unwind}} +// WASMEXN: call void @{{.*core9panicking19panic_cannot_unwind}} +// WASM-NOT: call void @{{.*core9panicking19panic_cannot_unwind}} #[no_mangle] pub unsafe extern "C" fn foo() { bar(); diff --git a/tests/codegen-llvm/wasm_exceptions.rs b/tests/codegen-llvm/wasm_exceptions.rs index 796b69b722b..e718f599a3c 100644 --- a/tests/codegen-llvm/wasm_exceptions.rs +++ b/tests/codegen-llvm/wasm_exceptions.rs @@ -1,8 +1,9 @@ //@ only-wasm32 -//@ compile-flags: -C panic=unwind -Z emscripten-wasm-eh +//@ revisions: WASM WASMEXN +//@ [WASMEXN] compile-flags: -C panic=unwind -Z emscripten-wasm-eh #![crate_type = "lib"] -#![feature(core_intrinsics, wasm_exception_handling_intrinsics)] +#![feature(core_intrinsics, wasm_exception_handling_intrinsics, link_llvm_intrinsics)] extern "C-unwind" { fn may_panic(); @@ -22,7 +23,8 @@ impl Drop for LogOnDrop { } } -// CHECK-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 +// WASM-LABEL: @test_cleanup() {{.*}} +// WASMEXN-LABEL: @test_cleanup() {{.*}} @__gxx_wasm_personality_v0 #[no_mangle] pub fn test_cleanup() { let _log_on_drop = LogOnDrop; @@ -30,12 +32,16 @@ pub fn test_cleanup() { may_panic(); } - // CHECK-NOT: call - // CHECK: invoke void @may_panic() - // CHECK: %cleanuppad = cleanuppad within none [] + // WASMEXN-NOT: call + // WASMEXN: invoke void @may_panic() + // WASMEXN: %cleanuppad = cleanuppad within none [] + // + // WASM: call void @may_panic() + // WASM-NOT: invoke void @may_panic() } -// CHECK-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 +// WASM-LABEL: @test_rtry() {{.*}} +// WASMEXN-LABEL: @test_rtry() {{.*}} @__gxx_wasm_personality_v0 #[no_mangle] pub fn test_rtry() { unsafe { @@ -51,23 +57,40 @@ pub fn test_rtry() { ); } - // CHECK-NOT: call - // CHECK: invoke void @may_panic() - // CHECK: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller - // CHECK: {{.*}} = catchpad within {{.*}} [ptr null] - // CHECK: catchret + // WASMEXN-NOT: call + // WASMEXN: invoke void @may_panic() + // WASMEXN: {{.*}} = catchswitch within none [label {{.*}}] unwind to caller + // WASMEXN: {{.*}} = catchpad within {{.*}} [ptr null] + // WASMEXN: catchret + + // WASM: call void @may_panic() + // WASM-NOT: invoke void @may_panic() + // WASM-NOT: catchswitch + // WASM-NOT: catchpad + // WASM-NOT: catchret } // Make sure the intrinsic is not inferred as nounwind. This is a regression test for #132416. -// CHECK-LABEL: @test_intrinsic() {{.*}} @__gxx_wasm_personality_v0 +// +// Note that this test uses the raw `wasm_throw` intrinsic because the one from +// libstd was built with `-Cpanic=abort` and it's technically not valid to use +// when this crate is compiled with `-Cpanic=unwind`. +// +// WASMEXN-LABEL: @test_intrinsic() {{.*}} @__gxx_wasm_personality_v0 #[no_mangle] +#[cfg(wasmexn)] pub fn test_intrinsic() { let _log_on_drop = LogOnDrop; + + unsafe extern "C-unwind" { + #[link_name = "llvm.wasm.throw"] + fn wasm_throw(tag: i32, ptr: *mut u8) -> !; + } unsafe { - core::arch::wasm32::throw::<0>(core::ptr::null_mut()); + wasm_throw(0, core::ptr::null_mut()); } - // CHECK-NOT: call - // CHECK: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null) - // CHECK: %cleanuppad = cleanuppad within none [] + // WASMEXN-NOT: call + // WASMEXN: invoke void @llvm.wasm.throw(i32 noundef 0, ptr noundef null) + // WASMEXN: %cleanuppad = cleanuppad within none [] } |
