From 07d41a7cd7f3ef8ca1e9b70768975695d3536272 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 13 Jul 2025 20:38:12 +0200 Subject: [PATCH 01/16] Correctly handle `--no-run` rustdoc test option --- src/librustdoc/doctest.rs | 2 +- src/librustdoc/doctest/runner.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 9499258f983a1..a1e917df75ab9 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -358,7 +358,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, diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index fcfa424968e48..5493d56456872 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -39,6 +39,7 @@ impl DocTestRunner { doctest: &DocTestBuilder, scraped_test: &ScrapedDocTest, target_str: &str, + opts: &RustdocOptions, ) { let ignore = match scraped_test.langstr.ignore { Ignore::All => true, @@ -62,6 +63,7 @@ impl DocTestRunner { self.nb_tests, &mut self.output, &mut self.output_merged_tests, + opts, ), )); self.supports_color &= doctest.supports_color; @@ -223,6 +225,7 @@ fn generate_mergeable_doctest( id: usize, output: &mut String, output_merged_tests: &mut String, + opts: &RustdocOptions, ) -> String { let test_id = format!("__doctest_{id}"); @@ -256,7 +259,7 @@ fn main() {returns_result} {{ ) .unwrap(); } - let not_running = ignore || scraped_test.langstr.no_run; + let not_running = ignore || scraped_test.no_run(opts); writeln!( output_merged_tests, " @@ -270,7 +273,7 @@ test::StaticTestFn( test_name = scraped_test.name, file = scraped_test.path(), line = scraped_test.line, - no_run = scraped_test.langstr.no_run, + no_run = scraped_test.no_run(opts), should_panic = !scraped_test.langstr.no_run && scraped_test.langstr.should_panic, // Setting `no_run` to `true` in `TestDesc` still makes the test run, so we simply // don't give it the function to run. From 796c4efe44a57ddbaf071937e26f1279e8595302 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Jul 2025 11:53:18 +0200 Subject: [PATCH 02/16] Correctly handle `should_panic` doctest attribute --- src/librustdoc/doctest.rs | 4 ++-- src/librustdoc/doctest/runner.rs | 17 ++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index a1e917df75ab9..df457536b70e8 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -836,7 +836,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(101) { return (duration, Err(TestFailure::UnexpectedRunPass)); } else if !langstr.should_panic && !out.status.success() { return (duration, Err(TestFailure::ExecutionFailure(out))); @@ -1146,7 +1146,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:?}"); diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 5493d56456872..d02b32faa319e 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -136,13 +136,20 @@ mod __doctest_mod {{ }} #[allow(unused)] - pub fn doctest_runner(bin: &std::path::Path, test_nb: usize) -> ExitCode {{ + pub fn doctest_runner(bin: &std::path::Path, test_nb: usize, should_panic: bool) -> ExitCode {{ let out = std::process::Command::new(bin) .env(self::RUN_OPTION, test_nb.to_string()) .args(std::env::args().skip(1).collect::>()) .output() .expect(\"failed to run command\"); - if !out.status.success() {{ + if should_panic {{ + if out.status.code() != Some(101) {{ + eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); + ExitCode::FAILURE + }} else {{ + ExitCode::SUCCESS + }} + }} else if !out.status.success() {{ if let Some(code) = out.status.code() {{ eprintln!(\"Test executable failed (exit status: {{code}}).\"); }} else {{ @@ -265,7 +272,7 @@ fn main() {returns_result} {{ " mod {test_id} {{ pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest( -{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, {should_panic}, +{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, false, test::StaticTestFn( || {{{runner}}}, )); @@ -274,7 +281,6 @@ test::StaticTestFn( file = scraped_test.path(), line = scraped_test.line, no_run = scraped_test.no_run(opts), - should_panic = !scraped_test.langstr.no_run && scraped_test.langstr.should_panic, // Setting `no_run` to `true` in `TestDesc` still makes the test run, so we simply // don't give it the function to run. runner = if not_running { @@ -283,11 +289,12 @@ test::StaticTestFn( format!( " if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{ - test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id})) + test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id}, {should_panic})) }} else {{ test::assert_test_result(doctest_bundle::{test_id}::__main_fn()) }} ", + should_panic = scraped_test.langstr.should_panic, ) }, ) From 11b7070577e52c1d26b35021b8a07475e794e93c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 4 Jul 2025 21:42:19 +0200 Subject: [PATCH 03/16] Add regression test for #143009 --- tests/run-make/rustdoc-should-panic/rmake.rs | 36 ++++++++++++++++++++ tests/run-make/rustdoc-should-panic/test.rs | 14 ++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/run-make/rustdoc-should-panic/rmake.rs create mode 100644 tests/run-make/rustdoc-should-panic/test.rs diff --git a/tests/run-make/rustdoc-should-panic/rmake.rs b/tests/run-make/rustdoc-should-panic/rmake.rs new file mode 100644 index 0000000000000..100a62f5db313 --- /dev/null +++ b/tests/run-make/rustdoc-should-panic/rmake.rs @@ -0,0 +1,36 @@ +// Ensure that `should_panic` doctests only succeed if the test actually panicked. +// Regression test for . + +//@ needs-target-std + +use run_make_support::rustdoc; + +fn check_output(output: String, edition: &str) { + let should_contain = &[ + "test test.rs - bad_exit_code (line 1) ... FAILED", + "test test.rs - did_not_panic (line 6) ... FAILED", + "test test.rs - did_panic (line 11) ... ok", + "---- test.rs - bad_exit_code (line 1) stdout ---- +Test executable failed (exit status: 1).", + "---- test.rs - did_not_panic (line 6) stdout ---- +Test didn't panic, but it's marked `should_panic`.", + "test result: FAILED. 1 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out;", + ]; + for text in should_contain { + assert!( + output.contains(text), + "output doesn't contains (edition: {edition}) {:?}\nfull output: {output}", + text + ); + } +} + +fn main() { + check_output(rustdoc().input("test.rs").arg("--test").run_fail().stdout_utf8(), "2015"); + + // Same check with the merged doctest feature (enabled with the 2024 edition). + check_output( + rustdoc().input("test.rs").arg("--test").edition("2024").run_fail().stdout_utf8(), + "2024", + ); +} diff --git a/tests/run-make/rustdoc-should-panic/test.rs b/tests/run-make/rustdoc-should-panic/test.rs new file mode 100644 index 0000000000000..1eea8e1e1958c --- /dev/null +++ b/tests/run-make/rustdoc-should-panic/test.rs @@ -0,0 +1,14 @@ +/// ``` +/// std::process::exit(1); +/// ``` +fn bad_exit_code() {} + +/// ```should_panic +/// std::process::exit(1); +/// ``` +fn did_not_panic() {} + +/// ```should_panic +/// panic!("yeay"); +/// ``` +fn did_panic() {} From 21a4d9dda7b2234d4454c2413956f96d8884cd65 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Jul 2025 13:35:02 +0200 Subject: [PATCH 04/16] Update std doctests --- library/std/src/error.rs | 16 ++++++++++++---- .../failed-doctest-should-panic-2021.stdout | 2 +- .../doctest/failed-doctest-should-panic.stdout | 5 +++-- tests/rustdoc-ui/doctest/wrong-ast-2024.stdout | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/library/std/src/error.rs b/library/std/src/error.rs index def5f984c88e4..09bfc83ebca6c 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -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; @@ -154,10 +154,14 @@ use crate::fmt::{self, Write}; /// # Err(SuperError { source: SuperErrorSideKick }) /// # } /// -/// fn main() -> Result<(), Report> { +/// fn run() -> Result<(), Report> { /// get_super_error()?; /// Ok(()) /// } +/// +/// fn main() { +/// assert!(run().is_err()); +/// } /// ``` /// /// This example produces the following output: @@ -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; @@ -201,12 +205,16 @@ use crate::fmt::{self, Write}; /// # Err(SuperError { source: SuperErrorSideKick }) /// # } /// -/// fn main() -> Result<(), Report> { +/// fn run() -> Result<(), Report> { /// 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: diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout index 9f4d60e6f4de5..f8413756e3d6d 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic-2021.stdout @@ -5,7 +5,7 @@ test $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) ... FAILED failures: ---- $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) stdout ---- -Test executable succeeded, but it's marked `should_panic`. +Test didn't panic, but it's marked `should_panic`. failures: $DIR/failed-doctest-should-panic-2021.rs - Foo (line 10) diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout index 9047fe0dcdd93..61099e6424ae7 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout @@ -1,11 +1,12 @@ running 1 test -test $DIR/failed-doctest-should-panic.rs - Foo (line 12) - should panic ... FAILED +test $DIR/failed-doctest-should-panic.rs - Foo (line 12) ... FAILED failures: ---- $DIR/failed-doctest-should-panic.rs - Foo (line 12) stdout ---- -note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:12:0 +Test didn't panic, but it's marked `should_panic`. + failures: $DIR/failed-doctest-should-panic.rs - Foo (line 12) diff --git a/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout index 13567b41e51f5..27f9a0157a6cc 100644 --- a/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout +++ b/tests/rustdoc-ui/doctest/wrong-ast-2024.stdout @@ -1,6 +1,6 @@ running 1 test -test $DIR/wrong-ast-2024.rs - three (line 20) - should panic ... ok +test $DIR/wrong-ast-2024.rs - three (line 20) ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From 5f2ae4fb078569486b3a285b3bc5378e3bf7c9fb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 13 Jul 2025 20:49:29 +0200 Subject: [PATCH 05/16] Add regression test for #143858 --- tests/run-make/rustdoc-should-panic/rmake.rs | 2 +- .../doctest/no-run.edition2021.stdout | 12 +++++ .../doctest/no-run.edition2024.stdout | 18 ++++++++ tests/rustdoc-ui/doctest/no-run.rs | 44 +++++++++++++++++++ 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 tests/rustdoc-ui/doctest/no-run.edition2021.stdout create mode 100644 tests/rustdoc-ui/doctest/no-run.edition2024.stdout create mode 100644 tests/rustdoc-ui/doctest/no-run.rs diff --git a/tests/run-make/rustdoc-should-panic/rmake.rs b/tests/run-make/rustdoc-should-panic/rmake.rs index 100a62f5db313..ffe3c9ef6eb60 100644 --- a/tests/run-make/rustdoc-should-panic/rmake.rs +++ b/tests/run-make/rustdoc-should-panic/rmake.rs @@ -1,7 +1,7 @@ // Ensure that `should_panic` doctests only succeed if the test actually panicked. // Regression test for . -//@ needs-target-std +//@ ignore-cross-compile use run_make_support::rustdoc; diff --git a/tests/rustdoc-ui/doctest/no-run.edition2021.stdout b/tests/rustdoc-ui/doctest/no-run.edition2021.stdout new file mode 100644 index 0000000000000..937cd76bfb462 --- /dev/null +++ b/tests/rustdoc-ui/doctest/no-run.edition2021.stdout @@ -0,0 +1,12 @@ + +running 7 tests +test $DIR/no-run.rs - f (line 14) - compile ... ok +test $DIR/no-run.rs - f (line 17) - compile ... ok +test $DIR/no-run.rs - f (line 20) ... ignored +test $DIR/no-run.rs - f (line 23) - compile ... ok +test $DIR/no-run.rs - f (line 29) - compile fail ... ok +test $DIR/no-run.rs - f (line 34) - compile ... ok +test $DIR/no-run.rs - f (line 38) - compile ... ok + +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/tests/rustdoc-ui/doctest/no-run.edition2024.stdout b/tests/rustdoc-ui/doctest/no-run.edition2024.stdout new file mode 100644 index 0000000000000..921e059979b1f --- /dev/null +++ b/tests/rustdoc-ui/doctest/no-run.edition2024.stdout @@ -0,0 +1,18 @@ + +running 5 tests +test $DIR/no-run.rs - f (line 14) - compile ... ok +test $DIR/no-run.rs - f (line 17) - compile ... ok +test $DIR/no-run.rs - f (line 23) - compile ... ok +test $DIR/no-run.rs - f (line 34) - compile ... ok +test $DIR/no-run.rs - f (line 38) - compile ... ok + +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + + +running 2 tests +test $DIR/no-run.rs - f (line 20) ... ignored +test $DIR/no-run.rs - f (line 29) - compile fail ... ok + +test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in $TIME + +all doctests ran in $TIME; merged doctests compilation took $TIME diff --git a/tests/rustdoc-ui/doctest/no-run.rs b/tests/rustdoc-ui/doctest/no-run.rs new file mode 100644 index 0000000000000..78198badd43b5 --- /dev/null +++ b/tests/rustdoc-ui/doctest/no-run.rs @@ -0,0 +1,44 @@ +// This test ensures that the `--no-run` flag works the same between normal and merged doctests. +// Regression test for . + +//@ check-pass +//@ revisions: edition2021 edition2024 +//@ [edition2021]edition:2021 +//@ [edition2024]edition:2024 +//@ compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1 +//@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" +//@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" +//@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" + +/// ``` +/// let a = true; +/// ``` +/// ```should_panic +/// panic!() +/// ``` +/// ```ignore (incomplete-code) +/// fn foo() { +/// ``` +/// ```no_run +/// loop { +/// println!("Hello, world"); +/// } +/// ``` +/// fails to compile +/// ```compile_fail +/// let x = 5; +/// x += 2; // shouldn't compile! +/// ``` +/// Ok the test does not run +/// ``` +/// panic!() +/// ``` +/// Ok the test does not run +/// ```should_panic +/// loop { +/// println!("Hello, world"); +/// panic!() +/// } +/// ``` +pub fn f() {} From b001ba67dda247037b052cfa76b154d2df3908ab Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 1 Aug 2025 11:28:17 +0200 Subject: [PATCH 06/16] Add FIXME comments to use `test::ERROR_EXIT_CODE` once public and fix typo --- src/librustdoc/doctest.rs | 1 + src/librustdoc/doctest/runner.rs | 1 + tests/run-make/rustdoc-should-panic/rmake.rs | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index df457536b70e8..51972f8b149c7 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -836,6 +836,7 @@ fn run_test( match result { Err(e) => return (duration, Err(TestFailure::ExecutionError(e))), Ok(out) => { + // FIXME: use test::ERROR_EXIT_CODE once public if langstr.should_panic && out.status.code() != Some(101) { return (duration, Err(TestFailure::UnexpectedRunPass)); } else if !langstr.should_panic && !out.status.success() { diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index d02b32faa319e..d241d44441d53 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -143,6 +143,7 @@ mod __doctest_mod {{ .output() .expect(\"failed to run command\"); if should_panic {{ + // FIXME: use test::ERROR_EXIT_CODE once public if out.status.code() != Some(101) {{ eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); ExitCode::FAILURE diff --git a/tests/run-make/rustdoc-should-panic/rmake.rs b/tests/run-make/rustdoc-should-panic/rmake.rs index ffe3c9ef6eb60..4d6e2c98ae771 100644 --- a/tests/run-make/rustdoc-should-panic/rmake.rs +++ b/tests/run-make/rustdoc-should-panic/rmake.rs @@ -19,7 +19,7 @@ Test didn't panic, but it's marked `should_panic`.", for text in should_contain { assert!( output.contains(text), - "output doesn't contains (edition: {edition}) {:?}\nfull output: {output}", + "output (edition: {edition}) doesn't contain {:?}\nfull output: {output}", text ); } From 030b66441986be7b84d355d5377cb68783b4b564 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 4 Oct 2025 13:39:31 +0200 Subject: [PATCH 07/16] Use libtest `ERROR_EXIT_CODE` constant --- src/librustdoc/doctest.rs | 3 +-- src/librustdoc/doctest/runner.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 51972f8b149c7..0eb698ca544fe 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -836,8 +836,7 @@ fn run_test( match result { Err(e) => return (duration, Err(TestFailure::ExecutionError(e))), Ok(out) => { - // FIXME: use test::ERROR_EXIT_CODE once public - if langstr.should_panic && out.status.code() != Some(101) { + 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))); diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index d241d44441d53..66ffb8aae23e6 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -143,8 +143,7 @@ mod __doctest_mod {{ .output() .expect(\"failed to run command\"); if should_panic {{ - // FIXME: use test::ERROR_EXIT_CODE once public - if out.status.code() != Some(101) {{ + if out.status.code() != Some(test::ERROR_EXIT_CODE) {{ eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); ExitCode::FAILURE }} else {{ From 560d4505591c160f0cfbfcc7653f281e8325cc0b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Oct 2025 20:43:05 +0200 Subject: [PATCH 08/16] Correctly handle `should_panic` on targets not supporting it --- src/librustdoc/doctest.rs | 16 ++++++++++++++++ src/librustdoc/doctest/runner.rs | 11 ++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 0eb698ca544fe..c3db6b712b316 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -803,6 +803,22 @@ fn run_test( let duration = instant.elapsed(); if doctest.no_run { return (duration, Ok(())); + } else if doctest.langstr.should_panic + // Equivalent of: + // + // ``` + // (cfg!(target_family = "wasm") || cfg!(target_os = "zkvm")) + // && !cfg!(target_os = "emscripten") + // ``` + && let TargetTuple::TargetTuple(ref s) = rustdoc_options.target + && let mut iter = s.split('-') + && let Some(arch) = iter.next() + && iter.next().is_some() + && let os = iter.next() + && (arch.starts_with("wasm") || os == Some("zkvm")) && os != Some("emscripten") + { + // We cannot correctly handle `should_panic` in some wasm targets so we exit early. + return (duration, Ok(())); } // Run the code! diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index 66ffb8aae23e6..d7fd586ebac1c 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -129,6 +129,9 @@ mod __doctest_mod {{ pub static BINARY_PATH: OnceLock = OnceLock::new(); pub const RUN_OPTION: &str = \"RUSTDOC_DOCTEST_RUN_NB_TEST\"; + pub const SHOULD_PANIC_DISABLED: bool = ( + cfg!(target_family = \"wasm\") || cfg!(target_os = \"zkvm\") + ) && !cfg!(target_os = \"emscripten\"); #[allow(unused)] pub fn doctest_path() -> Option<&'static PathBuf> {{ @@ -266,13 +269,14 @@ fn main() {returns_result} {{ ) .unwrap(); } + let should_panic = scraped_test.langstr.should_panic; let not_running = ignore || scraped_test.no_run(opts); writeln!( output_merged_tests, " mod {test_id} {{ pub const TEST: test::TestDescAndFn = test::TestDescAndFn::new_doctest( -{test_name:?}, {ignore}, {file:?}, {line}, {no_run}, false, +{test_name:?}, {ignore} || ({should_panic} && crate::__doctest_mod::SHOULD_PANIC_DISABLED), {file:?}, {line}, {no_run}, false, test::StaticTestFn( || {{{runner}}}, )); @@ -288,13 +292,14 @@ test::StaticTestFn( } else { format!( " -if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{ +if {should_panic} && crate::__doctest_mod::SHOULD_PANIC_DISABLED {{ + test::assert_test_result(Ok::<(), String>(())) +}} else if let Some(bin_path) = crate::__doctest_mod::doctest_path() {{ test::assert_test_result(crate::__doctest_mod::doctest_runner(bin_path, {id}, {should_panic})) }} else {{ test::assert_test_result(doctest_bundle::{test_id}::__main_fn()) }} ", - should_panic = scraped_test.langstr.should_panic, ) }, ) From a11fe5d389b08d62b138aedb31ed04e8c08cff91 Mon Sep 17 00:00:00 2001 From: Samuel Tardieu Date: Mon, 6 Oct 2025 23:50:47 +0200 Subject: [PATCH 09/16] Add diagnostic items for `pub mod consts` of FP types They will be used in Clippy. --- compiler/rustc_span/src/symbol.rs | 4 ++++ library/core/src/num/f128.rs | 1 + library/core/src/num/f16.rs | 1 + library/core/src/num/f32.rs | 1 + library/core/src/num/f64.rs | 1 + 5 files changed, 8 insertions(+) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 92dd56f3d5894..29e708ae4e6d4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -980,10 +980,12 @@ symbols! { external_doc, f, f16, + f16_consts_mod, f16_epsilon, f16_nan, f16c_target_feature, f32, + f32_consts_mod, f32_epsilon, f32_legacy_const_digits, f32_legacy_const_epsilon, @@ -1001,6 +1003,7 @@ symbols! { f32_legacy_const_radix, f32_nan, f64, + f64_consts_mod, f64_epsilon, f64_legacy_const_digits, f64_legacy_const_epsilon, @@ -1018,6 +1021,7 @@ symbols! { f64_legacy_const_radix, f64_nan, f128, + f128_consts_mod, f128_epsilon, f128_nan, fabsf16, diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs index 4fe4735e304c9..e7101537b298f 100644 --- a/library/core/src/num/f128.rs +++ b/library/core/src/num/f128.rs @@ -18,6 +18,7 @@ use crate::{intrinsics, mem}; /// Basic mathematical constants. #[unstable(feature = "f128", issue = "116909")] +#[rustc_diagnostic_item = "f128_consts_mod"] pub mod consts { // FIXME: replace with mathematical constants from cmath. diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs index 0bea6bc8801d8..aa8342a22ad58 100644 --- a/library/core/src/num/f16.rs +++ b/library/core/src/num/f16.rs @@ -20,6 +20,7 @@ use crate::{intrinsics, mem}; /// Basic mathematical constants. #[unstable(feature = "f16", issue = "116909")] +#[rustc_diagnostic_item = "f16_consts_mod"] pub mod consts { // FIXME: replace with mathematical constants from cmath. diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index e380cc698f574..3070e1dedbe43 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -277,6 +277,7 @@ pub const NEG_INFINITY: f32 = f32::NEG_INFINITY; /// Basic mathematical constants. #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "f32_consts_mod"] pub mod consts { // FIXME: replace with mathematical constants from cmath. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index ff7449fd996ce..dc8ccc551b2da 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -277,6 +277,7 @@ pub const NEG_INFINITY: f64 = f64::NEG_INFINITY; /// Basic mathematical constants. #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_diagnostic_item = "f64_consts_mod"] pub mod consts { // FIXME: replace with mathematical constants from cmath. From b70e20ab8829a61c9ade751ae4d8295ff56b4789 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 7 Oct 2025 16:27:43 +0200 Subject: [PATCH 10/16] Correctly handle `-C panic=abort` in doctests --- src/librustdoc/doctest.rs | 35 ++++++++++++++++-- src/librustdoc/doctest/runner.rs | 38 ++++++++++++++++---- tests/run-make/rustdoc-should-panic/rmake.rs | 19 ++++++---- 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index c3db6b712b316..28453f990aed2 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -7,6 +7,8 @@ mod rust; use std::fs::File; use std::hash::{Hash, Hasher}; use std::io::{self, Write}; +#[cfg(unix)] +use std::os::unix::process::ExitStatusExt; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -849,12 +851,39 @@ fn run_test( } else { cmd.output() }; + + // FIXME: Make `test::get_result_from_exit_code` public and use this code instead of this. + // + // On Zircon (the Fuchsia kernel), an abort from userspace calls the + // LLVM implementation of __builtin_trap(), e.g., ud2 on x86, which + // raises a kernel exception. If a userspace process does not + // otherwise arrange exception handling, the kernel kills the process + // with this return code. + #[cfg(target_os = "fuchsia")] + const ZX_TASK_RETCODE_EXCEPTION_KILL: i32 = -1028; + // On Windows we use __fastfail to abort, which is documented to use this + // exception code. + #[cfg(windows)] + const STATUS_FAIL_FAST_EXCEPTION: i32 = 0xC0000409u32 as i32; + #[cfg(unix)] + const SIGABRT: std::ffi::c_int = 6; match result { Err(e) => return (duration, Err(TestFailure::ExecutionError(e))), Ok(out) => { - 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() { + if langstr.should_panic { + match out.status.code() { + Some(test::ERROR_EXIT_CODE) => {} + #[cfg(windows)] + Some(STATUS_FAIL_FAST_EXCEPTION) => {} + #[cfg(unix)] + None if out.status.signal() == Some(SIGABRT) => {} + // Upon an abort, Fuchsia returns the status code + // `ZX_TASK_RETCODE_EXCEPTION_KILL`. + #[cfg(target_os = "fuchsia")] + Some(ZX_TASK_RETCODE_EXCEPTION_KILL) => {} + _ => return (duration, Err(TestFailure::UnexpectedRunPass)), + } + } else if !out.status.success() { return (duration, Err(TestFailure::ExecutionFailure(out))); } } diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index d7fd586ebac1c..afcab202a8e3e 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -123,9 +123,11 @@ impl DocTestRunner { {output} mod __doctest_mod {{ - use std::sync::OnceLock; + #[cfg(unix)] + use std::os::unix::process::ExitStatusExt; use std::path::PathBuf; use std::process::ExitCode; + use std::sync::OnceLock; pub static BINARY_PATH: OnceLock = OnceLock::new(); pub const RUN_OPTION: &str = \"RUSTDOC_DOCTEST_RUN_NB_TEST\"; @@ -146,11 +148,35 @@ mod __doctest_mod {{ .output() .expect(\"failed to run command\"); if should_panic {{ - if out.status.code() != Some(test::ERROR_EXIT_CODE) {{ - eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); - ExitCode::FAILURE - }} else {{ - ExitCode::SUCCESS + // FIXME: Make `test::get_result_from_exit_code` public and use this code instead of this. + // + // On Zircon (the Fuchsia kernel), an abort from userspace calls the + // LLVM implementation of __builtin_trap(), e.g., ud2 on x86, which + // raises a kernel exception. If a userspace process does not + // otherwise arrange exception handling, the kernel kills the process + // with this return code. + #[cfg(target_os = \"fuchsia\")] + const ZX_TASK_RETCODE_EXCEPTION_KILL: i32 = -1028; + // On Windows we use __fastfail to abort, which is documented to use this + // exception code. + #[cfg(windows)] + const STATUS_FAIL_FAST_EXCEPTION: i32 = 0xC0000409u32 as i32; + #[cfg(unix)] + const SIGABRT: std::ffi::c_int = 6; + + match out.status.code() {{ + Some(test::ERROR_EXIT_CODE) => ExitCode::SUCCESS, + #[cfg(windows)] + Some(STATUS_FAIL_FAST_EXCEPTION) => ExitCode::SUCCESS, + #[cfg(unix)] + None if out.status.signal() == Some(SIGABRT) => ExitCode::SUCCESS, + // Upon an abort, Fuchsia returns the status code ZX_TASK_RETCODE_EXCEPTION_KILL. + #[cfg(target_os = \"fuchsia\")] + Some(ZX_TASK_RETCODE_EXCEPTION_KILL) => ExitCode::SUCCESS, + _ => {{ + eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); + ExitCode::FAILURE + }} }} }} else if !out.status.success() {{ if let Some(code) = out.status.code() {{ diff --git a/tests/run-make/rustdoc-should-panic/rmake.rs b/tests/run-make/rustdoc-should-panic/rmake.rs index 4d6e2c98ae771..438608ff8b4ed 100644 --- a/tests/run-make/rustdoc-should-panic/rmake.rs +++ b/tests/run-make/rustdoc-should-panic/rmake.rs @@ -5,7 +5,13 @@ use run_make_support::rustdoc; -fn check_output(output: String, edition: &str) { +fn check_output(edition: &str, panic_abort: bool) { + let mut rustdoc_cmd = rustdoc(); + rustdoc_cmd.input("test.rs").arg("--test").edition(edition); + if panic_abort { + rustdoc_cmd.args(["-C", "panic=abort"]); + } + let output = rustdoc_cmd.run_fail().stdout_utf8(); let should_contain = &[ "test test.rs - bad_exit_code (line 1) ... FAILED", "test test.rs - did_not_panic (line 6) ... FAILED", @@ -26,11 +32,12 @@ Test didn't panic, but it's marked `should_panic`.", } fn main() { - check_output(rustdoc().input("test.rs").arg("--test").run_fail().stdout_utf8(), "2015"); + check_output("2015", false); // Same check with the merged doctest feature (enabled with the 2024 edition). - check_output( - rustdoc().input("test.rs").arg("--test").edition("2024").run_fail().stdout_utf8(), - "2024", - ); + check_output("2024", false); + + // Checking that `-C panic=abort` is working too. + check_output("2015", true); + check_output("2024", true); } From ec99e3eca22bf97b1bed90173f0095ffa38bde75 Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 15 Jul 2025 23:24:44 -0700 Subject: [PATCH 11/16] clarify wording of match ergonomics diagnostics --- compiler/rustc_hir_typeck/src/pat.rs | 21 +- compiler/rustc_lint_defs/src/builtin.rs | 2 +- .../rustc_middle/src/ty/typeck_results.rs | 6 +- compiler/rustc_mir_build/messages.ftl | 11 - compiler/rustc_mir_build/src/errors.rs | 66 +-- .../src/thir/pattern/migration.rs | 112 +++-- .../mixed-editions.classic2021.stderr | 10 +- .../mixed-editions.classic2024.stderr | 8 +- .../experimental/mixed-editions.rs | 4 +- .../mixed-editions.structural2021.stderr | 10 +- .../mixed-editions.structural2024.stderr | 8 +- ...nding-on-inh-ref-errors.classic2024.stderr | 48 +- .../ref-binding-on-inh-ref-errors.rs | 22 +- ...ng-on-inh-ref-errors.structural2024.stderr | 132 ++--- .../migration_lint.fixed | 82 ++-- .../migration_lint.rs | 82 ++-- .../migration_lint.stderr | 459 ++++++++++-------- .../min_match_ergonomics_fail.rs | 14 +- .../min_match_ergonomics_fail.stderr | 80 +-- 19 files changed, 629 insertions(+), 548 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 46accb76a184a..d14463e44a03f 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -3115,20 +3115,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // binding mode. This keeps it from making those suggestions, as doing so could panic. let info = table.entry(pat_id).or_insert_with(|| ty::Rust2024IncompatiblePatInfo { primary_labels: Vec::new(), - bad_modifiers: false, + bad_ref_modifiers: false, + bad_mut_modifiers: false, bad_ref_pats: false, suggest_eliding_modes: !self.tcx.features().ref_pat_eat_one_layer_2024() && !self.tcx.features().ref_pat_eat_one_layer_2024_structural(), }); let pat_kind = if let PatKind::Binding(user_bind_annot, _, _, _) = subpat.kind { - info.bad_modifiers = true; // If the user-provided binding modifier doesn't match the default binding mode, we'll // need to suggest reference patterns, which can affect other bindings. // For simplicity, we opt to suggest making the pattern fully explicit. info.suggest_eliding_modes &= user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not); - "binding modifier" + if user_bind_annot == BindingMode(ByRef::No, Mutability::Mut) { + info.bad_mut_modifiers = true; + "`mut` binding modifier" + } else { + info.bad_ref_modifiers = true; + match user_bind_annot.1 { + Mutability::Not => "explicit `ref` binding modifier", + Mutability::Mut => "explicit `ref mut` binding modifier", + } + } } else { info.bad_ref_pats = true; // For simplicity, we don't try to suggest eliding reference patterns. Thus, we'll @@ -3147,11 +3156,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so, we may want to inspect the span's source callee or macro backtrace. "occurs within macro expansion".to_owned() } else { - let dbm_str = match def_br_mutbl { - Mutability::Not => "ref", - Mutability::Mut => "ref mut", - }; - format!("{pat_kind} not allowed under `{dbm_str}` default binding mode") + format!("{pat_kind} not allowed when implicitly borrowing") }; info.primary_labels.push((trimmed_span, primary_label)); } diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 939f3d088b12f..8b7b13a4c3622 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -1601,7 +1601,7 @@ declare_lint! { "detects patterns whose meaning will change in Rust 2024", @future_incompatible = FutureIncompatibleInfo { reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024), - reference: "", + reference: "", }; } diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs index b276b993ec924..d1fb700913d91 100644 --- a/compiler/rustc_middle/src/ty/typeck_results.rs +++ b/compiler/rustc_middle/src/ty/typeck_results.rs @@ -858,8 +858,10 @@ impl<'tcx> std::fmt::Display for UserTypeKind<'tcx> { pub struct Rust2024IncompatiblePatInfo { /// Labeled spans for `&`s, `&mut`s, and binding modifiers incompatible with Rust 2024. pub primary_labels: Vec<(Span, String)>, - /// Whether any binding modifiers occur under a non-`move` default binding mode. - pub bad_modifiers: bool, + /// Whether any `mut` binding modifiers occur under a non-`move` default binding mode. + pub bad_mut_modifiers: bool, + /// Whether any `ref`/`ref mut` binding modifiers occur under a non-`move` default binding mode. + pub bad_ref_modifiers: bool, /// Whether any `&` or `&mut` patterns occur under a non-`move` default binding mode. pub bad_ref_pats: bool, /// If `true`, we can give a simpler suggestion solely by eliding explicit binding modifiers. diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 83fbcb30dd941..e84e42b8a44b5 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -322,17 +322,6 @@ mir_build_pointer_pattern = function pointers and raw pointers not derived from mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future -mir_build_rust_2024_incompatible_pat = {$bad_modifiers -> - *[true] binding modifiers{$bad_ref_pats -> - *[true] {" "}and reference patterns - [false] {""} - } - [false] reference patterns - } may only be written when the default binding mode is `move`{$is_hard_error -> - *[true] {""} - [false] {" "}in Rust 2024 - } - mir_build_static_in_pattern = statics cannot be referenced in patterns .label = can't be used in patterns mir_build_static_in_pattern_def = `static` defined here diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 58c3de4a8b59c..e2aae5b6283f2 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -1,8 +1,7 @@ -use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - MultiSpan, Subdiagnostic, pluralize, + MultiSpan, Subdiagnostic, }; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_middle::ty::{self, Ty}; @@ -1087,69 +1086,6 @@ pub(crate) enum MiscPatternSuggestion { }, } -#[derive(LintDiagnostic)] -#[diag(mir_build_rust_2024_incompatible_pat)] -pub(crate) struct Rust2024IncompatiblePat { - #[subdiagnostic] - pub(crate) sugg: Rust2024IncompatiblePatSugg, - pub(crate) bad_modifiers: bool, - pub(crate) bad_ref_pats: bool, - pub(crate) is_hard_error: bool, -} - -pub(crate) struct Rust2024IncompatiblePatSugg { - /// If true, our suggestion is to elide explicit binding modifiers. - /// If false, our suggestion is to make the pattern fully explicit. - pub(crate) suggest_eliding_modes: bool, - pub(crate) suggestion: Vec<(Span, String)>, - pub(crate) ref_pattern_count: usize, - pub(crate) binding_mode_count: usize, - /// Labels for where incompatibility-causing by-ref default binding modes were introduced. - pub(crate) default_mode_labels: FxIndexMap, -} - -impl Subdiagnostic for Rust2024IncompatiblePatSugg { - fn add_to_diag(self, diag: &mut Diag<'_, G>) { - // Format and emit explanatory notes about default binding modes. Reversing the spans' order - // means if we have nested spans, the innermost ones will be visited first. - for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { - // Don't point to a macro call site. - if !span.from_expansion() { - let note_msg = "matching on a reference type with a non-reference pattern changes the default binding mode"; - let label_msg = - format!("this matches on type `{}_`", def_br_mutbl.ref_prefix_str()); - let mut label = MultiSpan::from(span); - label.push_span_label(span, label_msg); - diag.span_note(label, note_msg); - } - } - - // Format and emit the suggestion. - let applicability = - if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) { - Applicability::MachineApplicable - } else { - Applicability::MaybeIncorrect - }; - let msg = if self.suggest_eliding_modes { - let plural_modes = pluralize!(self.binding_mode_count); - format!("remove the unnecessary binding modifier{plural_modes}") - } else { - let plural_derefs = pluralize!(self.ref_pattern_count); - let and_modes = if self.binding_mode_count > 0 { - format!(" and variable binding mode{}", pluralize!(self.binding_mode_count)) - } else { - String::new() - }; - format!("make the implied reference pattern{plural_derefs}{and_modes} explicit") - }; - // FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!) - if !self.suggestion.is_empty() { - diag.multipart_suggestion_verbose(msg, self.suggestion, applicability); - } - } -} - #[derive(Diagnostic)] #[diag(mir_build_loop_match_invalid_update)] pub(crate) struct LoopMatchInvalidUpdate { diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 12c457f13fc12..8887308530506 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -1,15 +1,12 @@ //! Automatic migration of Rust 2021 patterns to a form valid in both Editions 2021 and 2024. use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::MultiSpan; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, pluralize}; use rustc_hir::{BindingMode, ByRef, HirId, Mutability}; use rustc_lint as lint; use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt}; use rustc_span::{Ident, Span}; -use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg}; -use crate::fluent_generated as fluent; - /// For patterns flagged for migration during HIR typeck, this handles constructing and emitting /// a diagnostic suggestion. pub(super) struct PatMigration<'a> { @@ -49,39 +46,90 @@ impl<'a> PatMigration<'a> { for (span, label) in self.info.primary_labels.iter() { spans.push_span_label(*span, label.clone()); } - let sugg = Rust2024IncompatiblePatSugg { - suggest_eliding_modes: self.info.suggest_eliding_modes, - suggestion: self.suggestion, - ref_pattern_count: self.ref_pattern_count, - binding_mode_count: self.binding_mode_count, - default_mode_labels: self.default_mode_labels, - }; // If a relevant span is from at least edition 2024, this is a hard error. let is_hard_error = spans.primary_spans().iter().any(|span| span.at_least_rust_2024()); + let primary_message = self.primary_message(is_hard_error); if is_hard_error { - let mut err = - tcx.dcx().struct_span_err(spans, fluent::mir_build_rust_2024_incompatible_pat); - if let Some(info) = lint::builtin::RUST_2024_INCOMPATIBLE_PAT.future_incompatible { - // provide the same reference link as the lint - err.note(format!("for more information, see {}", info.reference)); - } - err.arg("bad_modifiers", self.info.bad_modifiers); - err.arg("bad_ref_pats", self.info.bad_ref_pats); - err.arg("is_hard_error", true); - err.subdiagnostic(sugg); + let mut err = tcx.dcx().struct_span_err(spans, primary_message); + err.note("for more information, see "); + self.format_subdiagnostics(&mut err); err.emit(); } else { - tcx.emit_node_span_lint( - lint::builtin::RUST_2024_INCOMPATIBLE_PAT, - pat_id, - spans, - Rust2024IncompatiblePat { - sugg, - bad_modifiers: self.info.bad_modifiers, - bad_ref_pats: self.info.bad_ref_pats, - is_hard_error, - }, - ); + tcx.node_span_lint(lint::builtin::RUST_2024_INCOMPATIBLE_PAT, pat_id, spans, |diag| { + diag.primary_message(primary_message); + self.format_subdiagnostics(diag); + }); + } + } + + fn primary_message(&self, is_hard_error: bool) -> String { + let verb1 = match (self.info.bad_mut_modifiers, self.info.bad_ref_modifiers) { + (true, true) => "write explicit binding modifiers", + (true, false) => "mutably bind by value", + (false, true) => "explicitly borrow", + (false, false) => "explicitly dereference", + }; + let or_verb2 = match ( + self.info.bad_mut_modifiers, + self.info.bad_ref_modifiers, + self.info.bad_ref_pats, + ) { + // We only need two verb phrases if mentioning both modifiers and reference patterns. + (false, false, _) | (_, _, false) => "", + // If mentioning `mut`, we don't have an "explicitly" yet. + (true, _, true) => " or explicitly dereference", + // If mentioning `ref`/`ref mut` but not `mut`, we already have an "explicitly". + (false, true, true) => " or dereference", + }; + let in_rust_2024 = if is_hard_error { "" } else { " in Rust 2024" }; + format!("cannot {verb1}{or_verb2} within an implicitly-borrowing pattern{in_rust_2024}") + } + + fn format_subdiagnostics(self, diag: &mut Diag<'_, impl EmissionGuarantee>) { + // Format and emit explanatory notes about default binding modes. Reversing the spans' order + // means if we have nested spans, the innermost ones will be visited first. + for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() { + // Don't point to a macro call site. + if !span.from_expansion() { + let note_msg = "matching on a reference type with a non-reference pattern implicitly borrows the contents"; + let label_msg = format!( + "this non-reference pattern matches on a reference type `{}_`", + def_br_mutbl.ref_prefix_str() + ); + let mut label = MultiSpan::from(span); + label.push_span_label(span, label_msg); + diag.span_note(label, note_msg); + } + } + + // Format and emit the suggestion. + let applicability = + if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }; + let plural_modes = pluralize!(self.binding_mode_count); + let msg = if self.info.suggest_eliding_modes { + format!("remove the unnecessary binding modifier{plural_modes}") + } else { + let match_on_these_references = if self.ref_pattern_count == 1 { + "match on the reference with a reference pattern" + } else { + "match on these references with reference patterns" + }; + let and_explain_modes = if self.binding_mode_count > 0 { + let a = if self.binding_mode_count == 1 { "a " } else { "" }; + format!(" and borrow explicitly using {a}variable binding mode{plural_modes}") + } else { + " to avoid implicitly borrowing".to_owned() + }; + format!("{match_on_these_references}{and_explain_modes}") + }; + // FIXME(dianne): for peace of mind, don't risk emitting a 0-part suggestion (that panics!) + debug_assert!(!self.suggestion.is_empty()); + if !self.suggestion.is_empty() { + diag.multipart_suggestion_verbose(msg, self.suggestion, applicability); } } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2021.stderr index 7e3caaf979748..fc1ca18c12026 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2021.stderr @@ -59,20 +59,20 @@ LL | let [&bind_ref_mut!(x)] = &mut [0]; | | | help: replace this `&` with `&mut`: `&mut` -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/mixed-editions.rs:30:10 | LL | let [bind_ref!(y)] = &[0]; | ^^^^^^^^^^^^ occurs within macro expansion | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/mixed-editions.rs:30:9 | LL | let [bind_ref!(y)] = &[0]; - | ^^^^^^^^^^^^^^ this matches on type `&_` + | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` = note: this error originates in the macro `bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) -help: make the implied reference pattern explicit +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[bind_ref!(y)] = &[0]; | + diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2024.stderr index 466993a1671f4..9377d535f1874 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.classic2024.stderr @@ -58,14 +58,14 @@ LL | let [&bind_ref_mut!(x)] = &mut [0]; | | | help: replace this `&` with `&mut`: `&mut` -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/mixed-editions.rs:26:21 | LL | let match_ctor!(ref x) = &[0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -help: make the implied reference pattern explicit + = note: for more information, see +help: match on the reference with a reference pattern to avoid implicitly borrowing --> $DIR/auxiliary/mixed-editions-macros.rs:11:9 | LL | &[$p] diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.rs index 0a22b55ab6374..3580ed3862703 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.rs @@ -24,11 +24,11 @@ fn assert_type_eq>(_: T, _: U) {} /// only when the binding is from edition 2024. fn ref_binding_tests() { let match_ctor!(ref x) = &[0]; - //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[classic2024,structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(classic2021, structural2021))] assert_type_eq(x, &0u32); let [bind_ref!(y)] = &[0]; - //[classic2021,structural2021]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[classic2021,structural2021]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(classic2024, structural2024))] assert_type_eq(y, &0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2021.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2021.stderr index 4075dc9529da1..69ddb0720526e 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2021.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2021.stderr @@ -37,20 +37,20 @@ LL | let [&bind_ref_mut!(x)] = &mut [0]; | | | help: replace this `&` with `&mut`: `&mut` -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/mixed-editions.rs:30:10 | LL | let [bind_ref!(y)] = &[0]; | ^^^^^^^^^^^^ occurs within macro expansion | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/mixed-editions.rs:30:9 | LL | let [bind_ref!(y)] = &[0]; - | ^^^^^^^^^^^^^^ this matches on type `&_` + | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` = note: this error originates in the macro `bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) -help: make the implied reference pattern explicit +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[bind_ref!(y)] = &[0]; | + diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2024.stderr index 819a54299ea1c..bc1fee35a6bb4 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mixed-editions.structural2024.stderr @@ -36,14 +36,14 @@ LL | let [&bind_ref_mut!(x)] = &mut [0]; | | | help: replace this `&` with `&mut`: `&mut` -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/mixed-editions.rs:26:21 | LL | let match_ctor!(ref x) = &[0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -help: make the implied reference pattern explicit + = note: for more information, see +help: match on the reference with a reference pattern to avoid implicitly borrowing --> $DIR/auxiliary/mixed-editions-macros.rs:11:9 | LL | &[$p] diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr index 04e53e06a22e6..956cd2166433a 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.classic2024.stderr @@ -11,19 +11,19 @@ LL - let [&mut ref x] = &[&mut 0]; LL + let [&ref x] = &[&mut 0]; | -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:73:10 | LL | let [ref mut x] = &[0]; - | ^^^^^^^ binding modifier not allowed under `ref` default binding mode + | ^^^^^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:73:9 | LL | let [ref mut x] = &[0]; - | ^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[ref mut x] = &[0]; | + @@ -34,53 +34,53 @@ error[E0596]: cannot borrow data in a `&` reference as mutable LL | let [ref mut x] = &[0]; | ^^^^^^^^^ cannot borrow as mutable -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:81:10 | LL | let [ref x] = &[0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:81:9 | LL | let [ref x] = &[0]; - | ^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[ref x] = &[0]; | + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:85:10 | LL | let [ref x] = &mut [0]; - | ^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:85:9 | LL | let [ref x] = &mut [0]; - | ^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [ref x] = &mut [0]; | ++++ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:89:10 | LL | let [ref mut x] = &mut [0]; - | ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^^^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:89:9 | LL | let [ref mut x] = &mut [0]; - | ^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [ref mut x] = &mut [0]; | ++++ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs index c9e3f75cf178a..628cb60b8495c 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.rs @@ -17,22 +17,22 @@ /// The eat-outer variant eats the inherited reference, so binding with `ref` isn't a problem. fn errors_from_eating_the_real_reference() { let [&ref x] = &[&0]; - //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&u32 = x; let [&ref x] = &mut [&0]; - //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&u32 = x; let [&mut ref x] = &mut [&mut 0]; - //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&mut u32 = x; let [&mut ref mut x] = &mut [&mut 0]; - //[structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &mut u32 = x; #[cfg(classic2024)] let _: &mut &mut u32 = x; } @@ -43,14 +43,14 @@ fn errors_from_eating_the_real_reference_caught_in_hir_typeck_on_stable() { let [&ref x] = &[&mut 0]; //[stable2021]~^ ERROR: mismatched types //[stable2021]~| NOTE types differ in mutability - //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[structural2024]~^^^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&mut u32 = x; let [&ref x] = &mut [&mut 0]; //[stable2021]~^ ERROR: mismatched types //[stable2021]~| NOTE types differ in mutability - //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[structural2024]~^^^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(classic2021, structural2021))] let _: &u32 = x; #[cfg(classic2024)] let _: &&mut u32 = x; } @@ -60,7 +60,7 @@ fn errors_dependent_on_eating_order_caught_in_hir_typeck_when_eating_outer() { let [&mut ref x] = &[&mut 0]; //[classic2024]~^ ERROR: mismatched types //[classic2024]~| NOTE cannot match inherited `&` with `&mut` pattern - //[structural2024]~^^^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[structural2024]~^^^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; } @@ -72,21 +72,21 @@ fn errors_dependent_on_eating_order_caught_in_hir_typeck_when_eating_outer() { fn borrowck_errors_in_old_editions() { let [ref mut x] = &[0]; //~^ ERROR: cannot borrow data in a `&` reference as mutable - //[classic2024,structural2024]~| ERROR: binding modifiers may only be written when the default binding mode is `move` + //[classic2024,structural2024]~| ERROR: cannot explicitly borrow within an implicitly-borrowing pattern } /// The remaining tests are purely for testing `ref` bindings in the presence of an inherited /// reference. These should always fail on edition 2024 and succeed on edition 2021. pub fn main() { let [ref x] = &[0]; - //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[classic2024,structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; let [ref x] = &mut [0]; - //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[classic2024,structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &u32 = x; let [ref mut x] = &mut [0]; - //[classic2024,structural2024]~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //[classic2024,structural2024]~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern #[cfg(any(stable2021, classic2021, structural2021))] let _: &mut u32 = x; } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr index def6deb325acd..9753e3e5fbfea 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-binding-on-inh-ref-errors.structural2024.stderr @@ -1,135 +1,135 @@ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:19:11 | LL | let [&ref x] = &[&0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:19:9 | LL | let [&ref x] = &[&0]; - | ^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&ref x] = &[&0]; | + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:24:11 | LL | let [&ref x] = &mut [&0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:24:9 | LL | let [&ref x] = &mut [&0]; - | ^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [&ref x] = &mut [&0]; | ++++ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:29:15 | LL | let [&mut ref x] = &mut [&mut 0]; - | ^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:29:9 | LL | let [&mut ref x] = &mut [&mut 0]; - | ^^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [&mut ref x] = &mut [&mut 0]; | ++++ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:34:15 | LL | let [&mut ref mut x] = &mut [&mut 0]; - | ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^^^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:34:9 | LL | let [&mut ref mut x] = &mut [&mut 0]; - | ^^^^^^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [&mut ref mut x] = &mut [&mut 0]; | ++++ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:43:11 | LL | let [&ref x] = &[&mut 0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:43:9 | LL | let [&ref x] = &[&mut 0]; - | ^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&ref x] = &[&mut 0]; | + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:50:11 | LL | let [&ref x] = &mut [&mut 0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:50:9 | LL | let [&ref x] = &mut [&mut 0]; - | ^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [&ref x] = &mut [&mut 0]; | ++++ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:60:15 | LL | let [&mut ref x] = &[&mut 0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:60:9 | LL | let [&mut ref x] = &[&mut 0]; - | ^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&mut ref x] = &[&mut 0]; | + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:73:10 | LL | let [ref mut x] = &[0]; - | ^^^^^^^ binding modifier not allowed under `ref` default binding mode + | ^^^^^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:73:9 | LL | let [ref mut x] = &[0]; - | ^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[ref mut x] = &[0]; | + @@ -140,53 +140,53 @@ error[E0596]: cannot borrow data in a `&` reference as mutable LL | let [ref mut x] = &[0]; | ^^^^^^^^^ cannot borrow as mutable -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:81:10 | LL | let [ref x] = &[0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:81:9 | LL | let [ref x] = &[0]; - | ^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[ref x] = &[0]; | + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:85:10 | LL | let [ref x] = &mut [0]; - | ^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:85:9 | LL | let [ref x] = &mut [0]; - | ^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [ref x] = &mut [0]; | ++++ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/ref-binding-on-inh-ref-errors.rs:89:10 | LL | let [ref mut x] = &mut [0]; - | ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^^^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/ref-binding-on-inh-ref-errors.rs:89:9 | LL | let [ref mut x] = &mut [0]; - | ^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut [ref mut x] = &mut [0]; | ++++ diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed index bb4ecc09063b7..2df39fdd6103d 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.fixed @@ -23,22 +23,22 @@ fn main() { assert_type_eq(x, &mut 0u8); let &Foo(mut x) = &Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let &mut Foo(mut x) = &mut Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let Foo(x) = &Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, &0u8); let &mut Foo(ref x) = &mut Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, &0u8); @@ -55,22 +55,22 @@ fn main() { assert_type_eq(x, &0u8); let &Foo(&x) = &Foo(&0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let &Foo(&mut x) = &Foo(&mut 0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let &mut Foo(&x) = &mut Foo(&0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let &mut Foo(&mut x) = &mut Foo(&mut 0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); @@ -79,25 +79,25 @@ fn main() { } if let &&&&&Some(&x) = &&&&&Some(&0u8) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); } if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); } if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); } if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, &mut 0u8); } @@ -109,20 +109,20 @@ fn main() { } let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 }; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, 0u32); let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 }; - //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow or dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &&0u32); assert_type_eq(c, &&0u32); if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } = - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 &(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) }) { @@ -135,7 +135,7 @@ fn main() { // The two patterns are the same syntactically, but because they're defined in different // editions they don't mean the same thing. &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern assert_type_eq(x, 0u32); assert_type_eq(y, 0u32); } @@ -143,26 +143,26 @@ fn main() { } let &mut [&mut &[ref a]] = &mut [&mut &[0]]; - //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow or dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); let &[&(_)] = &[&0]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 // NB: Most of the following tests are for possible future improvements to migration suggestions // Test removing multiple binding modifiers. let Struct { a, b, c } = &Struct { a: 0, b: 0, c: 0 }; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(c, &0u32); // Test that we don't change bindings' modes when removing binding modifiers. let &mut Struct { ref a, ref mut b, ref mut c } = &mut Struct { a: 0, b: 0, c: 0 }; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &mut 0u32); @@ -170,7 +170,7 @@ fn main() { // Test removing multiple reference patterns of various mutabilities, plus a binding modifier. let &mut &Struct { a: &[ref a], b: &mut [&[ref b]], ref c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &0u32); @@ -178,13 +178,13 @@ fn main() { // Test that we don't change bindings' types when removing reference patterns. let &Foo(&ref a) = &Foo(&0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); // Test that we don't change bindings' modes when adding reference paterns (caught early). let &(&a, ref b, &[ref c], &mut [&mut (ref d, &[ref e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &0u32); @@ -194,7 +194,7 @@ fn main() { // Test that we don't change bindings' modes when adding reference patterns (caught late). let &(ref a, &mut [ref b], &[mut c]) = &(0, &mut [0], &[0]); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &0u32); @@ -202,7 +202,7 @@ fn main() { // Test featuring both additions and removals. let &(&a, &mut (ref b, &[ref c])) = &(&0, &mut (0, &[0])); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &0u32); @@ -210,21 +210,21 @@ fn main() { // Test that bindings' subpatterns' modes are updated properly. let &[mut a @ ref b] = &[0]; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &0u32); // Test that bindings' subpatterns' modes are checked properly. let &[ref a @ mut b] = &[0]; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, 0u32); // Test that we respect bindings' subpatterns' types when rewriting `&ref x` to `x`. let [&Foo(&ref a @ ref b), &Foo(&ref c @ d)] = [&Foo(&0); 2]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &0u32); @@ -233,7 +233,7 @@ fn main() { // Test that we respect bindings' subpatterns' modes when rewriting `&ref x` to `x`. let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &[0u32]); assert_type_eq(b, &0u32); @@ -242,12 +242,32 @@ fn main() { // Test that we use the correct message and suggestion style when pointing inside expansions. let &[migration_lint_macros::bind_ref!(a)] = &[0]; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern assert_type_eq(a, &0u32); // Test that we use the correct span when labeling a `&` whose subpattern is from an expansion. let &[&migration_lint_macros::bind_ref!(a)] = &[&0]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); + + // Test the primary diagnostic message for mixes of `mut`/`ref`/`&`. + let &(mut a, ref b) = &(0, 0); + //~^ ERROR: cannot write explicit binding modifiers within an implicitly-borrowing pattern in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, &0u32); + + let &(mut a, &b) = &(0, &0); + //~^ ERROR: cannot mutably bind by value or explicitly dereference within an implicitly-borrowing pattern in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, 0u32); + + let &(mut a, ref b, &c) = &(0, 0, &0); + //~^ ERROR: cannot write explicit binding modifiers or explicitly dereference within an implicitly-borrowing pattern in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, &0u32); + assert_type_eq(c, 0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs index 2837c8d81dbdd..0d727ad7d7a5c 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.rs @@ -23,22 +23,22 @@ fn main() { assert_type_eq(x, &mut 0u8); let Foo(mut x) = &Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let Foo(mut x) = &mut Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let Foo(ref x) = &Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, &0u8); let Foo(ref x) = &mut Foo(0); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, &0u8); @@ -55,22 +55,22 @@ fn main() { assert_type_eq(x, &0u8); let Foo(&x) = &Foo(&0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let Foo(&mut x) = &Foo(&mut 0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let Foo(&x) = &mut Foo(&0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); let Foo(&mut x) = &mut Foo(&mut 0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); @@ -79,25 +79,25 @@ fn main() { } if let Some(&x) = &&&&&Some(&0u8) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); } if let Some(&mut x) = &&&&&Some(&mut 0u8) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); } if let Some(&x) = &&&&&mut Some(&0u8) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, 0u8); } if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(x, &mut 0u8); } @@ -109,20 +109,20 @@ fn main() { } let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, 0u32); let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; - //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow or dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &&0u32); assert_type_eq(c, &&0u32); if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 &(Struct { a: &Some(&0), b: &Some(&0), c: &Some(&0) }) { @@ -135,7 +135,7 @@ fn main() { // The two patterns are the same syntactically, but because they're defined in different // editions they don't mean the same thing. (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern assert_type_eq(x, 0u32); assert_type_eq(y, 0u32); } @@ -143,26 +143,26 @@ fn main() { } let [&mut [ref a]] = &mut [&mut &[0]]; - //~^ ERROR: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow or dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); let [&(_)] = &[&0]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 // NB: Most of the following tests are for possible future improvements to migration suggestions // Test removing multiple binding modifiers. let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(c, &0u32); // Test that we don't change bindings' modes when removing binding modifiers. let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 }; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &mut 0u32); @@ -170,7 +170,7 @@ fn main() { // Test removing multiple reference patterns of various mutabilities, plus a binding modifier. let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &0u32); @@ -178,13 +178,13 @@ fn main() { // Test that we don't change bindings' types when removing reference patterns. let Foo(&ref a) = &Foo(&0); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); // Test that we don't change bindings' modes when adding reference paterns (caught early). let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &0u32); @@ -194,7 +194,7 @@ fn main() { // Test that we don't change bindings' modes when adding reference patterns (caught late). let (a, [b], [mut c]) = &(0, &mut [0], &[0]); - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &0u32); @@ -202,7 +202,7 @@ fn main() { // Test featuring both additions and removals. let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0])); - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &0u32); @@ -210,21 +210,21 @@ fn main() { // Test that bindings' subpatterns' modes are updated properly. let [mut a @ b] = &[0]; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, 0u32); assert_type_eq(b, &0u32); // Test that bindings' subpatterns' modes are checked properly. let [a @ mut b] = &[0]; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, 0u32); // Test that we respect bindings' subpatterns' types when rewriting `&ref x` to `x`. let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); assert_type_eq(b, &0u32); @@ -233,7 +233,7 @@ fn main() { // Test that we respect bindings' subpatterns' modes when rewriting `&ref x` to `x`. let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &[0u32]); assert_type_eq(b, &0u32); @@ -242,12 +242,32 @@ fn main() { // Test that we use the correct message and suggestion style when pointing inside expansions. let [migration_lint_macros::bind_ref!(a)] = &[0]; - //~^ ERROR: binding modifiers may only be written when the default binding mode is `move` + //~^ ERROR: cannot explicitly borrow within an implicitly-borrowing pattern assert_type_eq(a, &0u32); // Test that we use the correct span when labeling a `&` whose subpattern is from an expansion. let [&migration_lint_macros::bind_ref!(a)] = &[&0]; - //~^ ERROR: reference patterns may only be written when the default binding mode is `move` in Rust 2024 + //~^ ERROR: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 //~| WARN: this changes meaning in Rust 2024 assert_type_eq(a, &0u32); + + // Test the primary diagnostic message for mixes of `mut`/`ref`/`&`. + let (mut a, ref b) = &(0, 0); + //~^ ERROR: cannot write explicit binding modifiers within an implicitly-borrowing pattern in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, &0u32); + + let (mut a, &b) = &(0, &0); + //~^ ERROR: cannot mutably bind by value or explicitly dereference within an implicitly-borrowing pattern in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, 0u32); + + let (mut a, ref b, &c) = &(0, 0, &0); + //~^ ERROR: cannot write explicit binding modifiers or explicitly dereference within an implicitly-borrowing pattern in Rust 2024 + //~| WARN: this changes meaning in Rust 2024 + assert_type_eq(a, 0u32); + assert_type_eq(b, &0u32); + assert_type_eq(c, 0u32); } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr index 6efda4f757ff6..01fcfdc8be6ee 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr @@ -1,602 +1,663 @@ -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:25:13 | LL | let Foo(mut x) = &Foo(0); - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ `mut` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:25:9 | LL | let Foo(mut x) = &Foo(0); - | ^^^^^^^^^^ this matches on type `&_` + | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` note: the lint level is defined here --> $DIR/migration_lint.rs:7:9 | LL | #![deny(rust_2024_incompatible_pat)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: make the implied reference pattern explicit +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(mut x) = &Foo(0); | + -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:30:13 | LL | let Foo(mut x) = &mut Foo(0); - | ^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^ `mut` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:30:9 | LL | let Foo(mut x) = &mut Foo(0); - | ^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(mut x) = &mut Foo(0); | ++++ -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:35:13 | LL | let Foo(ref x) = &Foo(0); - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:35:9 | LL | let Foo(ref x) = &Foo(0); - | ^^^^^^^^^^ this matches on type `&_` + | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` help: remove the unnecessary binding modifier | LL - let Foo(ref x) = &Foo(0); LL + let Foo(x) = &Foo(0); | -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:40:13 | LL | let Foo(ref x) = &mut Foo(0); - | ^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:40:9 | LL | let Foo(ref x) = &mut Foo(0); - | ^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(ref x) = &mut Foo(0); | ++++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:57:13 | LL | let Foo(&x) = &Foo(&0); - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:57:9 | LL | let Foo(&x) = &Foo(&0); - | ^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&x) = &Foo(&0); | + -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:62:13 | LL | let Foo(&mut x) = &Foo(&mut 0); - | ^^^^ reference pattern not allowed under `ref` default binding mode + | ^^^^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:62:9 | LL | let Foo(&mut x) = &Foo(&mut 0); - | ^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&mut x) = &Foo(&mut 0); | + -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:67:13 | LL | let Foo(&x) = &mut Foo(&0); - | ^ reference pattern not allowed under `ref mut` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:67:9 | LL | let Foo(&x) = &mut Foo(&0); - | ^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(&x) = &mut Foo(&0); | ++++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:72:13 | LL | let Foo(&mut x) = &mut Foo(&mut 0); - | ^^^^ reference pattern not allowed under `ref mut` default binding mode + | ^^^^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:72:9 | LL | let Foo(&mut x) = &mut Foo(&mut 0); - | ^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(&mut x) = &mut Foo(&mut 0); | ++++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:81:17 | LL | if let Some(&x) = &&&&&Some(&0u8) { - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:81:12 | LL | if let Some(&x) = &&&&&Some(&0u8) { - | ^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns explicit + | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&Some(&x) = &&&&&Some(&0u8) { | +++++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:87:17 | LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) { - | ^^^^ reference pattern not allowed under `ref` default binding mode + | ^^^^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:87:12 | LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) { - | ^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns explicit + | ^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) { | +++++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:93:17 | LL | if let Some(&x) = &&&&&mut Some(&0u8) { - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:93:12 | LL | if let Some(&x) = &&&&&mut Some(&0u8) { - | ^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns explicit + | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) { | ++++++++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:99:17 | LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { - | ^^^^ reference pattern not allowed under `ref mut` default binding mode + | ^^^^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:99:12 | LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { - | ^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference patterns and variable binding mode explicit + | ^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) { | ++++ ++++ +++++++ -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:111:21 | LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ `mut` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:111:9 | LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern and variable binding modes explicit + | ^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern and borrow explicitly using variable binding modes | LL | let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 }; | + +++ +++ -error: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly borrow or dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:117:21 | LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; - | ^ ^^^ binding modifier not allowed under `ref` default binding mode + | ^ ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | | - | reference pattern not allowed under `ref` default binding mode + | reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:117:9 | LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern and variable binding mode explicit + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 }; | + +++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:124:24 | LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = - | ^ ^ reference pattern not allowed under `ref` default binding mode + | ^ ^ reference pattern not allowed when implicitly borrowing | | - | reference pattern not allowed under `ref` default binding mode + | reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:124:12 | LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns and variable binding mode explicit + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } = | + + + +++ -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot mutably bind by value within an implicitly-borrowing pattern --> $DIR/migration_lint.rs:137:15 | LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { | ^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ occurs within macro expansion | | - | binding modifier not allowed under `ref` default binding mode + | `mut` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:137:9 | LL | (Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` = note: this error originates in the macro `migration_lint_macros::mixed_edition_pat` (in Nightly builds, run with -Z macro-backtrace for more info) -help: make the implied reference pattern explicit +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | &(Some(mut x), migration_lint_macros::mixed_edition_pat!(y)) => { | + -error: binding modifiers and reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly borrow or dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:145:10 | LL | let [&mut [ref a]] = &mut [&mut &[0]]; - | ^^^^ ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^^ ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | | - | reference pattern not allowed under `ref mut` default binding mode + | reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:145:15 | LL | let [&mut [ref a]] = &mut [&mut &[0]]; - | ^^^^^^^ this matches on type `&_` -note: matching on a reference type with a non-reference pattern changes the default binding mode + | ^^^^^^^ this non-reference pattern matches on a reference type `&_` +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:145:9 | LL | let [&mut [ref a]] = &mut [&mut &[0]]; - | ^^^^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference patterns explicit + | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on these references with reference patterns to avoid implicitly borrowing | LL | let &mut [&mut &[ref a]] = &mut [&mut &[0]]; | ++++ + -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:150:10 | LL | let [&(_)] = &[&0]; - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:150:9 | LL | let [&(_)] = &[&0]; - | ^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&(_)] = &[&0]; | + -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:157:18 | LL | let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; - | ^^^ ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | | - | binding modifier not allowed under `ref` default binding mode + | explicit `ref` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:157:9 | LL | let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` help: remove the unnecessary binding modifiers | LL - let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; LL + let Struct { a, b, c } = &Struct { a: 0, b: 0, c: 0 }; | -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:164:18 | LL | let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 }; - | ^^^ ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^ ^^^^^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | | - | binding modifier not allowed under `ref mut` default binding mode + | explicit `ref` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:164:9 | LL | let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&mut _` -help: make the implied reference pattern and variable binding mode explicit + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` +help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &mut Struct { ref a, ref mut b, ref mut c } = &mut Struct { a: 0, b: 0, c: 0 }; | ++++ +++++++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:172:21 | LL | let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; - | ^ ^^^^ reference pattern not allowed under `ref` default binding mode + | ^ ^^^^ reference pattern not allowed when implicitly borrowing | | - | reference pattern not allowed under `ref` default binding mode + | reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:172:9 | LL | let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns and variable binding modes explicit + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &mut &Struct { a: &[ref a], b: &mut [&[ref b]], ref c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; | ++++++ + +++ +++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:180:13 | LL | let Foo(&ref a) = &Foo(&0); - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:180:9 | LL | let Foo(&ref a) = &Foo(&0); - | ^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&ref a) = &Foo(&0); | + -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:186:10 | LL | let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:186:9 | LL | let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); - | ^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns and variable binding modes explicit + | ^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &(&a, ref b, &[ref c], &mut [&mut (ref d, &[ref e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); | + +++ + +++ ++++ ++++ +++ + +++ -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:196:19 | LL | let (a, [b], [mut c]) = &(0, &mut [0], &[0]); - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ `mut` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:196:9 | LL | let (a, [b], [mut c]) = &(0, &mut [0], &[0]); - | ^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns and variable binding modes explicit + | ^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &(ref a, &mut [ref b], &[mut c]) = &(0, &mut [0], &[0]); | + +++ ++++ +++ + -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:204:10 | LL | let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0])); - | ^ ^ reference pattern not allowed under `ref` default binding mode + | ^ ^ reference pattern not allowed when implicitly borrowing | | - | reference pattern not allowed under `ref` default binding mode + | reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:204:9 | LL | let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0])); - | ^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns and variable binding mode explicit + | ^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | let &(&a, &mut (ref b, &[ref c])) = &(&0, &mut (0, &[0])); | + ++++ +++ -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:212:10 | LL | let [mut a @ b] = &[0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ `mut` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:212:9 | LL | let [mut a @ b] = &[0]; - | ^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern and variable binding mode explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &[mut a @ ref b] = &[0]; | + +++ -error: binding modifiers may only be written when the default binding mode is `move` in Rust 2024 +error: cannot mutably bind by value within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:219:14 | LL | let [a @ mut b] = &[0]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ `mut` binding modifier not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:219:9 | LL | let [a @ mut b] = &[0]; - | ^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern and variable binding mode explicit + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &[ref a @ mut b] = &[0]; | + +++ -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:226:14 | LL | let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; - | ^ ^ reference pattern not allowed under `ref` default binding mode + | ^ ^ reference pattern not allowed when implicitly borrowing | | - | reference pattern not allowed under `ref` default binding mode + | reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:226:31 | LL | let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; - | ^^^^^^^^^^^^^^^ this matches on type `&_` -note: matching on a reference type with a non-reference pattern changes the default binding mode + | ^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:226:10 | LL | let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; - | ^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns explicit + | ^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns to avoid implicitly borrowing | LL | let [&Foo(&ref a @ ref b), &Foo(&ref c @ d)] = [&Foo(&0); 2]; | + + -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:235:14 | LL | let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; - | ^ ^ reference pattern not allowed under `ref` default binding mode + | ^ ^ reference pattern not allowed when implicitly borrowing | | - | reference pattern not allowed under `ref` default binding mode + | reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:235:33 | LL | let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; - | ^^^^^^^^^^^^^^^^^ this matches on type `&_` -note: matching on a reference type with a non-reference pattern changes the default binding mode + | ^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:235:10 | LL | let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; - | ^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference patterns explicit + | ^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on these references with reference patterns to avoid implicitly borrowing | LL | let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | + + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/migration_lint.rs:244:10 | LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ occurs within macro expansion | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:244:9 | LL | let [migration_lint_macros::bind_ref!(a)] = &[0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` = note: this error originates in the macro `migration_lint_macros::bind_ref` (in Nightly builds, run with -Z macro-backtrace for more info) -help: make the implied reference pattern explicit +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[migration_lint_macros::bind_ref!(a)] = &[0]; | + -error: reference patterns may only be written when the default binding mode is `move` in Rust 2024 +error: cannot explicitly dereference within an implicitly-borrowing pattern in Rust 2024 --> $DIR/migration_lint.rs:249:10 | LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | = warning: this changes meaning in Rust 2024 - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:249:9 | LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&migration_lint_macros::bind_ref!(a)] = &[&0]; | + -error: aborting due to 31 previous errors +error: cannot write explicit binding modifiers within an implicitly-borrowing pattern in Rust 2024 + --> $DIR/migration_lint.rs:255:10 + | +LL | let (mut a, ref b) = &(0, 0); + | ^^^ ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing + | | + | `mut` binding modifier not allowed when implicitly borrowing + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents + --> $DIR/migration_lint.rs:255:9 + | +LL | let (mut a, ref b) = &(0, 0); + | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing + | +LL | let &(mut a, ref b) = &(0, 0); + | + + +error: cannot mutably bind by value or explicitly dereference within an implicitly-borrowing pattern in Rust 2024 + --> $DIR/migration_lint.rs:261:10 + | +LL | let (mut a, &b) = &(0, &0); + | ^^^ ^ reference pattern not allowed when implicitly borrowing + | | + | `mut` binding modifier not allowed when implicitly borrowing + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents + --> $DIR/migration_lint.rs:261:9 + | +LL | let (mut a, &b) = &(0, &0); + | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing + | +LL | let &(mut a, &b) = &(0, &0); + | + + +error: cannot write explicit binding modifiers or explicitly dereference within an implicitly-borrowing pattern in Rust 2024 + --> $DIR/migration_lint.rs:267:10 + | +LL | let (mut a, ref b, &c) = &(0, 0, &0); + | ^^^ ^^^ ^ reference pattern not allowed when implicitly borrowing + | | | + | | explicit `ref` binding modifier not allowed when implicitly borrowing + | `mut` binding modifier not allowed when implicitly borrowing + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents + --> $DIR/migration_lint.rs:267:9 + | +LL | let (mut a, ref b, &c) = &(0, 0, &0); + | ^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing + | +LL | let &(mut a, ref b, &c) = &(0, 0, &0); + | + + +error: aborting due to 34 previous errors diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs index 4dc04d90aaf5e..d56b835ac5dfc 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.rs @@ -21,17 +21,17 @@ macro_rules! test_pat_on_type { } test_pat_on_type![(&x,): &(T,)]; //~ ERROR mismatched types -test_pat_on_type![(&x,): &(&T,)]; //~ ERROR reference patterns may only be written when the default binding mode is `move` +test_pat_on_type![(&x,): &(&T,)]; //~ ERROR cannot explicitly dereference within an implicitly-borrowing pattern test_pat_on_type![(&x,): &(&mut T,)]; //~ ERROR mismatched types test_pat_on_type![(&mut x,): &(&T,)]; //~ ERROR mismatched types -test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR reference patterns may only be written when the default binding mode is `move` +test_pat_on_type![(&mut x,): &(&mut T,)]; //~ ERROR cannot explicitly dereference within an implicitly-borrowing pattern test_pat_on_type![(&x,): &&mut &(T,)]; //~ ERROR mismatched types test_pat_on_type![Foo { f: (&x,) }: Foo]; //~ ERROR mismatched types test_pat_on_type![Foo { f: (&x,) }: &mut Foo]; //~ ERROR mismatched types -test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR reference patterns may only be written when the default binding mode is `move` -test_pat_on_type![(mut x,): &(T,)]; //~ ERROR binding modifiers may only be written when the default binding mode is `move` -test_pat_on_type![(ref x,): &(T,)]; //~ ERROR binding modifiers may only be written when the default binding mode is `move` -test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR binding modifiers may only be written when the default binding mode is `move` +test_pat_on_type![Foo { f: &(x,) }: &Foo]; //~ ERROR cannot explicitly dereference within an implicitly-borrowing pattern +test_pat_on_type![(mut x,): &(T,)]; //~ ERROR cannot mutably bind by value within an implicitly-borrowing pattern +test_pat_on_type![(ref x,): &(T,)]; //~ ERROR cannot explicitly borrow within an implicitly-borrowing pattern +test_pat_on_type![(ref mut x,): &mut (T,)]; //~ ERROR cannot explicitly borrow within an implicitly-borrowing pattern fn get() -> X { unimplemented!() @@ -40,6 +40,6 @@ fn get() -> X { // Make sure this works even when the underlying type is inferred. This test passes on rust stable. fn infer() -> X { match &get() { - (&x,) => x, //~ ERROR reference patterns may only be written when the default binding mode is `move` + (&x,) => x, //~ ERROR cannot explicitly dereference within an implicitly-borrowing pattern } } diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr index 0c6b2ff3a2f09..23f1557e56d39 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/min_match_ergonomics_fail.stderr @@ -99,123 +99,123 @@ LL - test_pat_on_type![Foo { f: (&x,) }: &mut Foo]; LL + test_pat_on_type![Foo { f: (x,) }: &mut Foo]; | -error: reference patterns may only be written when the default binding mode is `move` +error: cannot explicitly dereference within an implicitly-borrowing pattern --> $DIR/min_match_ergonomics_fail.rs:24:20 | LL | test_pat_on_type![(&x,): &(&T,)]; - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/min_match_ergonomics_fail.rs:24:19 | LL | test_pat_on_type![(&x,): &(&T,)]; - | ^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | test_pat_on_type![&(&x,): &(&T,)]; | + -error: reference patterns may only be written when the default binding mode is `move` +error: cannot explicitly dereference within an implicitly-borrowing pattern --> $DIR/min_match_ergonomics_fail.rs:27:20 | LL | test_pat_on_type![(&mut x,): &(&mut T,)]; - | ^^^^ reference pattern not allowed under `ref` default binding mode + | ^^^^ reference pattern not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/min_match_ergonomics_fail.rs:27:19 | LL | test_pat_on_type![(&mut x,): &(&mut T,)]; - | ^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | test_pat_on_type![&(&mut x,): &(&mut T,)]; | + -error: reference patterns may only be written when the default binding mode is `move` +error: cannot explicitly dereference within an implicitly-borrowing pattern --> $DIR/min_match_ergonomics_fail.rs:31:28 | LL | test_pat_on_type![Foo { f: &(x,) }: &Foo]; - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/min_match_ergonomics_fail.rs:31:19 | LL | test_pat_on_type![Foo { f: &(x,) }: &Foo]; - | ^^^^^^^^^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | test_pat_on_type![&Foo { f: &(x,) }: &Foo]; | + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot mutably bind by value within an implicitly-borrowing pattern --> $DIR/min_match_ergonomics_fail.rs:32:20 | LL | test_pat_on_type![(mut x,): &(T,)]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/min_match_ergonomics_fail.rs:32:19 | LL | test_pat_on_type![(mut x,): &(T,)]; - | ^^^^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | test_pat_on_type![&(mut x,): &(T,)]; | + -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/min_match_ergonomics_fail.rs:33:20 | LL | test_pat_on_type![(ref x,): &(T,)]; - | ^^^ binding modifier not allowed under `ref` default binding mode + | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/min_match_ergonomics_fail.rs:33:19 | LL | test_pat_on_type![(ref x,): &(T,)]; - | ^^^^^^^^ this matches on type `&_` + | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` help: remove the unnecessary binding modifier | LL - test_pat_on_type![(ref x,): &(T,)]; LL + test_pat_on_type![(x,): &(T,)]; | -error: binding modifiers may only be written when the default binding mode is `move` +error: cannot explicitly borrow within an implicitly-borrowing pattern --> $DIR/min_match_ergonomics_fail.rs:34:20 | LL | test_pat_on_type![(ref mut x,): &mut (T,)]; - | ^^^^^^^ binding modifier not allowed under `ref mut` default binding mode + | ^^^^^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/min_match_ergonomics_fail.rs:34:19 | LL | test_pat_on_type![(ref mut x,): &mut (T,)]; - | ^^^^^^^^^^^^ this matches on type `&mut _` + | ^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` help: remove the unnecessary binding modifier | LL - test_pat_on_type![(ref mut x,): &mut (T,)]; LL + test_pat_on_type![(x,): &mut (T,)]; | -error: reference patterns may only be written when the default binding mode is `move` +error: cannot explicitly dereference within an implicitly-borrowing pattern --> $DIR/min_match_ergonomics_fail.rs:43:10 | LL | (&x,) => x, - | ^ reference pattern not allowed under `ref` default binding mode + | ^ reference pattern not allowed when implicitly borrowing | - = note: for more information, see -note: matching on a reference type with a non-reference pattern changes the default binding mode + = note: for more information, see +note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/min_match_ergonomics_fail.rs:43:9 | LL | (&x,) => x, - | ^^^^^ this matches on type `&_` -help: make the implied reference pattern explicit + | ^^^^^ this non-reference pattern matches on a reference type `&_` +help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | &(&x,) => x, | + From 6060bccd26b9a3a6bc14fd26e47d35fccdf590a3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 8 Oct 2025 11:57:11 +0200 Subject: [PATCH 12/16] Improve error messages for failing `should_panic` doctests Added missing FIXME comments --- src/librustdoc/doctest.rs | 48 ++++++++++++++++--- src/librustdoc/doctest/runner.rs | 25 ++++++++-- tests/run-make/rustdoc-should-panic/rmake.rs | 2 +- .../doctest/failed-doctest-should-panic.rs | 13 +++-- .../failed-doctest-should-panic.stdout | 15 ++++-- 5 files changed, 83 insertions(+), 20 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 28453f990aed2..561a23a22a755 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -465,8 +465,8 @@ enum TestFailure { /// /// This typically means an assertion in the test failed or another form of panic occurred. ExecutionFailure(process::Output), - /// The test is marked `should_panic` but the test binary executed successfully. - UnexpectedRunPass, + /// The test is marked `should_panic` but the test binary didn't panic. + NoPanic(Option), } enum DirState { @@ -812,6 +812,9 @@ fn run_test( // (cfg!(target_family = "wasm") || cfg!(target_os = "zkvm")) // && !cfg!(target_os = "emscripten") // ``` + // + // FIXME: All this code is terrible and doesn't take into account `TargetTuple::TargetJson`. + // If `libtest` doesn't allow to handle this case, we'll need to use a rustc's API instead. && let TargetTuple::TargetTuple(ref s) = rustdoc_options.target && let mut iter = s.split('-') && let Some(arch) = iter.next() @@ -876,12 +879,41 @@ fn run_test( #[cfg(windows)] Some(STATUS_FAIL_FAST_EXCEPTION) => {} #[cfg(unix)] - None if out.status.signal() == Some(SIGABRT) => {} + None => match out.status.signal() { + Some(SIGABRT) => {} + Some(signal) => { + return ( + duration, + Err(TestFailure::NoPanic(Some(format!( + "Test didn't panic, but it's marked `should_panic` (exit signal: {signal}).", + )))), + ); + } + None => { + return ( + duration, + Err(TestFailure::NoPanic(Some(format!( + "Test didn't panic, but it's marked `should_panic` and exited with no error code and no signal.", + )))), + ); + } + }, + #[cfg(not(unix))] + None => return (duration, Err(TestFailure::NoPanic(None))), // Upon an abort, Fuchsia returns the status code // `ZX_TASK_RETCODE_EXCEPTION_KILL`. #[cfg(target_os = "fuchsia")] Some(ZX_TASK_RETCODE_EXCEPTION_KILL) => {} - _ => return (duration, Err(TestFailure::UnexpectedRunPass)), + Some(exit_code) => { + let err_msg = if !out.status.success() { + Some(format!( + "Test didn't panic, but it's marked `should_panic` (exit status: {exit_code}).", + )) + } else { + None + }; + return (duration, Err(TestFailure::NoPanic(err_msg))); + } } } else if !out.status.success() { return (duration, Err(TestFailure::ExecutionFailure(out))); @@ -1190,8 +1222,12 @@ fn doctest_run_fn( TestFailure::UnexpectedCompilePass => { eprint!("Test compiled successfully, but it's marked `compile_fail`."); } - TestFailure::UnexpectedRunPass => { - eprint!("Test didn't panic, but it's marked `should_panic`."); + TestFailure::NoPanic(msg) => { + if let Some(msg) = msg { + eprint!("{msg}"); + } else { + eprint!("Test didn't panic, but it's marked `should_panic`."); + } } TestFailure::MissingErrorCodes(codes) => { eprint!("Some expected error codes were not found: {codes:?}"); diff --git a/src/librustdoc/doctest/runner.rs b/src/librustdoc/doctest/runner.rs index afcab202a8e3e..1327b0717a7f5 100644 --- a/src/librustdoc/doctest/runner.rs +++ b/src/librustdoc/doctest/runner.rs @@ -169,12 +169,31 @@ mod __doctest_mod {{ #[cfg(windows)] Some(STATUS_FAIL_FAST_EXCEPTION) => ExitCode::SUCCESS, #[cfg(unix)] - None if out.status.signal() == Some(SIGABRT) => ExitCode::SUCCESS, + None => match out.status.signal() {{ + Some(SIGABRT) => ExitCode::SUCCESS, + Some(signal) => {{ + eprintln!(\"Test didn't panic, but it's marked `should_panic` (exit signal: {{signal}}).\"); + ExitCode::FAILURE + }} + None => {{ + eprintln!(\"Test didn't panic, but it's marked `should_panic` and exited with no error code and no signal.\"); + ExitCode::FAILURE + }} + }}, + #[cfg(not(unix))] + None => {{ + eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); + ExitCode::FAILURE + }} // Upon an abort, Fuchsia returns the status code ZX_TASK_RETCODE_EXCEPTION_KILL. #[cfg(target_os = \"fuchsia\")] Some(ZX_TASK_RETCODE_EXCEPTION_KILL) => ExitCode::SUCCESS, - _ => {{ - eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); + Some(exit_code) => {{ + if !out.status.success() {{ + eprintln!(\"Test didn't panic, but it's marked `should_panic` (exit status: {{exit_code}}).\"); + }} else {{ + eprintln!(\"Test didn't panic, but it's marked `should_panic`.\"); + }} ExitCode::FAILURE }} }} diff --git a/tests/run-make/rustdoc-should-panic/rmake.rs b/tests/run-make/rustdoc-should-panic/rmake.rs index 438608ff8b4ed..0e93440af5ace 100644 --- a/tests/run-make/rustdoc-should-panic/rmake.rs +++ b/tests/run-make/rustdoc-should-panic/rmake.rs @@ -19,7 +19,7 @@ fn check_output(edition: &str, panic_abort: bool) { "---- test.rs - bad_exit_code (line 1) stdout ---- Test executable failed (exit status: 1).", "---- test.rs - did_not_panic (line 6) stdout ---- -Test didn't panic, but it's marked `should_panic`.", +Test didn't panic, but it's marked `should_panic` (exit status: 1).", "test result: FAILED. 1 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out;", ]; for text in should_contain { diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs index 0504c3dc73033..b95e23715175f 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.rs @@ -2,14 +2,17 @@ // adapted to use that, and that normalize line can go away //@ edition: 2024 -//@ compile-flags:--test +//@ compile-flags:--test --test-args=--test-threads=1 //@ normalize-stdout: "tests/rustdoc-ui/doctest" -> "$$DIR" //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ normalize-stdout: "ran in \d+\.\d+s" -> "ran in $$TIME" //@ normalize-stdout: "compilation took \d+\.\d+s" -> "compilation took $$TIME" //@ failure-status: 101 -/// ```should_panic -/// println!("Hello, world!"); -/// ``` -pub struct Foo; +//! ```should_panic +//! println!("Hello, world!"); +//! ``` +//! +//! ```should_panic +//! std::process::exit(2); +//! ``` diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout index 61099e6424ae7..a8e27fcdda2c9 100644 --- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout +++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout @@ -1,16 +1,21 @@ -running 1 test -test $DIR/failed-doctest-should-panic.rs - Foo (line 12) ... FAILED +running 2 tests +test $DIR/failed-doctest-should-panic.rs - (line 12) ... FAILED +test $DIR/failed-doctest-should-panic.rs - (line 16) ... FAILED failures: ----- $DIR/failed-doctest-should-panic.rs - Foo (line 12) stdout ---- +---- $DIR/failed-doctest-should-panic.rs - (line 12) stdout ---- Test didn't panic, but it's marked `should_panic`. +---- $DIR/failed-doctest-should-panic.rs - (line 16) stdout ---- +Test didn't panic, but it's marked `should_panic` (exit status: 2). + failures: - $DIR/failed-doctest-should-panic.rs - Foo (line 12) + $DIR/failed-doctest-should-panic.rs - (line 12) + $DIR/failed-doctest-should-panic.rs - (line 16) -test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: FAILED. 0 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME all doctests ran in $TIME; merged doctests compilation took $TIME From 849feea2f8301ef11fd9815c732d4c8c922b5212 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 8 Oct 2025 06:54:28 -0700 Subject: [PATCH 13/16] Add a test for the cold attribute This adds a test for the cold attribute to verify that it actually does something, and that it applies correctly in all the positions it is expected to work. --- tests/codegen-llvm/cold-attribute.rs | 76 ++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tests/codegen-llvm/cold-attribute.rs diff --git a/tests/codegen-llvm/cold-attribute.rs b/tests/codegen-llvm/cold-attribute.rs new file mode 100644 index 0000000000000..ca771fc7e1cfa --- /dev/null +++ b/tests/codegen-llvm/cold-attribute.rs @@ -0,0 +1,76 @@ +// Checks that the cold attribute adds the llvm cold attribute. +// +//@ reference: attributes.codegen.cold.intro +//@ reference: attributes.codegen.cold.trait +//@ edition:2024 +//@ compile-flags: -Copt-level=0 + +#![crate_type = "lib"] + +// CHECK-LABEL: ; cold_attribute::free_function +// CHECK-NEXT: Function Attrs: cold {{.*}} +#[cold] +pub fn free_function() {} + +// CHECK-LABEL: ; cold_attribute::async_block +// CHECK-NEXT: Function Attrs: cold {{.*}} +#[cold] +pub async fn async_block() { + async fn x(f: impl Future) { + f.await; + } + x( + // CHECK-LABEL: ; cold_attribute::async_block::{{{{closure}}}}::{{{{closure}}}} + // CHECK-NEXT: Function Attrs: cold {{.*}} + #[cold] + async {}, + ) + .await; +} + +pub fn closure() { + fn x(f: impl Fn()) { + f() + } + x( + // CHECK-LABEL: ; cold_attribute::closure::{{{{closure}}}} + // CHECK-NEXT: Function Attrs: cold {{.*}} + #[cold] + || {}, + ); +} + +pub struct S; + +impl S { + // CHECK-LABEL: ; cold_attribute::S::method + // CHECK-NEXT: Function Attrs: cold {{.*}} + #[cold] + pub fn method(&self) {} +} + +pub trait Trait { + // CHECK-LABEL: ; cold_attribute::Trait::trait_fn + // CHECK-NEXT: Function Attrs: cold {{.*}} + #[cold] + fn trait_fn(&self) {} + + #[cold] + fn trait_fn_overridden(&self) {} + + fn impl_fn(&self); +} + +impl Trait for S { + // CHECK-LABEL: ; ::impl_fn + // CHECK-NEXT: Function Attrs: cold {{.*}} + #[cold] + fn impl_fn(&self) { + self.trait_fn(); + } + + // This does not have #[cold], and does not inherit the cold attribute from the trait. + // CHECK-LABEL: ; ::trait_fn_overridden + // CHECK-NEXT: ; Function Attrs: uwtable + fn trait_fn_overridden(&self) {} +} From d4ecd710a5de576a8b9f891c8169a107a638f3d6 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 8 Oct 2025 15:13:47 +0000 Subject: [PATCH 14/16] format: some small cleanup --- compiler/rustc_ast/src/token.rs | 4 +-- compiler/rustc_builtin_macros/src/format.rs | 37 ++++++++++----------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 6dc6d1026f621..e1231312a2afd 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -881,11 +881,11 @@ impl Token { } pub fn is_qpath_start(&self) -> bool { - self == &Lt || self == &Shl + matches!(self.kind, Lt | Shl) } pub fn is_path_start(&self) -> bool { - self == &PathSep + self.kind == PathSep || self.is_qpath_start() || matches!(self.is_metavar_seq(), Some(MetaVarKind::Path)) || self.is_path_segment_keyword() diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index bffc0407e8112..a0ee7ac19899b 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -69,35 +69,26 @@ struct MacroInput { /// Ok((fmtstr, parsed arguments)) /// ``` fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, MacroInput> { - let mut args = FormatArguments::new(); - let mut p = ecx.new_parser_from_tts(tts); - if p.token == token::Eof { - return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp })); - } - - let first_token = &p.token; - - let fmtstr = if let token::Literal(lit) = first_token.kind - && matches!(lit.kind, token::Str | token::StrRaw(_)) - { + // parse the format string + let fmtstr = match p.token.kind { + token::Eof => return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp })), // This allows us to properly handle cases when the first comma // after the format string is mistakenly replaced with any operator, // which cause the expression parser to eat too much tokens. - p.parse_literal_maybe_minus()? - } else { + token::Literal(token::Lit { kind: token::Str | token::StrRaw(_), .. }) => { + p.parse_literal_maybe_minus()? + } // Otherwise, we fall back to the expression parser. - p.parse_expr()? + _ => p.parse_expr()?, }; - // Only allow implicit captures to be used when the argument is a direct literal - // instead of a macro expanding to one. - let is_direct_literal = matches!(fmtstr.kind, ExprKind::Lit(_)); - + // parse comma FormatArgument pairs + let mut args = FormatArguments::new(); let mut first = true; - while p.token != token::Eof { + // parse a comma, or else report an error if !p.eat(exp!(Comma)) { if first { p.clear_expected_token_types(); @@ -120,9 +111,11 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, } } first = false; + // accept a trailing comma if p.token == token::Eof { break; - } // accept trailing commas + } + // parse a FormatArgument match p.token.ident() { Some((ident, _)) if p.look_ahead(1, |t| *t == token::Eq) => { p.bump(); @@ -156,6 +149,10 @@ fn parse_args<'a>(ecx: &ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<'a, } } } + + // Only allow implicit captures for direct literals + let is_direct_literal = matches!(fmtstr.kind, ExprKind::Lit(_)); + Ok(MacroInput { fmtstr, args, is_direct_literal }) } From 730221e654d2d017465807f16cddef4a88b72d7c Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 8 Oct 2025 09:39:11 +0200 Subject: [PATCH 15/16] Fix double error for `#[no_mangle]` on closures --- .../src/attributes/codegen_attrs.rs | 1 + compiler/rustc_codegen_ssa/messages.ftl | 2 -- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 13 ++++--------- compiler/rustc_codegen_ssa/src/errors.rs | 8 -------- tests/ui/attributes/no-mangle-closure.rs | 2 +- tests/ui/attributes/no-mangle-closure.stderr | 4 +++- 6 files changed, 9 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 7978bf28214cf..0f92968385f6f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -362,6 +362,7 @@ impl NoArgsAttributeParser for NoMangleParser { Allow(Target::Static), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), + Error(Target::Closure), ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle; } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 97ff04f66daec..e321b0773ec39 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -223,8 +223,6 @@ codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple time codegen_ssa_no_field = no field `{$name}` -codegen_ssa_no_mangle_nameless = `#[no_mangle]` cannot be used on {$definition} as it has no name - codegen_ssa_no_module_named = no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 2c7643e46ceaa..e8c8729f597b9 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -19,7 +19,6 @@ use rustc_span::{Ident, Span, sym}; use rustc_target::spec::SanitizerSet; use crate::errors; -use crate::errors::NoMangleNameless; use crate::target_features::{ check_target_feature_trait_unsafe, check_tied_features, from_target_feature_attr, }; @@ -182,14 +181,10 @@ fn process_builtin_attrs( if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; } else { - tcx.dcx().emit_err(NoMangleNameless { - span: *attr_span, - definition: format!( - "{} {}", - tcx.def_descr_article(did.to_def_id()), - tcx.def_descr(did.to_def_id()) - ), - }); + tcx.dcx().span_delayed_bug( + *attr_span, + "no_mangle should be on a named function", + ); } } AttributeKind::Optimize(optimize, _) => codegen_fn_attrs.optimize = *optimize, diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index d5c30c5c7a6b0..2dd7c6fa7c080 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1284,14 +1284,6 @@ impl Diagnostic<'_, G> for TargetFeatureDisableOrEnable<'_ } } -#[derive(Diagnostic)] -#[diag(codegen_ssa_no_mangle_nameless)] -pub(crate) struct NoMangleNameless { - #[primary_span] - pub span: Span, - pub definition: String, -} - #[derive(Diagnostic)] #[diag(codegen_ssa_feature_not_valid)] pub(crate) struct FeatureNotValid<'a> { diff --git a/tests/ui/attributes/no-mangle-closure.rs b/tests/ui/attributes/no-mangle-closure.rs index c76baa27f38a0..05dcbf8e5bed7 100644 --- a/tests/ui/attributes/no-mangle-closure.rs +++ b/tests/ui/attributes/no-mangle-closure.rs @@ -7,5 +7,5 @@ pub struct S([usize; 8]); pub fn outer_function(x: S, y: S) -> usize { (#[no_mangle] || y.0[0])() - //~^ ERROR `#[no_mangle]` cannot be used on a closure as it has no name + //~^ ERROR `#[no_mangle]` attribute cannot be used on closures } diff --git a/tests/ui/attributes/no-mangle-closure.stderr b/tests/ui/attributes/no-mangle-closure.stderr index c183783493bdb..f81e65d926752 100644 --- a/tests/ui/attributes/no-mangle-closure.stderr +++ b/tests/ui/attributes/no-mangle-closure.stderr @@ -1,8 +1,10 @@ -error: `#[no_mangle]` cannot be used on a closure as it has no name +error: `#[no_mangle]` attribute cannot be used on closures --> $DIR/no-mangle-closure.rs:9:6 | LL | (#[no_mangle] || y.0[0])() | ^^^^^^^^^^^^ + | + = help: `#[no_mangle]` can be applied to functions, methods, and statics error: aborting due to 1 previous error From c050bfbf6f1c932ae955a81a0571a0fa354442fc Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Wed, 8 Oct 2025 10:10:20 +0200 Subject: [PATCH 16/16] Fix double error for `#[no_mangle]` on consts --- .../src/attributes/codegen_attrs.rs | 2 ++ .../rustc_attr_parsing/src/target_checking.rs | 17 +++++++++++++++-- tests/ui/issues/issue-45562.fixed | 2 ++ tests/ui/issues/issue-45562.rs | 2 ++ tests/ui/issues/issue-45562.stderr | 2 +- 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index 0f92968385f6f..f09b02251e4d0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -6,6 +6,7 @@ use crate::session_diagnostics::{ NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral, }; +use crate::target_checking::Policy::AllowSilent; pub(crate) struct OptimizeParser; @@ -362,6 +363,7 @@ impl NoArgsAttributeParser for NoMangleParser { Allow(Target::Static), Allow(Target::Method(MethodKind::Inherent)), Allow(Target::Method(MethodKind::TraitImpl)), + AllowSilent(Target::Const), // Handled in the `InvalidNoMangleItems` pass Error(Target::Closure), ]); const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle; diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index d28f43943ba84..fabd364d3d7f8 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -31,7 +31,9 @@ impl AllowedTargets { pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult { match self { AllowedTargets::AllowList(list) => { - if list.contains(&Policy::Allow(target)) { + if list.contains(&Policy::Allow(target)) + || list.contains(&Policy::AllowSilent(target)) + { AllowedResult::Allowed } else if list.contains(&Policy::Warn(target)) { AllowedResult::Warn @@ -40,7 +42,9 @@ impl AllowedTargets { } } AllowedTargets::AllowListWarnRest(list) => { - if list.contains(&Policy::Allow(target)) { + if list.contains(&Policy::Allow(target)) + || list.contains(&Policy::AllowSilent(target)) + { AllowedResult::Allowed } else if list.contains(&Policy::Error(target)) { AllowedResult::Error @@ -61,6 +65,7 @@ impl AllowedTargets { .iter() .filter_map(|target| match target { Policy::Allow(target) => Some(*target), + Policy::AllowSilent(_) => None, // Not listed in possible targets Policy::Warn(_) => None, Policy::Error(_) => None, }) @@ -68,10 +73,18 @@ impl AllowedTargets { } } +/// This policy determines what diagnostics should be emitted based on the `Target` of the attribute. #[derive(Debug, Eq, PartialEq)] pub(crate) enum Policy { + /// A target that is allowed. Allow(Target), + /// A target that is allowed and not listed in the possible targets. + /// This is useful if the target is checked elsewhere. + AllowSilent(Target), + /// Emits a FCW on this target. + /// This is useful if the target was previously allowed but should not be. Warn(Target), + /// Emits an error on this target. Error(Target), } diff --git a/tests/ui/issues/issue-45562.fixed b/tests/ui/issues/issue-45562.fixed index 8dcdd3a541ce4..529b5bd744e03 100644 --- a/tests/ui/issues/issue-45562.fixed +++ b/tests/ui/issues/issue-45562.fixed @@ -1,5 +1,7 @@ //@ run-rustfix +#![deny(unused_attributes)] + #[no_mangle] pub static RAH: usize = 5; //~^ ERROR const items should never be `#[no_mangle]` diff --git a/tests/ui/issues/issue-45562.rs b/tests/ui/issues/issue-45562.rs index 08f6c8046dce4..7c30a967c7848 100644 --- a/tests/ui/issues/issue-45562.rs +++ b/tests/ui/issues/issue-45562.rs @@ -1,5 +1,7 @@ //@ run-rustfix +#![deny(unused_attributes)] + #[no_mangle] pub const RAH: usize = 5; //~^ ERROR const items should never be `#[no_mangle]` diff --git a/tests/ui/issues/issue-45562.stderr b/tests/ui/issues/issue-45562.stderr index 6fae86f9f31ca..55d35f76a0198 100644 --- a/tests/ui/issues/issue-45562.stderr +++ b/tests/ui/issues/issue-45562.stderr @@ -1,5 +1,5 @@ error: const items should never be `#[no_mangle]` - --> $DIR/issue-45562.rs:3:14 + --> $DIR/issue-45562.rs:5:14 | LL | #[no_mangle] pub const RAH: usize = 5; | ---------^^^^^^^^^^^^^^^^