Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d5ba5c1
Mark `PatternTypo` suggestion as maybe incorrect
Jules-Bertholet Oct 3, 2025
fd96a78
Add documentation about unwinding to wasm targets
alexcrichton Oct 3, 2025
e9a45e6
Avoid to suggest pattern match on the similarly named in fn signature
chenyukang Oct 4, 2025
ba42380
Implement non-poisoning `Mutex::with_mut`, `RwLock::with` and `RwLock…
EFanZh Oct 4, 2025
07d41a7
Correctly handle `--no-run` rustdoc test option
GuillaumeGomez Jul 13, 2025
796c4ef
Correctly handle `should_panic` doctest attribute
GuillaumeGomez Jul 7, 2025
11b7070
Add regression test for #143009
GuillaumeGomez Jul 4, 2025
21a4d9d
Update std doctests
GuillaumeGomez Jul 7, 2025
69833f1
Add regression test for #143858
GuillaumeGomez Jul 13, 2025
6e61a1c
Add FIXME comments to use `test::ERROR_EXIT_CODE` once public and fix…
GuillaumeGomez Aug 1, 2025
ef56675
Use libtest `ERROR_EXIT_CODE` constant
GuillaumeGomez Oct 4, 2025
2688f60
Make `fmt::Write` a diagnostic item
ada4a Oct 4, 2025
b5fb01d
Improve the advice given by panic_immediate_abort
saethlin Oct 4, 2025
757d98c
Move `DirectiveLine` into its own submodule
Zalathar Oct 3, 2025
6783e94
Allow easy extraction of name/value from a `DirectiveLine`
Zalathar Oct 2, 2025
33c99a0
Use new `DirectiveLine` features in directive parsing
Zalathar Oct 2, 2025
b7f4cbe
Rollup merge of #143900 - GuillaumeGomez:fix-no-run, r=lolbinarycat,f…
Zalathar Oct 5, 2025
dcc326d
Rollup merge of #147288 - Zalathar:directive, r=jieyouxu
Zalathar Oct 5, 2025
a90b054
Rollup merge of #147309 - alexcrichton:wasm-unwinding-docs, r=jieyouxu
Zalathar Oct 5, 2025
c64c7bf
Rollup merge of #147310 - Jules-Bertholet:maybe-incorrect-pattern-typ…
Zalathar Oct 5, 2025
9259b14
Rollup merge of #147320 - chenyukang:yukang-fix-147303-fn-arg, r=jiey…
Zalathar Oct 5, 2025
f089268
Rollup merge of #147328 - EFanZh:lock-with, r=joboet
Zalathar Oct 5, 2025
d7273e1
Rollup merge of #147337 - ada4a:write-diag-item, r=fmease
Zalathar Oct 5, 2025
91d7ff9
Rollup merge of #147349 - saethlin:panic-immediate-advice, r=Noratrieb
Zalathar Oct 5, 2025
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
2 changes: 1 addition & 1 deletion compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1365,7 +1365,7 @@ pub(crate) struct UnusedVarAssignedOnly {
#[multipart_suggestion(
passes_unused_var_typo,
style = "verbose",
applicability = "machine-applicable"
applicability = "maybe-incorrect"
)]
pub(crate) struct PatternTypo {
#[suggestion_part(code = "{code}")]
Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_passes/src/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,10 @@ impl<'tcx> Liveness<'_, 'tcx> {
if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) };

let mut typo = None;
for (hir_id, _, span) in &hir_ids_and_spans {
let filtered_hir_ids_and_spans = hir_ids_and_spans.iter().filter(|(hir_id, ..)| {
!matches!(self.ir.tcx.parent_hir_node(*hir_id), hir::Node::Param(_))
});
for (hir_id, _, span) in filtered_hir_ids_and_spans.clone() {
let ty = self.typeck_results.node_type(*hir_id);
if let ty::Adt(adt, _) = ty.peel_refs().kind() {
let name = Symbol::intern(&name);
Expand All @@ -1717,7 +1720,7 @@ impl<'tcx> Liveness<'_, 'tcx> {
}
}
if typo.is_none() {
for (hir_id, _, span) in &hir_ids_and_spans {
for (hir_id, _, span) in filtered_hir_ids_and_spans {
let ty = self.typeck_results.node_type(*hir_id);
// Look for consts of the same type with similar names as well, not just unit
// structs and variants.
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ symbols! {
File,
FileType,
FmtArgumentsNew,
FmtWrite,
Fn,
FnMut,
FnOnce,
Expand Down
1 change: 1 addition & 0 deletions library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ pub struct Error;
/// [`std::io::Write`]: ../../std/io/trait.Write.html
/// [flushable]: ../../std/io/trait.Write.html#tymethod.flush
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "FmtWrite"]
pub trait Write {
/// Writes a string slice into this writer, returning whether the write
/// succeeded.
Expand Down
3 changes: 2 additions & 1 deletion library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ use crate::panic::{Location, PanicInfo};
#[cfg(feature = "panic_immediate_abort")]
compile_error!(
"panic_immediate_abort is now a real panic strategy! \
Enable it with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`"
Enable it with `panic = \"immediate-abort\"` in Cargo.toml, \
or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`"
);

// First we define the two main entry points that all panics go through.
Expand Down
16 changes: 12 additions & 4 deletions library/std/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ use crate::fmt::{self, Write};
/// the `Debug` output means `Report` is an ideal starting place for formatting errors returned
/// from `main`.
///
/// ```should_panic
/// ```
/// #![feature(error_reporter)]
/// use std::error::Report;
/// # use std::error::Error;
Expand Down Expand Up @@ -154,10 +154,14 @@ use crate::fmt::{self, Write};
/// # Err(SuperError { source: SuperErrorSideKick })
/// # }
///
/// fn main() -> Result<(), Report<SuperError>> {
/// fn run() -> Result<(), Report<SuperError>> {
/// get_super_error()?;
/// Ok(())
/// }
///
/// fn main() {
/// assert!(run().is_err());
/// }
/// ```
///
/// This example produces the following output:
Expand All @@ -170,7 +174,7 @@ use crate::fmt::{self, Write};
/// output format. If you want to make sure your `Report`s are pretty printed and include backtrace
/// you will need to manually convert and enable those flags.
///
/// ```should_panic
/// ```
/// #![feature(error_reporter)]
/// use std::error::Report;
/// # use std::error::Error;
Expand Down Expand Up @@ -201,12 +205,16 @@ use crate::fmt::{self, Write};
/// # Err(SuperError { source: SuperErrorSideKick })
/// # }
///
/// fn main() -> Result<(), Report<SuperError>> {
/// fn run() -> Result<(), Report<SuperError>> {
/// get_super_error()
/// .map_err(Report::from)
/// .map_err(|r| r.pretty(true).show_backtrace(true))?;
/// Ok(())
/// }
///
/// fn main() {
/// assert!(run().is_err());
/// }
/// ```
///
/// This example produces the following output:
Expand Down
34 changes: 34 additions & 0 deletions library/std/src/sync/nonpoison/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,40 @@ impl<T: ?Sized> Mutex<T> {
pub const fn data_ptr(&self) -> *mut T {
self.data.get()
}

/// Acquires the mutex and provides mutable access to the underlying data by passing
/// a mutable reference to the given closure.
///
/// This method acquires the lock, calls the provided closure with a mutable reference
/// to the data, and returns the result of the closure. The lock is released after
/// the closure completes, even if it panics.
///
/// # Examples
///
/// ```
/// #![feature(lock_value_accessors, nonpoison_mutex)]
///
/// use std::sync::nonpoison::Mutex;
///
/// let mutex = Mutex::new(2);
///
/// let result = mutex.with_mut(|data| {
/// *data += 3;
///
/// *data + 5
/// });
///
/// assert_eq!(*mutex.lock(), 5);
/// assert_eq!(result, 10);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
// #[unstable(feature = "nonpoison_mutex", issue = "134645")]
pub fn with_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
f(&mut self.lock())
}
}

