diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index cff2aa7b08b93..0e3e8b1361d03 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -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(link_llvm_intrinsics, simd_wasm64) + feature(link_llvm_intrinsics, simd_wasm64, asm_experimental_arch) )] #![allow(internal_features)] #![deny(unsafe_op_in_unsafe_fn)] diff --git a/library/unwind/src/wasm.rs b/library/unwind/src/wasm.rs index 2bff306af293f..cd2a9c385703d 100644 --- a/library/unwind/src/wasm.rs +++ b/library/unwind/src/wasm.rs @@ -2,6 +2,30 @@ #![allow(nonstandard_style)] +// Define the __cpp_exception tag that LLVM's wasm exception handling requires. +// In particular it is required to use either of: +// 1. the wasm_throw llvm intrinsic, or +// 2. the Rust try intrinsic. +// +// This must be provided since LLVM commit +// aee99e8015daa9f53ab1fd4e5b24cc4c694bdc4a which changed the tag from being +// weakly defined in each object file to being an external reference that must +// be linked from somewhere. +// +// We only define this for wasm32-unknown-unknown because on Emscripten/WASI +// targets, this symbol should be defined by the external toolchain. In +// particular, defining this on Emscripten would break Emscripten dynamic +// libraries. +#[cfg(all(target_os = "unknown", panic = "unwind"))] +core::arch::global_asm!( + ".globl __cpp_exception", + #[cfg(target_pointer_width = "64")] + ".tagtype __cpp_exception i64", + #[cfg(target_pointer_width = "32")] + ".tagtype __cpp_exception i32", + "__cpp_exception:", +); + #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq)] pub enum _Unwind_Reason_Code { diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md index ec20672f65403..3dc608e704308 100644 --- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md +++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md @@ -267,3 +267,18 @@ the meantime using `-Cpanic=unwind` will require using [`-Zbuild-std`] and passing the appropriate flags to rustc. [`-Zbuild-std`]: ../../cargo/reference/unstable.html#build-std + +### The exception tag for panics + +Rust panics are currently implemented as a specific class of C++ exceptions. +This is because llvm only supports throwing and catching the C++ exception tag +from `wasm_throw` intrinsic and the lowering for the catchpads emitted by the +Rust try intrinsic. + +In particular, llvm throw and catch blocks expect a `WebAssembly.Tag` symbol +called `__cpp_exception`. If it is not defined somewhere, llvm will generate an +Emscripten style import from `env.__cpp_exception`. We don't want this, so we +define the symbol in `libunwind` but only for wasm32-unknown-unknown. WASI +doesn't currently support unwinding at all, and the Emscripten linker provides +the tag in an appropriate manner depending on what sort of binary is being +linked.