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
8 changes: 8 additions & 0 deletions compiler/rustc_target/src/spec/base/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ pub(crate) fn options() -> TargetOptions {
// representation, so this is disabled.
generate_arange_section: false,

// Differ from LLVM's default to use the legacy exception-handling
// proposal instructions and use the standard exception-handling
// instructions. Note that this is only applicable when unwinding is
// actually turned on, which it's not by default on this target. For
// `-Zbuild-std` builds, however, this affects when rebuilding libstd
// with unwinding.
llvm_args: cvs!["-wasm-use-legacy-eh=false"],
Copy link
Copy Markdown
Member

@bjorn3 bjorn3 May 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't

// Returns `true` if this session's target will use native wasm
// 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 != Os::Emscripten || sess.opts.unstable_opts.emscripten_wasm_eh)
}
already supposed to do this?

Edit: Might be confused with wasm vs js exception handling.

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe, yeah, that's related to the Emscripten-specific scheme of exceptions pre-wasm-exceptions of using JS instead. Effectively there's 3 modes of exceptions on Wasm:

  1. Historical JS-based support for Emscripten. That's used when wants_wasm_eh is false and is only applicable to historical versions of the Emscripten target (or -Zemscripten-wasm-eh=false)
  2. Historical wasm support. This uses the now-legacy exception-handling proposal that shipped in browsers but was never standardized. This uses wasm instructions and has wants_wasm_eh is true. LLVM by default emits this today.
  3. Modern wasm support. This uses the now-standard exception-handling proposal as the successor to the "legacy exceptions" of above. This is wants_wasm_eh is true plus an option to LLVM to use the new instructions.

For (1) the LLVM IR is different, and for (2) and (3) they're the same IR. I don't know much about (1) myself. For WASI this PR only exposes (3)