#[unstable(feature = "nonpoison_mutex", issue = "134645")]
Expand Down
62 changes: 62 additions & 0 deletions library/std/src/sync/nonpoison/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,68 @@ impl<T: ?Sized> RwLock<T> {
pub const fn data_ptr(&self) -> *mut T {
self.data.get()
}

/// Locks this `RwLock` with shared read access to the underlying data by passing
/// a reference to the given closure.
///
/// This method acquires the lock, calls the provided closure with a reference
/// to the data, and returns the result of the closure. The lock is released after
/// the closure completes, even if it panics.
///
/// # Examples
///
/// ```
/// #![feature(lock_value_accessors, nonpoison_rwlock)]
///
/// use std::sync::nonpoison::RwLock;
///
/// let rwlock = RwLock::new(2);
/// let result = rwlock.with(|data| *data + 3);
///
/// assert_eq!(result, 5);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
// #[unstable(feature = "nonpoison_rwlock", issue = "134645")]
pub fn with<F, R>(&self, f: F) -> R
where
F: FnOnce(&T) -> R,
{
f(&self.read())
}

/// Locks this `RwLock` with exclusive write access to the underlying data by passing
/// a mutable reference to the given closure.
///
/// This method acquires the lock, calls the provided closure with a mutable reference
/// to the data, and returns the result of the closure. The lock is released after
/// the closure completes, even if it panics.
///
/// # Examples
///
/// ```
/// #![feature(lock_value_accessors, nonpoison_rwlock)]
///
/// use std::sync::nonpoison::RwLock;
///
/// let rwlock = RwLock::new(2);
///
/// let result = rwlock.with_mut(|data| {
/// *data += 3;
///
/// *data + 5
/// });
///
/// assert_eq!(*rwlock.read(), 5);
/// assert_eq!(result, 10);
/// ```
#[unstable(feature = "lock_value_accessors", issue = "133407")]
// #[unstable(feature = "nonpoison_rwlock", issue = "134645")]
pub fn with_mut<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut T) -> R,
{
f(&mut self.write())
}
}

