Skip to content
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
32 changes: 0 additions & 32 deletions library/stdarch/crates/core_arch/src/wasm32/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,35 +173,3 @@ pub fn f64_nearest(a: f64) -> f64 {
pub fn f64_sqrt(a: f64) -> f64 {
crate::intrinsics::sqrtf64(a)
}

unsafe extern "C-unwind" {
#[link_name = "llvm.wasm.throw"]
fn wasm_throw(tag: i32, ptr: *mut u8) -> !;
}

/// Generates the [`throw`] instruction from the [exception-handling proposal] for WASM.
///
/// This function is unlikely to be stabilized until codegen backends have better support.
///
/// [`throw`]: https://webassembly.github.io/exception-handling/core/syntax/instructions.html#syntax-instr-control
/// [exception-handling proposal]: https://github.com/WebAssembly/exception-handling
// FIXME: wasmtime does not currently support exception-handling, so cannot execute
// a wasm module with the throw instruction in it. once it does, we can
// reenable this attribute.
// #[cfg_attr(test, assert_instr(throw, TAG = 0, ptr = core::ptr::null_mut()))]
#[inline]
#[unstable(feature = "wasm_exception_handling_intrinsics", issue = "122465")]
// FIXME: Since this instruction unwinds, `core` built with `-C panic=unwind`
// cannot be linked with `-C panic=abort` programs. But that's not
// entirely supported anyway, because runtimes without EH support won't
// be able to handle `try` blocks in `-C panic=unwind` crates either.
// We ship `-C panic=abort` `core`, so this doesn't affect users
// directly. Resolving this will likely require patching out both `try`
// and `throw` instructions, at which point we can look into whitelisting
// this function in the compiler to allow linking.
// See https://github.com/rust-lang/rust/issues/118168.
#[allow(ffi_unwind_calls)]
pub unsafe fn throw<const TAG: i32>(ptr: *mut u8) -> ! {
static_assert!(TAG == 0); // LLVM only supports tag 0 == C++ right now.
wasm_throw(TAG, ptr)
}
2 changes: 1 addition & 1 deletion library/unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#![cfg_attr(not(target_env = "msvc"), feature(libc))]
#![cfg_attr(
all(target_family = "wasm", any(not(target_os = "emscripten"), emscripten_wasm_eh)),
feature(simd_wasm64, wasm_exception_handling_intrinsics)
feature(link_llvm_intrinsics, simd_wasm64)
)]
#![allow(internal_features)]
#![deny(unsafe_op_in_unsafe_fn)]
Expand Down
40 changes: 29 additions & 11 deletions library/unwind/src/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,40 @@ pub unsafe fn _Unwind_DeleteException(exception: *mut _Unwind_Exception) {
}

pub unsafe fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code {
// The wasm `throw` instruction takes a "tag", which differentiates certain
// types of exceptions from others. LLVM currently just identifies these
// via integers, with 0 corresponding to C++ exceptions and 1 to C setjmp()/longjmp().
// Ideally, we'd be able to choose something unique for Rust, but for now,
// we pretend to be C++ and implement the Itanium exception-handling ABI.
// This implementation is only used for `wasm*-unknown-unknown` targets. Such targets are not
// guaranteed to support exceptions, and they default to `-C panic=abort`. Because an unknown
// instruction is a load-time error on wasm, instead of a runtime error like on traditional
// architectures, we never want to codegen a `throw` instruction unless the user explicitly
// enabled exceptions via `-Z build-std` with `-C panic=unwind`.
cfg_select! {
// panic=abort is default for wasm targets. Because an unknown instruction is a load-time
// error on wasm, instead of a runtime error like on traditional architectures, we never
// want to codegen a `throw` instruction, as that would break users using runtimes that
// don't yet support exceptions. The only time this first branch would be selected is if
// the user explicitly opts in to wasm exceptions, via -Zbuild-std with -Cpanic=unwind.
panic = "unwind" => {
// It's important that this intrinsic is defined here rather than in `core`. Since it
// unwinds, invoking it from Rust code compiled with `-C panic=unwind` immediately
// forces `panic_unwind` as the required panic runtime.
//
// We ship unwinding `core` on Emscripten, so making this intrinsic part of `core` would
// prevent linking precompiled `core` into `-C panic=abort` binaries. Unlike `core`,
// this particular module is never precompiled with `-C panic=unwind` because it's only
// used for bare-metal targets, so an error can only arise if the user both manually
// recompiles `std` with `-C panic=unwind` and manually compiles the binary crate with
// `-C panic=abort`, which we don't care to support.
//
// See https://github.com/rust-lang/rust/issues/148246.
unsafe extern "C-unwind" {
/// LLVM lowers this intrinsic to the `throw` instruction.
#[link_name = "llvm.wasm.throw"]
fn wasm_throw(tag: i32, ptr: *mut u8) -> !;
}

// The wasm `throw` instruction takes a "tag", which differentiates certain types of
// exceptions from others. LLVM currently just identifies these via integers, with 0
// corresponding to C++ exceptions and 1 to C setjmp()/longjmp(). Ideally, we'd be able
// to choose something unique for Rust, but for now, we pretend to be C++ and implement
// the Itanium exception-handling ABI.
// corresponds with llvm::WebAssembly::Tag::CPP_EXCEPTION
// in llvm-project/llvm/include/llvm/CodeGen/WasmEHFuncInfo.h
const CPP_EXCEPTION_TAG: i32 = 0;
core::arch::wasm::throw::<CPP_EXCEPTION_TAG>(exception.cast())
wasm_throw(CPP_EXCEPTION_TAG, exception.cast())
}
_ => {
let _ = exception;
Expand Down
2 changes: 1 addition & 1 deletion tests/codegen-llvm/wasm_exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//@ [WASMEXN] compile-flags: -C panic=unwind -Z emscripten-wasm-eh

#![crate_type = "lib"]
#![feature(core_intrinsics, wasm_exception_handling_intrinsics, link_llvm_intrinsics)]
#![feature(core_intrinsics, link_llvm_intrinsics)]

extern "C-unwind" {
fn may_panic();
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/wasm/wasm-link-to-panic-abort-issue-148246.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//@ only-wasm32
//@ compile-flags: -C panic=abort
//@ build-pass

// Test that a `-C panic=abort` binary crate can link to a `-C panic=unwind` core.

fn main() {}
Loading