Support `-Cpanic=unwind` on WASI targets
This commit is some minor updates/restructuring in a few locations with the end result being supporting `-Cpanic=unwind` on WASI targets. This continues to be off-by-default insofar as WASI targets default to `-Cpanic=abort`, meaning that actually using anything in this commit requires `-Zbuild-std`. Specifically the changes made here are:
* The self-contained sysroot for WASI targets now contains a copy of `libunwind.a` from wasi-sdk, first shipped with wasi-sdk-33 (also updated here).
* The `unwind` crate here in this repository uses the `libunwind` module instead of the custom bare-metal wasm implementation of exceptions. This means that Rust uses the `_Unwind_*` symbols which allows it to interoperate with C/C++/etc.
* Wasm targets are all updated to pass the LLVM argument `-wasm-use-legacy-eh=false` to differ from LLVM's/clang's default of using the legacy exception handling proposal for WebAssembly. This has no effect by default because `panic=abort` is used on most targets. Emscripten is exempted from this as the Emscripten target is explicitly intended to follow LLVM's/clang's defaults.
* There's a single test in the test suite that links to the `panic_unwind` crate which ended up requiring `-Wexceptions` from Wasmtime, so the test parts were updated and Wasmtime was updated in CI, too.
The net result of all of this is that this should not actually affect any WebAssembly target's default behavior. Optionally, though, WASI programs can be built with exception handling via:
RUSTFLAGS='-Cpanic=unwind' cargo +nightly run -Z build-std --target wasm32-wasip2
Effectively `-Zbuild-std` and `-Cpanic=unwind` is all that's necessary to enable this support on wasm targets.
Finally, this ends up closing rust-lang/rust#154593 as well. The WASI targets are now defined to use `-lunwind` to implement unwinding. This means that the in-tree definition of `__cpp_exception` is no longer of concern and the definition is always sourced externally. If Rust is linked with other C/C++ code using WASI then these idioms are compatible with wasi-sdk, for example, to use that as a linker. The main caveat is that when using an external linker the `-fwasm-exceptions` argument needs to be passed to `clang` for it to be able to find the `libunwind.a` library to link against.
Closesrust-lang/rust#154593
This commit is some minor updates/restructuring in a few locations with
the end result being supporting `-Cpanic=unwind` on WASI targets. This
continues to be off-by-default insofar as WASI targets default to
`-Cpanic=abort`, meaning that actually using anything in this commit
requires `-Zbuild-std`. Specifically the changes made here are:
* The self-contained sysroot for WASI targets now contains a copy of
`libunwind.a` from wasi-sdk, first shipped with wasi-sdk-33 (also
updated here).
* The `unwind` crate here in this repository uses the `libunwind` module
instead of the custom bare-metal wasm implementation of exceptions.
This means that Rust uses the `_Unwind_*` symbols which allows it to
interoperate with C/C++/etc.
* Wasm targets are all updated to pass the LLVM argument
`-wasm-use-legacy-eh=false` to differ from LLVM's/clang's default of
using the legacy exception handling proposal for WebAssembly. This has
no effect by default because `panic=abort` is used on most targets.
Emscripten is exempted from this as the Emscripten target is
explicitly intended to follow LLVM's/clang's defaults.
* There's a single test in the test suite that links to the
`panic_unwind` crate which ended up requiring `-Wexceptions` from
Wasmtime, so the test parts were updated and Wasmtime was updated in
CI, too.
The net result of all of this is that this should not actually affect
any WebAssembly target's default behavior. Optionally, though, WASI
programs can be built with exception handling via:
RUSTFLAGS='-Cpanic=unwind' cargo +nightly run -Z build-std --target wasm32-wasip2
Effectively `-Zbuild-std` and `-Cpanic=unwind` is all that's necessary
to enable this support on wasm targets.
Finally, this ends up closing 154593 as well. The WASI targets are now
defined to use `-lunwind` to implement unwinding. This means that the
in-tree definition of `__cpp_exception` is no longer of concern and the
definition is always sourced externally. If Rust is linked with other
C/C++ code using WASI then these idioms are compatible with wasi-sdk,
for example, to use that as a linker. The main caveat is that when using
an external linker the `-fwasm-exceptions` argument needs to be passed
to `clang` for it to be able to find the `libunwind.a` library to link
against.
Closes 154593
Fix alias path for rustdoc
I ran this command:
```console
x build --stage 1 --skip rustdoc
Building bootstrap
Compiling bootstrap v0.0.0 (/Users/yukang/rust/src/bootstrap)
Finished `dev` profile [unoptimized] target(s) in 1.08s
/Users/yukang/rust/build/aarch64-apple-darwin/ci-llvm/bin/llvm-strip does not exist; skipping copy
Building stage1 compiler artifacts (stage0 -> stage1, aarch64-apple-darwin)
Finished `release` profile [optimized + debuginfo] target(s) in 0.45s
Creating a sysroot for stage1 compiler (use `rustup toolchain link 'name' build/host/stage1`)
Building stage1 library artifacts{alloc, compiler_builtins, core, panic_abort, panic_unwind, proc_macro, rustc-std-workspace-core, std, std_detect, sysroot, test, unwind} (stage1 -> stage1, aarch64-apple-darwin)
Finished `dist` profile [optimized + debuginfo] target(s) in 0.10s
Skipping Set({build::src/tools/rustdoc}) because it is excluded
Building stage1 rustdoc_tool_binary (stage0 -> stage1, aarch64-apple-darwin)
Finished `release` profile [optimized + debuginfo] target(s) in 0.19s
```
expect all `rustdoc` related compiling phase will be exlcuded, but from the log we can see `rustdoc_tool_binary` is still compiled.
`src/tools/rustdoc` and `src/librustdoc` are documented as aliases in path set here:
https://github.com/rust-lang/rust/blob/a25435bcf7cfc9b953d356eda3a51db8da9e3386/src/bootstrap/src/core/builder/mod.rs#L355-L360
we can also see here two paths are treated as alias:
https://github.com/rust-lang/rust/blob/a25435bcf7cfc9b953d356eda3a51db8da9e3386/src/bootstrap/src/core/build_steps/check.rs#L818-L822
but bootstrap registered them as two different sets with `.path(..).path(...)`:
https://github.com/rust-lang/rust/blob/a25435bcf7cfc9b953d356eda3a51db8da9e3386/src/bootstrap/src/core/build_steps/tool.rs#L691-L693
That meant commands like `x build --skip rustdoc`, `--skip src/tools/rustdoc`, or `--skip src/librustdoc` only excluded one side.
linker-messages is warn-by-default again
cc rust-lang/rust#136096
I ended up keeping it a lint and adding an option for lints to ignore `-Dwarnings` (there was already a lint that did that actually, it was just hard-coded in rustc_middle instead of in rustc_lint_defs like I'd expect). This allows people to actually see the warnings without them failing the build in CI.
switch to v0 mangling by default on stable
Following rust-lang/rust#89117, rustc has defaulted to the v0 mangling scheme by default (since Nov 20th 2025). This surfaced two bugs:
- rust-lang/rust#138261 was a small ICE (found via fuzzing) where an implementation-internal namespace was missing for global assembly - this occurs with names instantiated within global assembly (that can happen inside constants)
- rust-lang/rust#134479 only occurs with unstable `generic_const_exprs`
Since there have been three-to-four months for users to find bugs with this mangling scheme on nightly, that the scheme has been waiting many years to be stabilised, and has been used successfully internally at Microsoft, Meta and Google for many years, this patch proposes stabilising the v0 mangling scheme on stable.
This patch does not propose removing the legacy mangling, it will remain usable on nightly as an escape-hatch if there are remaining bugs (though admittedly it would require switching to nightly for those on stable) - it is anticipated that this would be unlikely given current testing undergone by v0. Legacy mangling can be removed in another follow-up.
r? @wesleywiser
This made it very annoying to debug bootstrap itself, because every
`--dry-run` invocation would start out by cloning LLVM, which is almost
never necessary. Instead change a few Steps to properly support dry_run
when no submodule is checked out.
This adds a `--quiet` flag to x.py and bootstrap to suppress some of the
output when compiling Rust. It conflicts with `--verbose`, matching the
behavior of `cargo` which does not allow `--verbose` and `--quiet`.
It works by passing quiet flags down to the underlying cargo, or LLVM
build processes. Note that for LLVM, we only can suppress logs when we
explicitly configure it with ninja. Otherwise we won't know what flag
to pass along to whichever build system cmake decides to use.
This can be helpful with AI workloads in the Rust codebase to help
shrink down the output to reduce token usage, which can help prevent
context pollution and lower costs.
This patch was partially generated with Gemini, but I've reviewed the
changes it made.
Fix manpage version replacement and use verbose version
- Fix a bug where `t!(fs::copy(&page_src, &page_dst))` was called after`fs::write`, silently overwriting the substituted content with the original template (restoring the `<INSERT VERSION HERE>` placeholder verbatim) (Related rust-lang/rust#93685)
- Use `rust_info().version()` instead of the bare version number, so the man page now includes the full version string with commit hash and date
Add a flag to control verbose subprocess output for run-make tests. When using --no-capture on panic=abort test suites like cg_clif, passing test output can flood the terminal. This flag (default true) lets users opt out via --verbose-run-make-subprocess-output=false.
Extract a private print_command_output helper in run-make-support to avoid inlining the output logic in handle_failed_output, ensuring failures always print regardless of the flag.
Currently all downloaded rustc and LLVM components are auto patched on
NixOS, but this is not done for libgccjit.so, so when GCC backend is
enabled on NixOS, the build ICEs with errors like this:
thread 'rustc' (2286205) panicked at compiler/rustc_codegen_gcc/src/lib.rs:191:9:
Cannot load libgccjit.so: libzstd.so.1: cannot open shared object file: No such file or directory
Fix this by auto-patch libgccjit.so, too. `zstd` is added to the dependency
environment.
Signed-off-by: Gary Guo <gary@garyguo.net>
Anything that can change there can also be changed in bootstrap.toml.
We have a separate check to make sure that the local config is
compatable with CI's config.
Example output:
```
$ x b compiler
Building bootstrap
Finished `dev` profile [unoptimized] target(s) in 0.02s
NOTE: detected 3 modifications that could affect a build of rustc
- src/bootstrap/src/core/config/config.rs
- src/bootstrap/src/core/download.rs
- src/build_helper/src/git.rs
skipping rustc download due to `download-rustc = 'if-unchanged'`
Building stage1 compiler artifacts (stage0 -> stage1, aarch64-apple-darwin)
Finished `release` profile [optimized] target(s) in 0.72s
Creating a sysroot for stage1 compiler (use `rustup toolchain link 'name' build/host/stage1`)
Build completed successfully in 0:00:05
```
CI jobs were sometimes hanging because cargo would inherit the jobserver based the MFLAGS
environment variable when it contained file descriptors. However, these FDs were not
valid, since bootstrap.py does not pass them through from make.
This leads cargo's job server to use invalid FDs when setting up the
jobserver.
Bootstrap had a mitigation for this when it came from MAKEFLAGS,
but not when it came from MFLAGS.
Make sure we run the full suite, even when more specific filters are given
Some test suite's filter code took this into account, while others didn't.
Imagine this:
```
x test tests/ui/sometest.rs tests/ui
```
This would run only `tests/ui/sometest.rs` since we filtered out `tests/ui` since it matches the name of the test suite.
The reason `x test tests/ui` on its own works, is that if compiletest gets no filter paths, only a suite, it runs the entire suite.
What I've implemented here is that when you pass the suite path, we effectively ignore specific filters and just run the entire suite since that'll include the more specific paths too. This was the case for a few other suites as well, like rustdocjs, but others actually handle this correctly (like clippy, which my code does edit but for which the behavior doesn't change).
Hope this makes sense!
Fix ambiguous parsing in bootstrap.py
Noticed this while trying to produce rustdoc-json for std and saw JSON output from the bootstrap.py build of bootstrap's Rust code. This is technically a breaking change, but I think the fix should be simple and arguably an improvement in future compatibility if/when the flag set changes.
Rollup of 9 pull requests
Successful merges:
- rust-lang/rust#154357 (uefi: extend comment for TcpStream Send impl)
- rust-lang/rust#154410 (Clean up the API for opening/checking incremental-compilation files )
- rust-lang/rust#154081 (format safety doc of Rc/Arc::from_raw/from_raw_in)
- rust-lang/rust#154110 (Change "error finalizing incremental compilation" text and emit it as a note, not a warning)
- rust-lang/rust#154196 (Make `Ipv6Addr::multicast_scope()` exhaustive)
- rust-lang/rust#154221 (`vec::as_mut_slice()`: use lowercase "isize" in safety comment)
- rust-lang/rust#154234 (Use common Timestamp impl in Hermit (attempt 2))
- rust-lang/rust#154396 (chore(deps): update rust crate tar to v0.4.45)
- rust-lang/rust#154488 (Revert "Unstable book options parser")
bootstrap: `-Zjson-target-spec` for synthetic targets
Fixesrust-lang/rust#154340
Synthetic targets for mir-opt tests build a standard library using a `.json` target, which now requires `-Zjson-target-spec`
r? @jieyouxu