#[unstable(feature = "nonpoison_rwlock", issue = "134645")]
Expand Down
14 changes: 14 additions & 0 deletions library/std/tests/sync/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,3 +549,17 @@ fn panic_while_mapping_unlocked_poison() {

drop(lock);
}

#[test]
fn test_mutex_with_mut() {
let mutex = std::sync::nonpoison::Mutex::new(2);

let result = mutex.with_mut(|value| {
*value += 3;

*value + 5
});

assert_eq!(*mutex.lock(), 5);
assert_eq!(result, 10);
}
22 changes: 22 additions & 0 deletions library/std/tests/sync/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -861,3 +861,25 @@ fn panic_while_mapping_write_unlocked_poison() {

drop(lock);
}

#[test]
fn test_rwlock_with() {
let rwlock = std::sync::nonpoison::RwLock::new(2);
let result = rwlock.with(|value| *value + 3);

assert_eq!(result, 5);
}

#[test]
fn test_rwlock_with_mut() {
let rwlock = std::sync::nonpoison::RwLock::new(2);

let result = rwlock.with_mut(|value| {
*value += 3;

*value + 5
});

assert_eq!(*rwlock.read(), 5);
assert_eq!(result, 10);
}
62 changes: 61 additions & 1 deletion src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ $ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unkno
```

Here the `mvp` "cpu" is a placeholder in LLVM for disabling all supported
features by default. Cargo's `-Zbuild-std` feature, a Nightly Rust feature, is
features by default. Cargo's [`-Zbuild-std`] feature, a Nightly Rust feature, is
then used to recompile the standard library in addition to your own code. This
will produce a binary that uses only the original WebAssembly features by
default and no proposals since its inception.
Expand Down Expand Up @@ -207,3 +207,63 @@ conditionally compile code instead. This is notably different to the way native
platforms such as x86\_64 work, and this is due to the fact that WebAssembly
binaries must only contain code the engine understands. Native binaries work so
long as the CPU doesn't execute unknown code dynamically at runtime.

## Unwinding

By default the `wasm32-unknown-unknown` target is compiled with `-Cpanic=abort`.
Historically this was due to the fact that there was no way to catch panics in
wasm, but since mid-2025 the WebAssembly [`exception-handling`
proposal](https://github.com/WebAssembly/exception-handling) reached
stabilization. LLVM has support for this proposal as well and when this is all
combined together it's possible to enable `-Cpanic=unwind` on wasm targets.

Compiling wasm targets with `-Cpanic=unwind` is not as easy as just passing
`-Cpanic=unwind`, however:

```sh
$ rustc foo.rs -Cpanic=unwind --target wasm32-unknown-unknown
error: the crate `panic_unwind` does not have the panic strategy `unwind`
```

Notably the precompiled standard library that is shipped through Rustup is
compiled with `-Cpanic=abort`, not `-Cpanic=unwind`. While this is the case
you're going to be required to use Cargo's [`-Zbuild-std`] feature to build with
unwinding support:

```sh
$ RUSTFLAGS='-Cpanic=unwind' cargo +nightly build --target wasm32-unknown-unknown -Zbuild-std
```

Note, however, that as of 2025-10-03 LLVM is still using the "legacy exception
instructions" by default, not the officially standard version of the
exception-handling proposal:

```sh
$ wasm-tools validate target/wasm32-unknown-unknown/debug/foo.wasm
error: <sysroot>/library/std/src/sys/backtrace.rs:161:5
function `std::sys::backtrace::__rust_begin_short_backtrace` failed to validate