..Default::default()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ pub(crate) fn target() -> Target {
panic_strategy: PanicStrategy::Unwind,
no_default_libraries: false,
families: cvs!["unix", "wasm"],
// Explicitly override the `base::wasm`'s `llvm_args` back to empty. The
// base is to force using the most standard exception-handling
// instructions, when enabled, but this target is intended to follow
// Emscripten, which is whatever LLVM defaults to.
llvm_args: cvs![],
..base::wasm::options()
};
Target {
Expand Down
1 change: 1 addition & 0 deletions library/unwind/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ cfg_select! {
target_os = "psp",
target_os = "solid_asp3",
all(target_vendor = "fortanix", target_env = "sgx"),
all(target_os = "wasi", panic = "unwind"),
) => {
mod libunwind;
pub use libunwind::*;
Expand Down
9 changes: 8 additions & 1 deletion library/unwind/src/libunwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub const unwinder_private_data_size: usize = 2;
#[cfg(all(target_arch = "wasm32", target_os = "emscripten"))]
pub const unwinder_private_data_size: usize = 20;

#[cfg(all(target_arch = "wasm32", target_os = "linux"))]
#[cfg(all(target_arch = "wasm32", any(target_os = "linux", target_os = "wasi")))]
pub const unwinder_private_data_size: usize = 2;

#[cfg(target_arch = "hexagon")]
Expand Down Expand Up @@ -111,6 +111,13 @@ pub type _Unwind_Exception_Cleanup_Fn =
),
link(name = "unwind", kind = "static", modifiers = "-bundle")
)]
// Explicitly link the `unwind` library on WASI targets.
//
// This is provided in the self-contained sysroot for WASI targets by default.
// Note that Rust defaults to `-Cpanic=abort` on WASI targets meaning that this
// doesn't end up getting used by default, but this does mean that with
// `-Zbuild-std` this'll automatically link it in.
#[cfg_attr(target_os = "wasi", link(name = "unwind"))]
unsafe extern "C-unwind" {
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
}
Comment thread
bjorn3 marked this conversation as resolved.
Expand Down
10 changes: 10 additions & 0 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,16 @@ fn copy_self_contained_objects(
DependencyType::TargetSelfContained,
);
}
if srcdir.join("eh").exists() {
copy_and_stamp(
builder,
&libdir_self_contained,
&srcdir.join("eh"),
"libunwind.a",
&mut target_deps,
DependencyType::TargetSelfContained,
);
}
Comment thread
bjorn3 marked this conversation as resolved.
} else if target.is_windows_gnu() || target.is_windows_gnullvm() {
for obj in ["crt2.o", "dllcrt2.o"].iter() {
let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);
Expand Down
2 changes: 1 addition & 1 deletion src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1500,7 +1500,7 @@ impl Build {
if let Some(path) = finder.maybe_have("wasmtime")
&& let Ok(mut path) = path.into_os_string().into_string()
{
path.push_str(" run -C cache=n --dir .");
path.push_str(" run -Wexceptions -C cache=n --dir .");
Copy link
Copy Markdown
Member

@bjorn3 bjorn3 May 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are no tests added that use exceptions, right?

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost yeah, but there's one test that does extern crate panic_unwind; which pulls in libunwind which pulls in a throw instruction which then needs this to validate

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised that even works without //@ needs-unwind to only run the test for panic=unwind. I thought rustc refused to link a panic runtime that doesn't match the -Cpanic=..., but I guess that check is only done when the panic runtime dependency is injected by rustc, not when it is explicitly done by the user.

// Make sure that tests have access to RUSTC_BOOTSTRAP. This (for example) is
// required for libtest to work on beta/stable channels.
//
Expand Down
4 changes: 2 additions & 2 deletions src/ci/docker/host-x86_64/dist-various-2/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ RUN /tmp/build-fuchsia-toolchain.sh
COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/
RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh

RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-32/wasi-sdk-32.0-x86_64-linux.tar.gz | \
RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-33/wasi-sdk-33.0-x86_64-linux.tar.gz | \
tar -xz
ENV WASI_SDK_PATH=/tmp/wasi-sdk-32.0-x86_64-linux
ENV WASI_SDK_PATH=/tmp/wasi-sdk-33.0-x86_64-linux

COPY scripts/freebsd-toolchain.sh /tmp/
RUN /tmp/freebsd-toolchain.sh i686
Expand Down
4 changes: 2 additions & 2 deletions src/ci/docker/host-x86_64/pr-check-2/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
mingw-w64 \
&& rm -rf /var/lib/apt/lists/*

RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-32/wasi-sdk-32.0-x86_64-linux.tar.gz | \
RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-33/wasi-sdk-33.0-x86_64-linux.tar.gz | \
tar -xz
ENV WASI_SDK_PATH=/wasi-sdk-32.0-x86_64-linux
ENV WASI_SDK_PATH=/wasi-sdk-33.0-x86_64-linux

ENV RUST_CONFIGURE_ARGS="--set rust.validate-mir-opts=3"

Expand Down
8 changes: 4 additions & 4 deletions src/ci/docker/host-x86_64/test-various/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ WORKDIR /
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh

RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-32/wasi-sdk-32.0-x86_64-linux.tar.gz | \
RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-33/wasi-sdk-33.0-x86_64-linux.tar.gz | \
tar -xz
ENV WASI_SDK_PATH=/wasi-sdk-32.0-x86_64-linux
ENV WASI_SDK_PATH=/wasi-sdk-33.0-x86_64-linux

ENV RUST_CONFIGURE_ARGS="--musl-root-x86_64=/usr/local/x86_64-linux-musl \
--set rust.lld"
Expand All @@ -57,9 +57,9 @@ ENV RUST_CONFIGURE_ARGS="--musl-root-x86_64=/usr/local/x86_64-linux-musl \
ENV NO_DEBUG_ASSERTIONS=1
ENV NO_OVERFLOW_CHECKS=1

RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v38.0.4/wasmtime-v38.0.4-x86_64-linux.tar.xz | \
RUN curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v44.0.1/wasmtime-v44.0.1-x86_64-linux.tar.xz | \
tar -xJ
ENV PATH="$PATH:/wasmtime-v38.0.4-x86_64-linux"
ENV PATH="$PATH:/wasmtime-v44.0.1-x86_64-linux"

ENV WASM_WASIP_TARGET=wasm32-wasip1
ENV WASM_WASIP_SCRIPT="python3 /checkout/x.py --stage 2 test --host= --target $WASM_WASIP_TARGET \
Expand Down
16 changes: 8 additions & 8 deletions tests/assembly-llvm/wasm_exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ pub fn test_cleanup() {
}

// CHECK-NOT: call
// CHECK: try
// CHECK: try_table (catch_all_ref 0)
// CHECK: call may_panic
// CHECK: catch_all
// CHECK: rethrow
// CHECK: end_try
// CHECK: end_try_table
// CHECK: call log_number
// CHECK: throw_ref
}

// CHECK-LABEL: test_rtry:
Expand All @@ -57,11 +57,11 @@ pub fn test_rtry() {
}

// CHECK-NOT: call
// CHECK: try
// CHECK: try_table (catch __cpp_exception 0)
// CHECK: call may_panic
// CHECK: catch
// CHECK: end_try_table
// CHECK: call log_number
// CHECK: call log_number
// CHECK-NOT: rethrow
// CHECK: end_try
// CHECK-NOT: throw_ref
// CHECK: end_function
}
Loading