Caused by:
0: func 2 failed to validate
1: legacy_exceptions feature required for try instruction (at offset 0x880)
```

Fixing this requires passing `-Cllvm-args=-wasm-use-legacy-eh=false` to the Rust
compiler as well:

```sh
$ RUSTFLAGS='-Cpanic=unwind -Cllvm-args=-wasm-use-legacy-eh=false' cargo +nightly build --target wasm32-unknown-unknown -Zbuild-std
$ wasm-tools validate target/wasm32-unknown-unknown/debug/foo.wasm
```

At this time there are no concrete plans for adding new targets to the Rust
compiler which have `-Cpanic=unwind` enabled-by-default. The most likely route
to having this enabled is that in a few years when the `exception-handling`
target feature is enabled by default in LLVM (due to browsers/runtime support
propagating widely enough) the targets will switch to using `-Cpanic=unwind` by
default. This is not for certain, however, and will likely be accompanied with
either an MCP or an RFC about changing all wasm targets in the same manner. In
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
6 changes: 6 additions & 0 deletions src/doc/rustc/src/platform-support/wasm32-wasip1.md
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,9 @@ to Rust 1.80 the `target_env` condition was not set.
The default set of WebAssembly features enabled for compilation is currently the
same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the
documentation there for more information.

## Unwinding

This target is compiled with `-Cpanic=abort` by default. For information on
using `-Cpanic=unwind` see the [documentation about unwinding for
`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md#unwinding).
6 changes: 6 additions & 0 deletions src/doc/rustc/src/platform-support/wasm32-wasip2.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,9 @@ It's recommended to conditionally compile code for this target with:
The default set of WebAssembly features enabled for compilation is currently the
same as [`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md). See the
documentation there for more information.

## Unwinding

This target is compiled with `-Cpanic=abort` by default. For information on
using `-Cpanic=unwind` see the [documentation about unwinding for
`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md#unwinding).
11 changes: 11 additions & 0 deletions src/doc/rustc/src/platform-support/wasm32v1-none.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,14 @@ $ cargo +nightly build -Zbuild-std=panic_abort,std --target wasm32-unknown-unkno
Which not only rebuilds `std`, `core` and `alloc` (which is somewhat costly and annoying) but more importantly requires the use of nightly Rust toolchains (for the `-Zbuild-std` flag). This is very undesirable for the target audience, which consists of people targeting WebAssembly implementations that prioritize stability, simplicity and/or security over feature support.

This `wasm32v1-none` target exists as an alternative option that works on stable Rust toolchains, without rebuilding the stdlib.

## Unwinding

This target is compiled with `-Cpanic=abort` by default. Using `-Cpanic=unwind`
would require using the WebAssembly exception-handling proposal stabilized
mid-2025, and if that's desired then you most likely don't want to use this
target and instead want to use `wasm32-unknown-unknown` instead. It's unlikely
that this target will ever support unwinding with the precompiled artifacts
shipped through rustup. For documentation about using `-Zbuild-std` to enable
using `-Cpanic=unwind` see the [documentation of
`wasm32-unknown-unknown`](./wasm32-unknown-unknown.md#unwinding).
6 changes: 3 additions & 3 deletions src/librustdoc/doctest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ pub(crate) fn run_tests(
);

for (doctest, scraped_test) in &doctests {
tests_runner.add_test(doctest, scraped_test, &target_str);
tests_runner.add_test(doctest, scraped_test, &target_str, rustdoc_options);
}
let (duration, ret) = tests_runner.run_merged_tests(
rustdoc_test_options,
Expand Down Expand Up @@ -838,7 +838,7 @@ fn run_test(
match result {
Err(e) => return (duration, Err(TestFailure::ExecutionError(e))),
Ok(out) => {
if langstr.should_panic && out.status.success() {
if langstr.should_panic && out.status.code() != Some(test::ERROR_EXIT_CODE) {
return (duration, Err(TestFailure::UnexpectedRunPass));
} else if !langstr.should_panic && !out.status.success() {
return (duration, Err(TestFailure::ExecutionFailure(out)));
Expand Down Expand Up @@ -1148,7 +1148,7 @@ fn doctest_run_fn(
eprint!("Test compiled successfully, but it's marked `compile_fail`.");
}
TestFailure::UnexpectedRunPass => {
eprint!("Test executable succeeded, but it's marked `should_panic`.");
eprint!("Test didn't panic, but it's marked `should_panic`.");
}
TestFailure::MissingErrorCodes(codes) => {
eprint!("Some expected error codes were not found: {codes:?}");
Expand Down
Loading
Loading