From a4bd5f55e7f93baca5ffc398a429a0039517a318 Mon Sep 17 00:00:00 2001 From: thiago-fealves Date: Sun, 3 May 2026 18:47:34 -0300 Subject: [PATCH 01/16] compiler: suggest `.collect()` when `String` is expected and `Iterator` is found This commit adds a diagnostic suggestion to help users who forget to call `.collect()` when they have an iterator and the function or variable expects a `String`. The logic checks if the expected type is `std::string::String` and if the found type implements the `Iterator` trait, if so the compiler provides a suggestion to add `.collect()` Includes also a UI test to verify if the suggestion appears correctly --- compiler/rustc_hir_typeck/src/demand.rs | 1 + .../src/fn_ctxt/suggestions.rs | 72 +++++++++++++++++++ tests/ui/suggestions/suggest-collect.rs | 16 +++++ tests/ui/suggestions/suggest-collect.stderr | 63 ++++++++++++++++ 4 files changed, 152 insertions(+) create mode 100644 tests/ui/suggestions/suggest-collect.rs create mode 100644 tests/ui/suggestions/suggest-collect.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 5454b282d5226..6e4d6aa80a63a 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -40,6 +40,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { || self.suggest_semicolon_in_repeat_expr(err, expr, expr_ty) || self.suggest_deref_ref_or_into(err, expr, expected, expr_ty, expected_ty_expr) || self.suggest_option_to_bool(err, expr, expr_ty, expected) + || self.suggest_collect(err, expr, expected, expr_ty) || self.suggest_compatible_variants(err, expr, expected, expr_ty) || self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty) || self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index afd5356d5a1e7..1ce004e11e996 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -250,6 +250,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Suggests calling `.collect()` on an `Iterator` it can be collected in the return type + /// ```compile_fail + /// let x: String = "foo".chars().map(|c| c); // with a .collect() here the code compiles + /// ``` + pub(crate) fn suggest_collect( + &self, + err: &mut Diag<'_>, + expr: &hir::Expr<'_>, + expected_type: Ty<'tcx>, + found_type: Ty<'tcx>, + ) -> bool { + let tcx = self.tcx; + let expected = self.resolve_vars_if_possible(expected_type); + let found = self.resolve_vars_if_possible(found_type); + + if expected.references_error() || found.references_error() { + return false; + } + + if expected.is_unit() { + return false; + } + + let Some(iterator_trait_id) = tcx.get_diagnostic_item(sym::Iterator) else { + return false; + }; + + if !self + .infcx + .type_implements_trait(iterator_trait_id, [found], self.param_env) + .must_apply_modulo_regions() + { + return false; + } + + let Some(from_iterator_trait_id) = tcx.get_diagnostic_item(sym::FromIterator) else { + return false; + }; + + let Some(iterator_item_id) = tcx + .associated_items(iterator_trait_id) + .in_definition_order() + .find(|item| item.name() == sym::Item) + .map(|item| item.def_id) + else { + return false; + }; + + let item_type = Ty::new_projection(tcx, iterator_item_id, [found]); + let item_type = + self.normalize(expr.span, rustc_middle::ty::Unnormalized::new_wip(item_type)); + + let can_collect = self + .infcx + .type_implements_trait(from_iterator_trait_id, [expected, item_type], self.param_env) + .may_apply(); + + if can_collect { + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + format!( + "consider using `.collect()` to convert the `Iterator` into a `{expected}`" + ), + ".collect()", + rustc_errors::Applicability::MaybeIncorrect, + ); + return true; + } + + false + } + pub(crate) fn suggest_remove_last_method_call( &self, err: &mut Diag<'_>, diff --git a/tests/ui/suggestions/suggest-collect.rs b/tests/ui/suggestions/suggest-collect.rs new file mode 100644 index 0000000000000..44e8909fca20f --- /dev/null +++ b/tests/ui/suggestions/suggest-collect.rs @@ -0,0 +1,16 @@ +fn main() { + let _x: String = "hello".chars().map(|c| c); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `String` + + let _y: Vec = vec![1, 2, 3].into_iter().map(|x| x); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `Vec` + + let res: Result, _> = ["1", "2"].into_iter().map(|s| s.parse::()); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `Result, _>` + let (a, b): (Vec, Vec) = vec![1, 2].into_iter().map(|x| (x, x)); + //~^ ERROR mismatched types + //~| HELP consider using `.collect()` to convert the `Iterator` into a `(Vec, Vec)` +} diff --git a/tests/ui/suggestions/suggest-collect.stderr b/tests/ui/suggestions/suggest-collect.stderr new file mode 100644 index 0000000000000..a7bca2bbcaa7b --- /dev/null +++ b/tests/ui/suggestions/suggest-collect.stderr @@ -0,0 +1,63 @@ +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:2:22 + | +LL | let _x: String = "hello".chars().map(|c| c); + | ------ ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected struct `String` + found struct `Map, {closure@$DIR/suggest-collect.rs:2:42: 2:45}>` +help: consider using `.collect()` to convert the `Iterator` into a `String` + | +LL | let _x: String = "hello".chars().map(|c| c).collect(); + | ++++++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:6:24 + | +LL | let _y: Vec = vec![1, 2, 3].into_iter().map(|x| x); + | -------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Vec`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected struct `Vec` + found struct `Map, {closure@$DIR/suggest-collect.rs:6:54: 6:57}>` +help: consider using `.collect()` to convert the `Iterator` into a `Vec` + | +LL | let _y: Vec = vec![1, 2, 3].into_iter().map(|x| x).collect(); + | ++++++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:10:36 + | +LL | let res: Result, _> = ["1", "2"].into_iter().map(|s| s.parse::()); + | ------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result, _>`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected enum `Result, _>` + found struct `Map, {closure@$DIR/suggest-collect.rs:10:63: 10:66}>` +help: consider using `.collect()` to convert the `Iterator` into a `Result, _>` + | +LL | let res: Result, _> = ["1", "2"].into_iter().map(|s| s.parse::()).collect(); + | ++++++++++ + +error[E0308]: mismatched types + --> $DIR/suggest-collect.rs:13:40 + | +LL | let (a, b): (Vec, Vec) = vec![1, 2].into_iter().map(|x| (x, x)); + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `(Vec, Vec)`, found `Map, {closure@...}>` + | | + | expected due to this + | + = note: expected tuple `(Vec, Vec)` + found struct `Map, {closure@$DIR/suggest-collect.rs:13:67: 13:70}>` +help: consider using `.collect()` to convert the `Iterator` into a `(Vec, Vec)` + | +LL | let (a, b): (Vec, Vec) = vec![1, 2].into_iter().map(|x| (x, x)).collect(); + | ++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From e1941ffee672efea442b269011d6b40be6dbbff9 Mon Sep 17 00:00:00 2001 From: Thiago Felipe Alves do Carmo <63806038+thiago-fealves@users.noreply.github.com> Date: Mon, 4 May 2026 15:47:45 +0000 Subject: [PATCH 02/16] Update compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs Co-authored-by: Qai Juang --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1ce004e11e996..77aa9fb3daab8 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -265,11 +265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let expected = self.resolve_vars_if_possible(expected_type); let found = self.resolve_vars_if_possible(found_type); - if expected.references_error() || found.references_error() { - return false; - } - - if expected.is_unit() { + if expected.references_error() || found.references_error() || expected.is_unit() { return false; } From ecf01910d554f37fcc101c48fe43b1d0f749e5db Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 15 May 2026 17:43:09 +0800 Subject: [PATCH 03/16] Avoid rustfix suggestions for macro-expanded unused imports --- compiler/rustc_resolve/src/check_unused.rs | 15 ++++++++----- compiler/rustc_resolve/src/errors.rs | 2 +- ...ed-import-in-macro-expansion-rustfix.fixed | 22 +++++++++++++++++++ ...nused-import-in-macro-expansion-rustfix.rs | 22 +++++++++++++++++++ 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed create mode 100644 tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 8ab0087ae6158..efa6e08a34fa4 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -486,6 +486,9 @@ impl Resolver<'_, '_> { let remove_whole_use = remove_spans.len() == 1 && remove_spans[0] == unused.item_span; let num_to_remove = ms.primary_spans().len(); + // Only offer rustfix suggestions for spans that point at directly editable code. + let can_suggest_removal = + remove_spans.iter().all(|span| span.can_be_used_for_suggestions()); // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]` // attribute; however, if not, suggest adding the attribute. There is no way to @@ -516,11 +519,13 @@ impl Resolver<'_, '_> { unused.use_tree_id, ms, move |dcx, level, sess| { - let sugg = if remove_whole_use { - errors::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] } - } else { - errors::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove } - }; + let sugg = can_suggest_removal.then(|| { + if remove_whole_use { + errors::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] } + } else { + errors::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove } + } + }); let test_module_span = test_module_span.map(|span| { sess.downcast_ref::() .expect("expected a `Session`") diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index 342484a8c0d51..4bcc7a5eb02e8 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1742,7 +1742,7 @@ pub(crate) struct ElidedLifetimesInPaths { )] pub(crate) struct UnusedImports { #[subdiagnostic] - pub sugg: UnusedImportsSugg, + pub sugg: Option, #[help("if this is a test module, consider adding a `#[cfg(test)]` to the containing module")] pub test_module_span: Option, diff --git a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed new file mode 100644 index 0000000000000..00cc0238688d9 --- /dev/null +++ b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed @@ -0,0 +1,22 @@ +//@ edition:2024 +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ check-pass + +mod m { + macro_rules! define_new_macro { + ($name:ident) => { + macro_rules! $name { + () => {}; + } + pub(crate) use $name; + }; + } + + define_new_macro!(item_used); + define_new_macro!(item_unused); +} + +fn main() { + m::item_used!(); +} diff --git a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs new file mode 100644 index 0000000000000..00cc0238688d9 --- /dev/null +++ b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs @@ -0,0 +1,22 @@ +//@ edition:2024 +//@ run-rustfix +//@ rustfix-only-machine-applicable +//@ check-pass + +mod m { + macro_rules! define_new_macro { + ($name:ident) => { + macro_rules! $name { + () => {}; + } + pub(crate) use $name; + }; + } + + define_new_macro!(item_used); + define_new_macro!(item_unused); +} + +fn main() { + m::item_used!(); +} From 9d769128a75769e6930db0f7bfae2bdbc4106adb Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 15 May 2026 17:49:11 +0800 Subject: [PATCH 04/16] comment for issue id --- tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed | 1 + tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed index 00cc0238688d9..a60805eb3287d 100644 --- a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed +++ b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed @@ -1,3 +1,4 @@ +// Regression test for //@ edition:2024 //@ run-rustfix //@ rustfix-only-machine-applicable diff --git a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs index 00cc0238688d9..a60805eb3287d 100644 --- a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs +++ b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs @@ -1,3 +1,4 @@ +// Regression test for //@ edition:2024 //@ run-rustfix //@ rustfix-only-machine-applicable From 209ee9daac941699f8043fa24c9db68e084f6699 Mon Sep 17 00:00:00 2001 From: cijiugechu Date: Fri, 15 May 2026 17:49:33 +0800 Subject: [PATCH 05/16] use edition 2021 --- tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed | 2 +- tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed index a60805eb3287d..3b7c8051122fc 100644 --- a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed +++ b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.fixed @@ -1,5 +1,5 @@ // Regression test for -//@ edition:2024 +//@ edition:2021 //@ run-rustfix //@ rustfix-only-machine-applicable //@ check-pass diff --git a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs index a60805eb3287d..3b7c8051122fc 100644 --- a/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs +++ b/tests/ui/imports/unused-import-in-macro-expansion-rustfix.rs @@ -1,5 +1,5 @@ // Regression test for -//@ edition:2024 +//@ edition:2021 //@ run-rustfix //@ rustfix-only-machine-applicable //@ check-pass From 5f2e455a1cf7cad807effb6f7be51f75180934f9 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 15 May 2026 10:46:35 -0700 Subject: [PATCH 06/16] rustdoc: add test case for `-Drustdoc::` CLI param This works, but I couldn't find any test cases for it. --- ...rr => unescaped_backticks.deny_cli.stderr} | 134 +++++++++--------- tests/rustdoc-ui/lints/unescaped_backticks.rs | 133 ++++++++--------- 2 files changed, 133 insertions(+), 134 deletions(-) rename tests/rustdoc-ui/lints/{unescaped_backticks.stderr => unescaped_backticks.deny_cli.stderr} (91%) diff --git a/tests/rustdoc-ui/lints/unescaped_backticks.stderr b/tests/rustdoc-ui/lints/unescaped_backticks.deny_cli.stderr similarity index 91% rename from tests/rustdoc-ui/lints/unescaped_backticks.stderr rename to tests/rustdoc-ui/lints/unescaped_backticks.deny_cli.stderr index 1bcb88e108f20..3424a355b506b 100644 --- a/tests/rustdoc-ui/lints/unescaped_backticks.stderr +++ b/tests/rustdoc-ui/lints/unescaped_backticks.deny_cli.stderr @@ -1,14 +1,10 @@ error: unescaped backtick - --> $DIR/unescaped_backticks.rs:187:70 + --> $DIR/unescaped_backticks.rs:190:70 | LL | /// if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect = | ^ | -note: the lint level is defined here - --> $DIR/unescaped_backticks.rs:1:9 - | -LL | #![deny(rustdoc::unescaped_backticks)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: requested on the command line with `-D rustdoc::unescaped-backticks` help: the closing backtick of an inline code may be missing | LL | /// "runtime", phase = "optimized")]` if you don't. @@ -19,7 +15,7 @@ LL | /// if you want your MIR to be modified by the full MIR pipeline, or \`#![c | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:232:13 + --> $DIR/unescaped_backticks.rs:235:13 | LL | //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")] | ^ @@ -34,7 +30,7 @@ LL | //! \`#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kin | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:237:13 + --> $DIR/unescaped_backticks.rs:240:13 | LL | /// `cfg=... | ^ @@ -49,7 +45,7 @@ LL | /// \`cfg=... | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:241:42 + --> $DIR/unescaped_backticks.rs:244:42 | LL | /// `cfg=... and not `#[cfg_attr]` | ^ @@ -64,7 +60,7 @@ LL | /// `cfg=... and not `#[cfg_attr]\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:193:93 + --> $DIR/unescaped_backticks.rs:196:93 | LL | /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given `msg to | ^ @@ -79,7 +75,7 @@ LL | /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:202:34 + --> $DIR/unescaped_backticks.rs:205:34 | LL | /// in `nt_to_tokenstream` | ^ @@ -94,7 +90,7 @@ LL | /// in `nt_to_tokenstream\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:208:62 + --> $DIR/unescaped_backticks.rs:211:62 | LL | /// that `Option` only takes up 4 bytes, because `newtype_index! reserves | ^ @@ -109,7 +105,7 @@ LL | /// that `Option` only takes up 4 bytes, because \`newtype_inde | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:216:52 + --> $DIR/unescaped_backticks.rs:219:52 | LL | /// also avoids the need to import `OpenOptions`. | ^ @@ -124,7 +120,7 @@ LL | /// also avoids the need to import `OpenOptions\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:221:47 + --> $DIR/unescaped_backticks.rs:224:47 | LL | /// `ChunkedBitSet`. Has no effect if `row` does not exist. | ^ @@ -139,7 +135,7 @@ LL | /// `ChunkedBitSet`. Has no effect if `row\` does not exist. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:247:12 + --> $DIR/unescaped_backticks.rs:250:12 | LL | /// RWU`s can get very large, so it uses a more compact representation. | ^ @@ -154,7 +150,7 @@ LL | /// RWU\`s can get very large, so it uses a more compact representation | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:254:15 + --> $DIR/unescaped_backticks.rs:257:15 | LL | /// in `U2`. | ^ @@ -169,7 +165,7 @@ LL | /// in `U2\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:271:42 + --> $DIR/unescaped_backticks.rs:274:42 | LL | /// because it contains `[type error]`. Yuck! (See issue #29857 for | ^ @@ -184,7 +180,7 @@ LL | /// because it contains `[type error]\`. Yuck! (See issue #29857 for | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:281:53 + --> $DIR/unescaped_backticks.rs:284:53 | LL | /// well as the second instance of `A: AutoTrait`) to suppress | ^ @@ -199,7 +195,7 @@ LL | /// well as the second instance of `A: AutoTrait\`) to suppress | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:291:40 + --> $DIR/unescaped_backticks.rs:294:40 | LL | /// `'a` with `'b` and not `'static`. But it will have to do for | ^ @@ -211,7 +207,7 @@ LL | /// `'a` with `'b` and not `'static\`. But it will have to do for | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:300:54 + --> $DIR/unescaped_backticks.rs:303:54 | LL | /// `None`. Otherwise, it will return `Some(Dispatch)`. | ^ @@ -226,7 +222,7 @@ LL | /// `None`. Otherwise, it will return `Some(Dispatch)\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:304:13 + --> $DIR/unescaped_backticks.rs:307:13 | LL | /// or `None` if it isn't. | ^ @@ -238,7 +234,7 @@ LL | /// or `None\` if it isn't. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:308:14 + --> $DIR/unescaped_backticks.rs:311:14 | LL | /// `on_event` should be called. | ^ @@ -253,7 +249,7 @@ LL | /// `on_event\` should be called. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:313:29 + --> $DIR/unescaped_backticks.rs:316:29 | LL | /// [`rebuild_interest_cache`][rebuild] is called after the value of the max | ^ @@ -268,7 +264,7 @@ LL | /// [`rebuild_interest_cache\`][rebuild] is called after the value of the m | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:323:5 + --> $DIR/unescaped_backticks.rs:326:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -284,7 +280,7 @@ LL | | /// level changes. to this: `None`. Otherwise, it will return `Some(Dispatch)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:323:5 + --> $DIR/unescaped_backticks.rs:326:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -298,7 +294,7 @@ LL | | /// level changes. to this: or `None\` if it isn't. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:323:5 + --> $DIR/unescaped_backticks.rs:326:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -314,7 +310,7 @@ LL | | /// level changes. to this: `on_event\` should be called. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:323:5 + --> $DIR/unescaped_backticks.rs:326:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -330,7 +326,7 @@ LL | | /// level changes. to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max error: unescaped backtick - --> $DIR/unescaped_backticks.rs:349:56 + --> $DIR/unescaped_backticks.rs:352:56 | LL | /// instead and use [`CloneCounterObserver::counter`] to increment. | ^ @@ -342,7 +338,7 @@ LL | /// instead and use [`CloneCounterObserver::counter\`] to increment. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:12:5 + --> $DIR/unescaped_backticks.rs:15:5 | LL | /// ` | ^ @@ -354,7 +350,7 @@ LL | /// \` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:19:7 + --> $DIR/unescaped_backticks.rs:22:7 | LL | /// \` | ^ @@ -369,7 +365,7 @@ LL | /// \\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:26:6 + --> $DIR/unescaped_backticks.rs:29:6 | LL | /// [`link1] | ^ @@ -384,7 +380,7 @@ LL | /// [\`link1] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:30:11 + --> $DIR/unescaped_backticks.rs:33:11 | LL | /// [link2`] | ^ @@ -399,7 +395,7 @@ LL | /// [link2\`] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:34:6 + --> $DIR/unescaped_backticks.rs:37:6 | LL | /// [`link_long](link_long) | ^ @@ -414,7 +410,7 @@ LL | /// [\`link_long](link_long) | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:38:6 + --> $DIR/unescaped_backticks.rs:41:6 | LL | /// [`broken-link] | ^ @@ -429,7 +425,7 @@ LL | /// [\`broken-link] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:45:8 + --> $DIR/unescaped_backticks.rs:48:8 | LL | /// | ^ @@ -444,7 +440,7 @@ LL | /// | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:55:6 + --> $DIR/unescaped_backticks.rs:58:6 | LL | /// 🦀`🦀 | ^ @@ -463,7 +459,7 @@ LL | /// 🦀\`🦀 | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:59:5 + --> $DIR/unescaped_backticks.rs:62:5 | LL | /// `foo( | ^ @@ -478,7 +474,7 @@ LL | /// \`foo( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:65:14 + --> $DIR/unescaped_backticks.rs:68:14 | LL | /// `foo `bar` | ^ @@ -493,7 +489,7 @@ LL | /// `foo `bar\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:71:5 + --> $DIR/unescaped_backticks.rs:74:5 | LL | /// `foo( | ^ @@ -508,7 +504,7 @@ LL | /// \`foo( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:76:83 + --> $DIR/unescaped_backticks.rs:79:83 | LL | /// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`. | ^ @@ -523,7 +519,7 @@ LL | /// Addition is commutative, which means that add(a, b)` is the same as `ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:80:51 + --> $DIR/unescaped_backticks.rs:83:51 | LL | /// or even to add a number `n` to 42 (`add(42, b)`)! | ^ @@ -538,7 +534,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, b)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:84:83 + --> $DIR/unescaped_backticks.rs:87:83 | LL | /// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`. | ^ @@ -553,7 +549,7 @@ LL | /// Addition is commutative, which means that `add(a, b) is the same as `ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:88:51 + --> $DIR/unescaped_backticks.rs:91:51 | LL | /// or even to add a number `n` to 42 (`add(42, n)`)! | ^ @@ -568,7 +564,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:92:83 + --> $DIR/unescaped_backticks.rs:95:83 | LL | /// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`. | ^ @@ -583,7 +579,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:96:50 + --> $DIR/unescaped_backticks.rs:99:50 | LL | /// or even to add a number `n` to 42 (add(42, n)`)! | ^ @@ -598,7 +594,7 @@ LL | /// or even to add a number `n` to 42 (add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:100:74 + --> $DIR/unescaped_backticks.rs:103:74 | LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a). | ^ @@ -613,7 +609,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as \` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:104:51 + --> $DIR/unescaped_backticks.rs:107:51 | LL | /// or even to add a number `n` to 42 (`add(42, n)`)! | ^ @@ -628,7 +624,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:108:10 + --> $DIR/unescaped_backticks.rs:111:10 | LL | #[doc = "`"] | ^ @@ -639,7 +635,7 @@ LL | #[doc = "`"] to this: \` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:115:26 + --> $DIR/unescaped_backticks.rs:118:26 | LL | #[doc = concat!("\\", "`")] | ^ @@ -652,7 +648,7 @@ LL | #[doc = concat!("\\", "`")] to this: \\` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:119:9 + --> $DIR/unescaped_backticks.rs:122:9 | LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -665,7 +661,7 @@ LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same a to this: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:123:9 + --> $DIR/unescaped_backticks.rs:126:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -678,7 +674,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same a to this: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:127:9 + --> $DIR/unescaped_backticks.rs:130:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -691,7 +687,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same to this: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:131:9 + --> $DIR/unescaped_backticks.rs:134:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -704,7 +700,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same to this: Addition is commutative, which means that `add(a, b)` is the same as \`add(b, a). error: unescaped backtick - --> $DIR/unescaped_backticks.rs:136:5 + --> $DIR/unescaped_backticks.rs:139:5 | LL | /// `foo | ^ @@ -719,7 +715,7 @@ LL | /// \`foo | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:140:7 + --> $DIR/unescaped_backticks.rs:143:7 | LL | /// # `(heading | ^ @@ -734,7 +730,7 @@ LL | /// # \`(heading | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:142:17 + --> $DIR/unescaped_backticks.rs:145:17 | LL | /// ## heading2)` | ^ @@ -749,7 +745,7 @@ LL | /// ## heading2)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:145:11 + --> $DIR/unescaped_backticks.rs:148:11 | LL | /// multi `( | ^ @@ -764,7 +760,7 @@ LL | /// multi \`( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:151:10 + --> $DIR/unescaped_backticks.rs:154:10 | LL | /// para)`(graph | ^ @@ -783,7 +779,7 @@ LL | /// para)\`(graph | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:154:10 + --> $DIR/unescaped_backticks.rs:157:10 | LL | /// para)`(graph2 | ^ @@ -802,7 +798,7 @@ LL | /// para)\`(graph2 | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:157:12 + --> $DIR/unescaped_backticks.rs:160:12 | LL | /// 1. foo)` | ^ @@ -817,7 +813,7 @@ LL | /// 1. foo)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:159:8 + --> $DIR/unescaped_backticks.rs:162:8 | LL | /// 2. `(bar | ^ @@ -832,7 +828,7 @@ LL | /// 2. \`(bar | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:161:11 + --> $DIR/unescaped_backticks.rs:164:11 | LL | /// * baz)` | ^ @@ -847,7 +843,7 @@ LL | /// * baz)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:163:7 + --> $DIR/unescaped_backticks.rs:166:7 | LL | /// * `(quux | ^ @@ -862,7 +858,7 @@ LL | /// * \`(quux | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:166:5 + --> $DIR/unescaped_backticks.rs:169:5 | LL | /// `#![this_is_actually_an_image(and(not), an = "attribute")] | ^ @@ -877,7 +873,7 @@ LL | /// \`#![this_is_actually_an_image(and(not), an = "attribute")] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:169:62 + --> $DIR/unescaped_backticks.rs:172:62 | LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]` | ^ @@ -892,7 +888,7 @@ LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:174:7 + --> $DIR/unescaped_backticks.rs:177:7 | LL | /// | `table( | )head` | | ^ @@ -907,7 +903,7 @@ LL | /// | \`table( | )head` | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:174:22 + --> $DIR/unescaped_backticks.rs:177:22 | LL | /// | `table( | )head` | | ^ @@ -922,7 +918,7 @@ LL | /// | `table( | )head\` | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:178:12 + --> $DIR/unescaped_backticks.rs:181:12 | LL | /// | table`( | )`body | | ^ @@ -937,7 +933,7 @@ LL | /// | table\`( | )`body | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:178:18 + --> $DIR/unescaped_backticks.rs:181:18 | LL | /// | table`( | )`body | | ^ diff --git a/tests/rustdoc-ui/lints/unescaped_backticks.rs b/tests/rustdoc-ui/lints/unescaped_backticks.rs index 8d6239296bf78..a0c25ca2eaf03 100644 --- a/tests/rustdoc-ui/lints/unescaped_backticks.rs +++ b/tests/rustdoc-ui/lints/unescaped_backticks.rs @@ -1,4 +1,7 @@ -#![deny(rustdoc::unescaped_backticks)] +//@revisions: deny_cli allow_cli +//@[deny_cli] compile-flags: -Drustdoc::unescaped_backticks +//@[allow_cli] compile-flags: -Arustdoc::unescaped_backticks +//@[allow_cli] check-pass #![allow(rustdoc::broken_intra_doc_links)] #![allow(rustdoc::invalid_html_tags)] #![allow(rustdoc::redundant_explicit_links)] @@ -10,40 +13,40 @@ pub fn empty() {} pub fn empty2() {} /// ` -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn single() {} /// \` pub fn escaped() {} /// \\` -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn not_escaped() {} /// \\\` pub fn not_not_escaped() {} /// [`link1] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn link1() {} /// [link2`] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn link2() {} /// [`link_long](link_long) -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn link_long() {} /// [`broken-link] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn broken_link() {} /// pub fn url() {} /// -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn not_url() {} ///

`

@@ -53,131 +56,131 @@ pub fn html_tag() {} pub fn html_escape() {} /// 🦀`🦀 -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn unicode() {} /// `foo( -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// paragraph pub fn paragraph() {} /// `foo `bar` -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// paragraph pub fn paragraph2() {} /// `foo( -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// not paragraph pub fn not_paragraph() {} /// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`. -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// You could use this function to add 42 to a number `n` (add(n, 42)`), /// or even to add a number `n` to 42 (`add(42, b)`)! -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn add1(a: i32, b: i32) -> i32 { a + b } /// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`. -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// You could use this function to add 42 to a number `n` (`add(n, 42)), /// or even to add a number `n` to 42 (`add(42, n)`)! -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn add2(a: i32, b: i32) -> i32 { a + b } /// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`. -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// You could use this function to add 42 to a number `n` (`add(n, 42)`), /// or even to add a number `n` to 42 (add(42, n)`)! -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn add3(a: i32, b: i32) -> i32 { a + b } /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a). -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// You could use this function to add 42 to a number `n` (`add(n, 42)), /// or even to add a number `n` to 42 (`add(42, n)`)! -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn add4(a: i32, b: i32) -> i32 { a + b } #[doc = "`"] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn attr() {} #[doc = concat!("\\", "`")] pub fn attr_escaped() {} #[doc = concat!("\\\\", "`")] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn attr_not_escaped() {} #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn attr_add1(a: i32, b: i32) -> i32 { a + b } #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn attr_add2(a: i32, b: i32) -> i32 { a + b } #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn attr_add3(a: i32, b: i32) -> i32 { a + b } #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn attr_add4(a: i32, b: i32) -> i32 { a + b } /// ``double backticks`` /// `foo -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick pub fn double_backticks() {} /// # `(heading -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// ## heading2)` -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// multi `( -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// line /// ) heading /// = /// /// para)`(graph -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// para)`(graph2 -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// 1. foo)` -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// 2. `(bar -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// * baz)` -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// * `(quux -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// `#![this_is_actually_an_image(and(not), an = "attribute")] -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// #![this_is_actually_an_image(and(not), an = "attribute")]` -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// [this_is_actually_an_image(and(not), an = "attribute")]: `.png /// /// | `table( | )head` | -//~^ ERROR unescaped backtick -//~| ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick +//[deny_cli]~| ERROR unescaped backtick /// |---------|--------| /// | table`( | )`body | -//~^ ERROR unescaped backtick -//~| ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick +//[deny_cli]~| ERROR unescaped backtick pub fn complicated_markdown() {} /// The `custom_mir` attribute tells the compiler to treat the function as being custom MIR. This @@ -185,13 +188,13 @@ pub fn complicated_markdown() {} /// another function. The `dialect` and `phase` parameters indicate which [version of MIR][dialect /// docs] you are inserting here. Generally you'll want to use `#![custom_mir(dialect = "built")]` /// if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect = -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// "runtime", phase = "optimized")] if you don't. pub mod mir {} pub mod rustc { /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given `msg to - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick /// ensure it gets used. pub fn ty_error_with_message() {} @@ -200,13 +203,13 @@ pub mod rustc { /// if we parsed no predicates (e.g. `struct Foo where {} /// This allows us to accurately pretty-print /// in `nt_to_tokenstream` - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick pub has_where_token: bool, } /// A symbol is an interned or gensymed string. The use of `newtype_index!` means /// that `Option` only takes up 4 bytes, because `newtype_index! reserves - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick /// the last 256 values for tagging purposes. pub struct Symbol(); @@ -214,12 +217,12 @@ pub mod rustc { /// readable code. Instead of `OpenOptions::new().read(true).open("foo.txt")` /// you can write `File::with_options().read(true).open("foo.txt"). This /// also avoids the need to import `OpenOptions`. - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick pub fn with_options() {} /// Subtracts `set from `row`. `set` can be either `BitSet` or /// `ChunkedBitSet`. Has no effect if `row` does not exist. - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick /// /// Returns true if the row was changed. pub fn subtract_row() {} @@ -230,29 +233,29 @@ pub mod rustc { //! perturb the reuse results. //! //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")] - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick //! allows for doing a more fine-grained check to see if pre- or post-lto data //! was re-used. /// `cfg=... - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick pub fn foo() {} /// `cfg=... and not `#[cfg_attr]` - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick pub fn bar() {} } /// Conceptually, this is like a `Vec>`. But the number of /// RWU`s can get very large, so it uses a more compact representation. - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick pub struct RWUTable {} /// Like [Self::canonicalize_query], but preserves distinct universes. For /// example, canonicalizing `&'?0: Trait<'?1>`, where `'?0` is in `U1` and /// `'?1` is in `U3` would be canonicalized to have ?0` in `U1` and `'?1` /// in `U2`. - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick /// /// This is used for Chalk integration. pub fn canonicalize_query_preserving_universes() {} @@ -269,7 +272,7 @@ pub mod rustc { /// ` as Trait>::Foo`. We are supposed to report /// an error for this obligation, but we legitimately should not, /// because it contains `[type error]`. Yuck! (See issue #29857 for - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick /// one case where this arose.) pub fn normalize_to_error() {} @@ -279,7 +282,7 @@ pub mod rustc { /// encountered a problem (later on) with `A: AutoTrait. So we /// currently set a flag on the stack node for `B: AutoTrait` (as /// well as the second instance of `A: AutoTrait`) to suppress - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick /// caching. pub struct TraitObligationStack; @@ -289,7 +292,7 @@ pub mod rustc { /// actually stricter than necessary: ideally, we'd support bounds /// like `for<'a: 'b`>` that might then allow us to approximate /// `'a` with `'b` and not `'static`. But it will have to do for - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick /// now. pub fn add_incompatible_universe(){} } @@ -298,20 +301,20 @@ pub mod rustc { /// which returns an `Option`. If all [`Dispatch`] clones that point /// at the `Subscriber` have been dropped, [`WeakDispatch::upgrade`] will return /// `None`. Otherwise, it will return `Some(Dispatch)`. -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// Returns some reference to this `[`Subscriber`] value if it is of type `T`, /// or `None` if it isn't. -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// Called before the filtered [`Layer]'s [`on_event`], to determine if /// `on_event` should be called. -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// /// Therefore, if the `Filter will change the value returned by this /// method, it is responsible for ensuring that /// [`rebuild_interest_cache`][rebuild] is called after the value of the max -//~^ ERROR unescaped backtick +//[deny_cli]~^ ERROR unescaped backtick /// level changes. pub mod tracing {} @@ -321,10 +324,10 @@ macro_rules! id { id! { /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], - //~^ ERROR unescaped backtick - //~| ERROR unescaped backtick - //~| ERROR unescaped backtick - //~| ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick + //[deny_cli]~| ERROR unescaped backtick + //[deny_cli]~| ERROR unescaped backtick + //[deny_cli]~| ERROR unescaped backtick /// which returns an `Option`. If all [`Dispatch`] clones that point /// at the `Subscriber` have been dropped, [`WeakDispatch::upgrade`] will return /// `None`. Otherwise, it will return `Some(Dispatch)`. @@ -347,7 +350,7 @@ pub mod trillium_server_common { /// One-indexed, because the first CloneCounter is included. If you don't /// want the original to count, construct a [``CloneCounterObserver`] /// instead and use [`CloneCounterObserver::counter`] to increment. - //~^ ERROR unescaped backtick + //[deny_cli]~^ ERROR unescaped backtick pub struct CloneCounter; /// This is used by the above. From 0344a0226199f732da17a92f9afc02fc951a5daf Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Fri, 15 May 2026 11:13:16 -0700 Subject: [PATCH 07/16] rustdoc: add test case for `--cap-lints=allow` --- .../lints/unescaped_backticks.deny_cli.stderr | 128 +++++++++--------- tests/rustdoc-ui/lints/unescaped_backticks.rs | 4 +- 2 files changed, 67 insertions(+), 65 deletions(-) diff --git a/tests/rustdoc-ui/lints/unescaped_backticks.deny_cli.stderr b/tests/rustdoc-ui/lints/unescaped_backticks.deny_cli.stderr index 3424a355b506b..6a2396ea1f9d6 100644 --- a/tests/rustdoc-ui/lints/unescaped_backticks.deny_cli.stderr +++ b/tests/rustdoc-ui/lints/unescaped_backticks.deny_cli.stderr @@ -1,5 +1,5 @@ error: unescaped backtick - --> $DIR/unescaped_backticks.rs:190:70 + --> $DIR/unescaped_backticks.rs:192:70 | LL | /// if you want your MIR to be modified by the full MIR pipeline, or `#![custom_mir(dialect = | ^ @@ -15,7 +15,7 @@ LL | /// if you want your MIR to be modified by the full MIR pipeline, or \`#![c | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:235:13 + --> $DIR/unescaped_backticks.rs:237:13 | LL | //! `#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kind="post-lto")] | ^ @@ -30,7 +30,7 @@ LL | //! \`#![rustc_expected_cgu_reuse(module="spike", cfg="rpass2", kin | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:240:13 + --> $DIR/unescaped_backticks.rs:242:13 | LL | /// `cfg=... | ^ @@ -45,7 +45,7 @@ LL | /// \`cfg=... | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:244:42 + --> $DIR/unescaped_backticks.rs:246:42 | LL | /// `cfg=... and not `#[cfg_attr]` | ^ @@ -60,7 +60,7 @@ LL | /// `cfg=... and not `#[cfg_attr]\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:196:93 + --> $DIR/unescaped_backticks.rs:198:93 | LL | /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug` with the given `msg to | ^ @@ -75,7 +75,7 @@ LL | /// Constructs a `TyKind::Error` type and registers a `span_delayed_bug | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:205:34 + --> $DIR/unescaped_backticks.rs:207:34 | LL | /// in `nt_to_tokenstream` | ^ @@ -90,7 +90,7 @@ LL | /// in `nt_to_tokenstream\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:211:62 + --> $DIR/unescaped_backticks.rs:213:62 | LL | /// that `Option` only takes up 4 bytes, because `newtype_index! reserves | ^ @@ -105,7 +105,7 @@ LL | /// that `Option` only takes up 4 bytes, because \`newtype_inde | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:219:52 + --> $DIR/unescaped_backticks.rs:221:52 | LL | /// also avoids the need to import `OpenOptions`. | ^ @@ -120,7 +120,7 @@ LL | /// also avoids the need to import `OpenOptions\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:224:47 + --> $DIR/unescaped_backticks.rs:226:47 | LL | /// `ChunkedBitSet`. Has no effect if `row` does not exist. | ^ @@ -135,7 +135,7 @@ LL | /// `ChunkedBitSet`. Has no effect if `row\` does not exist. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:250:12 + --> $DIR/unescaped_backticks.rs:252:12 | LL | /// RWU`s can get very large, so it uses a more compact representation. | ^ @@ -150,7 +150,7 @@ LL | /// RWU\`s can get very large, so it uses a more compact representation | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:257:15 + --> $DIR/unescaped_backticks.rs:259:15 | LL | /// in `U2`. | ^ @@ -165,7 +165,7 @@ LL | /// in `U2\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:274:42 + --> $DIR/unescaped_backticks.rs:276:42 | LL | /// because it contains `[type error]`. Yuck! (See issue #29857 for | ^ @@ -180,7 +180,7 @@ LL | /// because it contains `[type error]\`. Yuck! (See issue #29857 for | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:284:53 + --> $DIR/unescaped_backticks.rs:286:53 | LL | /// well as the second instance of `A: AutoTrait`) to suppress | ^ @@ -195,7 +195,7 @@ LL | /// well as the second instance of `A: AutoTrait\`) to suppress | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:294:40 + --> $DIR/unescaped_backticks.rs:296:40 | LL | /// `'a` with `'b` and not `'static`. But it will have to do for | ^ @@ -207,7 +207,7 @@ LL | /// `'a` with `'b` and not `'static\`. But it will have to do for | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:303:54 + --> $DIR/unescaped_backticks.rs:305:54 | LL | /// `None`. Otherwise, it will return `Some(Dispatch)`. | ^ @@ -222,7 +222,7 @@ LL | /// `None`. Otherwise, it will return `Some(Dispatch)\`. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:307:13 + --> $DIR/unescaped_backticks.rs:309:13 | LL | /// or `None` if it isn't. | ^ @@ -234,7 +234,7 @@ LL | /// or `None\` if it isn't. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:311:14 + --> $DIR/unescaped_backticks.rs:313:14 | LL | /// `on_event` should be called. | ^ @@ -249,7 +249,7 @@ LL | /// `on_event\` should be called. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:316:29 + --> $DIR/unescaped_backticks.rs:318:29 | LL | /// [`rebuild_interest_cache`][rebuild] is called after the value of the max | ^ @@ -264,7 +264,7 @@ LL | /// [`rebuild_interest_cache\`][rebuild] is called after the value of the m | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:326:5 + --> $DIR/unescaped_backticks.rs:328:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -280,7 +280,7 @@ LL | | /// level changes. to this: `None`. Otherwise, it will return `Some(Dispatch)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:326:5 + --> $DIR/unescaped_backticks.rs:328:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -294,7 +294,7 @@ LL | | /// level changes. to this: or `None\` if it isn't. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:326:5 + --> $DIR/unescaped_backticks.rs:328:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -310,7 +310,7 @@ LL | | /// level changes. to this: `on_event\` should be called. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:326:5 + --> $DIR/unescaped_backticks.rs:328:5 | LL | / /// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`], ... | @@ -326,7 +326,7 @@ LL | | /// level changes. to this: [`rebuild_interest_cache\`][rebuild] is called after the value of the max error: unescaped backtick - --> $DIR/unescaped_backticks.rs:352:56 + --> $DIR/unescaped_backticks.rs:354:56 | LL | /// instead and use [`CloneCounterObserver::counter`] to increment. | ^ @@ -338,7 +338,7 @@ LL | /// instead and use [`CloneCounterObserver::counter\`] to increment. | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:15:5 + --> $DIR/unescaped_backticks.rs:17:5 | LL | /// ` | ^ @@ -350,7 +350,7 @@ LL | /// \` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:22:7 + --> $DIR/unescaped_backticks.rs:24:7 | LL | /// \` | ^ @@ -365,7 +365,7 @@ LL | /// \\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:29:6 + --> $DIR/unescaped_backticks.rs:31:6 | LL | /// [`link1] | ^ @@ -380,7 +380,7 @@ LL | /// [\`link1] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:33:11 + --> $DIR/unescaped_backticks.rs:35:11 | LL | /// [link2`] | ^ @@ -395,7 +395,7 @@ LL | /// [link2\`] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:37:6 + --> $DIR/unescaped_backticks.rs:39:6 | LL | /// [`link_long](link_long) | ^ @@ -410,7 +410,7 @@ LL | /// [\`link_long](link_long) | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:41:6 + --> $DIR/unescaped_backticks.rs:43:6 | LL | /// [`broken-link] | ^ @@ -425,7 +425,7 @@ LL | /// [\`broken-link] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:48:8 + --> $DIR/unescaped_backticks.rs:50:8 | LL | /// | ^ @@ -440,7 +440,7 @@ LL | /// | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:58:6 + --> $DIR/unescaped_backticks.rs:60:6 | LL | /// 🦀`🦀 | ^ @@ -459,7 +459,7 @@ LL | /// 🦀\`🦀 | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:62:5 + --> $DIR/unescaped_backticks.rs:64:5 | LL | /// `foo( | ^ @@ -474,7 +474,7 @@ LL | /// \`foo( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:68:14 + --> $DIR/unescaped_backticks.rs:70:14 | LL | /// `foo `bar` | ^ @@ -489,7 +489,7 @@ LL | /// `foo `bar\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:74:5 + --> $DIR/unescaped_backticks.rs:76:5 | LL | /// `foo( | ^ @@ -504,7 +504,7 @@ LL | /// \`foo( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:79:83 + --> $DIR/unescaped_backticks.rs:81:83 | LL | /// Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`. | ^ @@ -519,7 +519,7 @@ LL | /// Addition is commutative, which means that add(a, b)` is the same as `ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:83:51 + --> $DIR/unescaped_backticks.rs:85:51 | LL | /// or even to add a number `n` to 42 (`add(42, b)`)! | ^ @@ -534,7 +534,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, b)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:87:83 + --> $DIR/unescaped_backticks.rs:89:83 | LL | /// Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`. | ^ @@ -549,7 +549,7 @@ LL | /// Addition is commutative, which means that `add(a, b) is the same as `ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:91:51 + --> $DIR/unescaped_backticks.rs:93:51 | LL | /// or even to add a number `n` to 42 (`add(42, n)`)! | ^ @@ -564,7 +564,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:95:83 + --> $DIR/unescaped_backticks.rs:97:83 | LL | /// Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`. | ^ @@ -579,7 +579,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as ad | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:99:50 + --> $DIR/unescaped_backticks.rs:101:50 | LL | /// or even to add a number `n` to 42 (add(42, n)`)! | ^ @@ -594,7 +594,7 @@ LL | /// or even to add a number `n` to 42 (add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:103:74 + --> $DIR/unescaped_backticks.rs:105:74 | LL | /// Addition is commutative, which means that `add(a, b)` is the same as `add(b, a). | ^ @@ -609,7 +609,7 @@ LL | /// Addition is commutative, which means that `add(a, b)` is the same as \` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:107:51 + --> $DIR/unescaped_backticks.rs:109:51 | LL | /// or even to add a number `n` to 42 (`add(42, n)`)! | ^ @@ -624,7 +624,7 @@ LL | /// or even to add a number `n` to 42 (`add(42, n)\`)! | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:111:10 + --> $DIR/unescaped_backticks.rs:113:10 | LL | #[doc = "`"] | ^ @@ -635,7 +635,7 @@ LL | #[doc = "`"] to this: \` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:118:26 + --> $DIR/unescaped_backticks.rs:120:26 | LL | #[doc = concat!("\\", "`")] | ^ @@ -648,7 +648,7 @@ LL | #[doc = concat!("\\", "`")] to this: \\` error: unescaped backtick - --> $DIR/unescaped_backticks.rs:122:9 + --> $DIR/unescaped_backticks.rs:124:9 | LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same as `add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -661,7 +661,7 @@ LL | #[doc = "Addition is commutative, which means that add(a, b)` is the same a to this: Addition is commutative, which means that add(a, b)` is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:126:9 + --> $DIR/unescaped_backticks.rs:128:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same as `add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -674,7 +674,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b) is the same a to this: Addition is commutative, which means that `add(a, b) is the same as `add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:130:9 + --> $DIR/unescaped_backticks.rs:132:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as add(b, a)`."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -687,7 +687,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same to this: Addition is commutative, which means that `add(a, b)` is the same as add(b, a)\`. error: unescaped backtick - --> $DIR/unescaped_backticks.rs:134:9 + --> $DIR/unescaped_backticks.rs:136:9 | LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same as `add(b, a)."] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -700,7 +700,7 @@ LL | #[doc = "Addition is commutative, which means that `add(a, b)` is the same to this: Addition is commutative, which means that `add(a, b)` is the same as \`add(b, a). error: unescaped backtick - --> $DIR/unescaped_backticks.rs:139:5 + --> $DIR/unescaped_backticks.rs:141:5 | LL | /// `foo | ^ @@ -715,7 +715,7 @@ LL | /// \`foo | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:143:7 + --> $DIR/unescaped_backticks.rs:145:7 | LL | /// # `(heading | ^ @@ -730,7 +730,7 @@ LL | /// # \`(heading | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:145:17 + --> $DIR/unescaped_backticks.rs:147:17 | LL | /// ## heading2)` | ^ @@ -745,7 +745,7 @@ LL | /// ## heading2)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:148:11 + --> $DIR/unescaped_backticks.rs:150:11 | LL | /// multi `( | ^ @@ -760,7 +760,7 @@ LL | /// multi \`( | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:154:10 + --> $DIR/unescaped_backticks.rs:156:10 | LL | /// para)`(graph | ^ @@ -779,7 +779,7 @@ LL | /// para)\`(graph | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:157:10 + --> $DIR/unescaped_backticks.rs:159:10 | LL | /// para)`(graph2 | ^ @@ -798,7 +798,7 @@ LL | /// para)\`(graph2 | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:160:12 + --> $DIR/unescaped_backticks.rs:162:12 | LL | /// 1. foo)` | ^ @@ -813,7 +813,7 @@ LL | /// 1. foo)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:162:8 + --> $DIR/unescaped_backticks.rs:164:8 | LL | /// 2. `(bar | ^ @@ -828,7 +828,7 @@ LL | /// 2. \`(bar | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:164:11 + --> $DIR/unescaped_backticks.rs:166:11 | LL | /// * baz)` | ^ @@ -843,7 +843,7 @@ LL | /// * baz)\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:166:7 + --> $DIR/unescaped_backticks.rs:168:7 | LL | /// * `(quux | ^ @@ -858,7 +858,7 @@ LL | /// * \`(quux | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:169:5 + --> $DIR/unescaped_backticks.rs:171:5 | LL | /// `#![this_is_actually_an_image(and(not), an = "attribute")] | ^ @@ -873,7 +873,7 @@ LL | /// \`#![this_is_actually_an_image(and(not), an = "attribute")] | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:172:62 + --> $DIR/unescaped_backticks.rs:174:62 | LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]` | ^ @@ -888,7 +888,7 @@ LL | /// #![this_is_actually_an_image(and(not), an = "attribute")]\` | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:177:7 + --> $DIR/unescaped_backticks.rs:179:7 | LL | /// | `table( | )head` | | ^ @@ -903,7 +903,7 @@ LL | /// | \`table( | )head` | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:177:22 + --> $DIR/unescaped_backticks.rs:179:22 | LL | /// | `table( | )head` | | ^ @@ -918,7 +918,7 @@ LL | /// | `table( | )head\` | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:181:12 + --> $DIR/unescaped_backticks.rs:183:12 | LL | /// | table`( | )`body | | ^ @@ -933,7 +933,7 @@ LL | /// | table\`( | )`body | | + error: unescaped backtick - --> $DIR/unescaped_backticks.rs:181:18 + --> $DIR/unescaped_backticks.rs:183:18 | LL | /// | table`( | )`body | | ^ diff --git a/tests/rustdoc-ui/lints/unescaped_backticks.rs b/tests/rustdoc-ui/lints/unescaped_backticks.rs index a0c25ca2eaf03..55ea1ac699d00 100644 --- a/tests/rustdoc-ui/lints/unescaped_backticks.rs +++ b/tests/rustdoc-ui/lints/unescaped_backticks.rs @@ -1,4 +1,6 @@ -//@revisions: deny_cli allow_cli +//@revisions: deny_cli allow_cli capped +//@[capped] compile-flags: --cap-lints=allow +//@[capped] check-pass //@[deny_cli] compile-flags: -Drustdoc::unescaped_backticks //@[allow_cli] compile-flags: -Arustdoc::unescaped_backticks //@[allow_cli] check-pass From 124126e0839b6a2aaa94cc7df1ca520122c66ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= Date: Fri, 15 May 2026 00:06:14 +0800 Subject: [PATCH 08/16] Test EII UI tests with prefer-dynamic --- tests/ui/eii/default/auxiliary/decl_with_default.rs | 1 - tests/ui/eii/default/auxiliary/decl_with_default_panics.rs | 1 - tests/ui/eii/default/auxiliary/impl1.rs | 1 - tests/ui/eii/default/call_default.rs | 1 - tests/ui/eii/default/call_default_panics.rs | 1 - tests/ui/eii/default/call_impl.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl1.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl2.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl3.rs | 1 - tests/ui/eii/duplicate/auxiliary/impl4.rs | 1 - tests/ui/eii/duplicate/duplicate1.rs | 1 - tests/ui/eii/duplicate/duplicate1.stderr | 4 ++-- tests/ui/eii/duplicate/duplicate2.rs | 1 - tests/ui/eii/duplicate/duplicate2.stderr | 4 ++-- tests/ui/eii/duplicate/duplicate3.rs | 1 - tests/ui/eii/duplicate/duplicate3.stderr | 4 ++-- tests/ui/eii/static/auxiliary/cross_crate_def.rs | 1 - 17 files changed, 6 insertions(+), 20 deletions(-) diff --git a/tests/ui/eii/default/auxiliary/decl_with_default.rs b/tests/ui/eii/default/auxiliary/decl_with_default.rs index 8d962c19c94d9..ba855cb854afd 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs b/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs index 14778a40cde4a..3867bfb85c9fe 100644 --- a/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs +++ b/tests/ui/eii/default/auxiliary/decl_with_default_panics.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ needs-unwind //@ exec-env:RUST_BACKTRACE=1 #![crate_type = "rlib"] diff --git a/tests/ui/eii/default/auxiliary/impl1.rs b/tests/ui/eii/default/auxiliary/impl1.rs index 3510ea1eb3f27..84edf24e12816 100644 --- a/tests/ui/eii/default/auxiliary/impl1.rs +++ b/tests/ui/eii/default/auxiliary/impl1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/default/call_default.rs b/tests/ui/eii/default/call_default.rs index 8806c7fa7d8ce..07b2a650d3c42 100644 --- a/tests/ui/eii/default/call_default.rs +++ b/tests/ui/eii/default/call_default.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs //@ run-pass //@ check-run-results diff --git a/tests/ui/eii/default/call_default_panics.rs b/tests/ui/eii/default/call_default_panics.rs index db664e0cbcb0d..379ba8ea070b6 100644 --- a/tests/ui/eii/default/call_default_panics.rs +++ b/tests/ui/eii/default/call_default_panics.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default_panics.rs //@ edition: 2021 //@ run-pass diff --git a/tests/ui/eii/default/call_impl.rs b/tests/ui/eii/default/call_impl.rs index 1a972774beaeb..4553427b8c799 100644 --- a/tests/ui/eii/default/call_impl.rs +++ b/tests/ui/eii/default/call_impl.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl_with_default.rs //@ aux-build: impl1.rs //@ run-pass diff --git a/tests/ui/eii/duplicate/auxiliary/impl1.rs b/tests/ui/eii/duplicate/auxiliary/impl1.rs index e99932c69b90b..ffa2cd79818cc 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl1.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl2.rs b/tests/ui/eii/duplicate/auxiliary/impl2.rs index 3a09c824b8292..592234f53fd40 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl2.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl2.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl3.rs b/tests/ui/eii/duplicate/auxiliary/impl3.rs index 09bdd8509da29..5e9fdaba0bb6b 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl3.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl3.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/auxiliary/impl4.rs b/tests/ui/eii/duplicate/auxiliary/impl4.rs index fd68a83de1252..068cc18d78e6a 100644 --- a/tests/ui/eii/duplicate/auxiliary/impl4.rs +++ b/tests/ui/eii/duplicate/auxiliary/impl4.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: decl.rs #![crate_type = "rlib"] #![feature(extern_item_impls)] diff --git a/tests/ui/eii/duplicate/duplicate1.rs b/tests/ui/eii/duplicate/duplicate1.rs index 2128cac70eb30..3d770232af50f 100644 --- a/tests/ui/eii/duplicate/duplicate1.rs +++ b/tests/ui/eii/duplicate/duplicate1.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ ignore-backends: gcc diff --git a/tests/ui/eii/duplicate/duplicate1.stderr b/tests/ui/eii/duplicate/duplicate1.stderr index 54cc141f88694..f691043e6a597 100644 --- a/tests/ui/eii/duplicate/duplicate1.stderr +++ b/tests/ui/eii/duplicate/duplicate1.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/duplicate/duplicate2.rs b/tests/ui/eii/duplicate/duplicate2.rs index b0f1b1266e4ca..4311969ed8894 100644 --- a/tests/ui/eii/duplicate/duplicate2.rs +++ b/tests/ui/eii/duplicate/duplicate2.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ aux-build: impl3.rs diff --git a/tests/ui/eii/duplicate/duplicate2.stderr b/tests/ui/eii/duplicate/duplicate2.stderr index 033e43c8b2fbd..492d2b3e6004b 100644 --- a/tests/ui/eii/duplicate/duplicate2.stderr +++ b/tests/ui/eii/duplicate/duplicate2.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/duplicate/duplicate3.rs b/tests/ui/eii/duplicate/duplicate3.rs index 4b2b0fc111b58..4504ba30c246e 100644 --- a/tests/ui/eii/duplicate/duplicate3.rs +++ b/tests/ui/eii/duplicate/duplicate3.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic //@ aux-build: impl1.rs //@ aux-build: impl2.rs //@ aux-build: impl3.rs diff --git a/tests/ui/eii/duplicate/duplicate3.stderr b/tests/ui/eii/duplicate/duplicate3.stderr index 801d40e69c552..f3ca087a27325 100644 --- a/tests/ui/eii/duplicate/duplicate3.stderr +++ b/tests/ui/eii/duplicate/duplicate3.stderr @@ -1,10 +1,10 @@ error: multiple implementations of `#[eii1]` - --> $DIR/auxiliary/impl1.rs:10:1 + --> $DIR/auxiliary/impl1.rs:9:1 | LL | fn other(x: u64) { | ^^^^^^^^^^^^^^^^ first implemented here in crate `impl1` | - ::: $DIR/auxiliary/impl2.rs:10:1 + ::: $DIR/auxiliary/impl2.rs:9:1 | LL | fn other(x: u64) { | ---------------- also implemented here in crate `impl2` diff --git a/tests/ui/eii/static/auxiliary/cross_crate_def.rs b/tests/ui/eii/static/auxiliary/cross_crate_def.rs index 70933440a62be..56d3f6fcdc557 100644 --- a/tests/ui/eii/static/auxiliary/cross_crate_def.rs +++ b/tests/ui/eii/static/auxiliary/cross_crate_def.rs @@ -1,4 +1,3 @@ -//@ no-prefer-dynamic #![crate_type = "rlib"] #![feature(extern_item_impls)] From 87821d9f784fe4f3a408919c21c7b1aaa3a50255 Mon Sep 17 00:00:00 2001 From: Eval Exec Date: Sat, 16 May 2026 03:14:52 -0400 Subject: [PATCH 09/16] Add regression test for issue 41261 --- .../ambiguous-cast-suggestion-issue-41261.rs | 19 +++++++++++++++++++ ...biguous-cast-suggestion-issue-41261.stderr | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs create mode 100644 tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr diff --git a/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs new file mode 100644 index 0000000000000..b1c4dfb9f1003 --- /dev/null +++ b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.rs @@ -0,0 +1,19 @@ +//@ edition: 2021 + +// Regression test for issue #41261. +// The diagnostic should point at the ambiguous cast, not at the later method call. + +struct S { + v: Vec<(u32, Vec)>, +} + +impl S { + pub fn remove(&mut self, i: u32) -> Option> { + self.v.get_mut(i as _).map(|&mut (_, ref mut v2)| { + //~^ ERROR type annotations needed + v2.drain(..) + }) + } +} + +fn main() {} diff --git a/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr new file mode 100644 index 0000000000000..da66f6237203e --- /dev/null +++ b/tests/ui/inference/ambiguous-cast-suggestion-issue-41261.stderr @@ -0,0 +1,17 @@ +error[E0282]: type annotations needed for `&mut (_, _)` + --> $DIR/ambiguous-cast-suggestion-issue-41261.rs:12:37 + | +LL | self.v.get_mut(i as _).map(|&mut (_, ref mut v2)| { + | ^^^^^^^^^^^^^^^^^^^^ +LL | +LL | v2.drain(..) + | -- type must be known at this point + | +help: consider giving this closure parameter an explicit type, where the placeholders `_` are specified + | +LL | self.v.get_mut(i as _).map(|&mut (_, ref mut v2): &mut (_, _)| { + | +++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0282`. From 6d91f14af9538e9d776595df8570f1e28b7c6443 Mon Sep 17 00:00:00 2001 From: b1yd <2156864690@qq.com> Date: Sat, 16 May 2026 16:03:00 +0800 Subject: [PATCH 10/16] fix --- compiler/rustc_parse/src/parser/diagnostics.rs | 7 +++---- compiler/rustc_parse/src/parser/mod.rs | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 47ac91feefd4b..4ef2788c5baf5 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1889,9 +1889,8 @@ impl<'a> Parser<'a> { true } - /// Creates a `Diag` for an unexpected token `t` and tries to recover if it is a - /// closing delimiter. - pub(super) fn unexpected_try_recover(&mut self, t: &TokenKind) -> PResult<'a, Recovered> { + /// Creates a `Diag` for an unexpected token `t` + pub(super) fn unexpected_err(&mut self, t: &TokenKind) -> Diag<'a> { let token_str = pprust::token_kind_to_string(t); let this_token_str = super::token_descr(&self.token); let (prev_sp, sp) = match (&self.token.kind, self.subparser_name) { @@ -1926,7 +1925,7 @@ impl<'a> Parser<'a> { err.span_label(prev_sp, label_exp); err.span_label(sp, "unexpected token"); } - Err(err) + err } pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> { diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 9303be8ff0ccd..850d64c8ecf44 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -409,7 +409,7 @@ impl<'a> Parser<'a> { self.bump(); Ok(Recovered::No) } else { - self.unexpected_try_recover(&exp.tok) + Err(self.unexpected_err(&exp.tok)) } } else { self.expect_one_of(slice::from_ref(&exp), &[]) From 053761df0a0e72f6846dd1a2ac8975c12207ad0a Mon Sep 17 00:00:00 2001 From: human9000 Date: Mon, 11 May 2026 19:11:49 +0500 Subject: [PATCH 11/16] minor `rustc_mir_transform` cleanup --- compiler/rustc_mir_transform/src/inline.rs | 3 +-- compiler/rustc_mir_transform/src/pass_manager.rs | 9 ++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index fbe3a827d6394..31871c62fa7a2 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -1072,8 +1072,7 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>( // // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. if callsite.fn_sig.abi() == ExternAbi::RustCall && callee_body.spread_arg.is_none() { - // FIXME(edition_2024): switch back to a normal method call. - let mut args = <_>::into_iter(args); + let mut args = args.into_iter(); let self_ = create_temp_if_necessary( inliner, args.next().unwrap().node, diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index ef4cf82cf1b5d..fbf16f91610c5 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -296,15 +296,14 @@ fn run_passes_inner<'tcx>( if is_optimization_stage(body, phase_change, optimizations) && let Some(limit) = &tcx.sess.opts.unstable_opts.mir_opt_bisect_limit - { - if limited_by_opt_bisect( + && limited_by_opt_bisect( tcx, tcx.def_path_debug_str(body.source.def_id()), *limit, *pass, - ) { - continue; - } + ) + { + continue; } let dumper = if pass.is_mir_dump_enabled() From e5998316eb12505f14e3236b5df49c15aea2e47f Mon Sep 17 00:00:00 2001 From: Andy Russell Date: Sat, 9 May 2026 17:41:28 -0400 Subject: [PATCH 12/16] suggest hex escapes for C-style escapes --- .../src/lexer/unescape_error_reporting.rs | 42 ++++- tests/ui/parser/byte-literals.stderr | 10 ++ tests/ui/parser/byte-string-literals.stderr | 10 ++ tests/ui/parser/foreign-escapes.rs | 25 +++ tests/ui/parser/foreign-escapes.stderr | 165 ++++++++++++++++++ 5 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 tests/ui/parser/foreign-escapes.rs create mode 100644 tests/ui/parser/foreign-escapes.stderr diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index 895374ab2cc4b..099bd44e9a065 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -3,7 +3,7 @@ use std::iter::once; use std::ops::Range; -use rustc_errors::{Applicability, DiagCtxtHandle, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed}; use rustc_literal_escaper::{EscapeError, Mode}; use rustc_span::{BytePos, Span}; use tracing::debug; @@ -172,6 +172,8 @@ pub(crate) fn emit_unescape_error( "for more information, visit \ ", ); + + foreign_escape_suggestion(&mut diag, (&ec, span), err_span); } diag.emit() } @@ -302,6 +304,44 @@ pub(crate) fn emit_unescape_error( }) } +/// Add additional suggestions for escapes that are supported by C. +fn foreign_escape_suggestion( + diag: &mut Diag<'_>, + (escaped_char, escape_span): (&str, Span), + err_span: Span, +) { + if escaped_char == "?" { + diag.span_suggestion( + err_span, + "if you meant to write a literal question mark, don't escape the character", + "?", + Applicability::MaybeIncorrect, + ); + return; + } + + if u8::from_str_radix(escaped_char, 8).is_ok() { + diag.help(r"if you meant to write an ASCII control code, use a `\xNN` hex escape"); + return; + } + + let (name, hex) = match escaped_char { + "a" => ("an audible bell", "07"), + "b" => ("a backspace", "08"), + "f" => ("a form feed", "0C"), + "v" => ("a vertical tab", "0B"), + "e" => ("an ANSI escape sequence", "1B"), + _ => return, + }; + + diag.span_suggestion( + escape_span, + format!("if you meant to write {name}, use a hex escape"), + format!("x{hex}"), + Applicability::MaybeIncorrect, + ); +} + /// Pushes a character to a message string for error reporting pub(crate) fn escaped_char(c: char) -> String { match c { diff --git a/tests/ui/parser/byte-literals.stderr b/tests/ui/parser/byte-literals.stderr index 1c89e8e2864b6..4df5f764cfe85 100644 --- a/tests/ui/parser/byte-literals.stderr +++ b/tests/ui/parser/byte-literals.stderr @@ -5,6 +5,11 @@ LL | static FOO: u8 = b'\f'; | ^ unknown byte escape | = help: for more information, visit +help: if you meant to write a form feed, use a hex escape + | +LL - static FOO: u8 = b'\f'; +LL + static FOO: u8 = b'\x0C'; + | error: unknown byte escape: `f` --> $DIR/byte-literals.rs:6:8 @@ -13,6 +18,11 @@ LL | b'\f'; | ^ unknown byte escape | = help: for more information, visit +help: if you meant to write a form feed, use a hex escape + | +LL - b'\f'; +LL + b'\x0C'; + | error: invalid character in numeric character escape: `Z` --> $DIR/byte-literals.rs:7:10 diff --git a/tests/ui/parser/byte-string-literals.stderr b/tests/ui/parser/byte-string-literals.stderr index 3e589258d4132..d036fae68ea1f 100644 --- a/tests/ui/parser/byte-string-literals.stderr +++ b/tests/ui/parser/byte-string-literals.stderr @@ -5,6 +5,11 @@ LL | static FOO: &'static [u8] = b"\f"; | ^ unknown byte escape | = help: for more information, visit +help: if you meant to write a form feed, use a hex escape + | +LL - static FOO: &'static [u8] = b"\f"; +LL + static FOO: &'static [u8] = b"\x0C"; + | error: unknown byte escape: `f` --> $DIR/byte-string-literals.rs:4:8 @@ -13,6 +18,11 @@ LL | b"\f"; | ^ unknown byte escape | = help: for more information, visit +help: if you meant to write a form feed, use a hex escape + | +LL - b"\f"; +LL + b"\x0C"; + | error: invalid character in numeric character escape: `Z` --> $DIR/byte-string-literals.rs:5:10 diff --git a/tests/ui/parser/foreign-escapes.rs b/tests/ui/parser/foreign-escapes.rs new file mode 100644 index 0000000000000..d802f858f8e31 --- /dev/null +++ b/tests/ui/parser/foreign-escapes.rs @@ -0,0 +1,25 @@ +// Specified by both C and Rust +pub const SINGLE_QUOTE: char = '\''; +pub const DOUBLE_QUOTE: char = '\"'; +pub const BACKSLASH: char = '\\'; +pub const NEWLINE: char = '\n'; +pub const CARRIAGE_RETURN: char = '\r'; +pub const HORIZONTAL_TAB: char = '\t'; +pub const NULL: char = '\0'; + +// Specified by C, but not Rust +pub const QUESTION_MARK: char = '\?'; //~ ERROR unknown character escape +pub const AUDIBLE_BELL: char = '\a'; //~ ERROR unknown character escape +pub const BACKSPACE: char = '\b'; //~ ERROR unknown character escape +pub const FORM_FEED: char = '\f'; //~ ERROR unknown character escape +pub const VERTICAL_TAB: char = '\v'; //~ ERROR unknown character escape +pub const OCTAL: char = '\1'; //~ ERROR unknown character escape +pub const OCTAL_TWO_DIGIT: char = '\12'; //~ ERROR unknown character escape +pub const OCTAL_THREE_DIGIT: char = '\12'; //~ ERROR unknown character escape +pub const OCTAL_OUT_OF_RANGE: char = '\9'; //~ ERROR unknown character escape + +// Not specified by C, but recognized by GCC as an extension. +// Used for ANSI escape sequences in terminal emulators. +pub const ESCAPE: char = '\e'; //~ ERROR unknown character escape + +fn main() {} diff --git a/tests/ui/parser/foreign-escapes.stderr b/tests/ui/parser/foreign-escapes.stderr new file mode 100644 index 0000000000000..619d7d1e6e8b7 --- /dev/null +++ b/tests/ui/parser/foreign-escapes.stderr @@ -0,0 +1,165 @@ +error: unknown character escape: `?` + --> $DIR/foreign-escapes.rs:11:35 + | +LL | pub const QUESTION_MARK: char = '\?'; + | ^ unknown character escape + | + = help: for more information, visit +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const QUESTION_MARK: char = '\?'; +LL + pub const QUESTION_MARK: char = r"\?"; + | +help: if you meant to write a literal question mark, don't escape the character + | +LL - pub const QUESTION_MARK: char = '\?'; +LL + pub const QUESTION_MARK: char = '?'; + | + +error: unknown character escape: `a` + --> $DIR/foreign-escapes.rs:12:34 + | +LL | pub const AUDIBLE_BELL: char = '\a'; + | ^ unknown character escape + | + = help: for more information, visit +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const AUDIBLE_BELL: char = '\a'; +LL + pub const AUDIBLE_BELL: char = r"\a"; + | +help: if you meant to write an audible bell, use a hex escape + | +LL - pub const AUDIBLE_BELL: char = '\a'; +LL + pub const AUDIBLE_BELL: char = '\x07'; + | + +error: unknown character escape: `b` + --> $DIR/foreign-escapes.rs:13:31 + | +LL | pub const BACKSPACE: char = '\b'; + | ^ unknown character escape + | + = help: for more information, visit +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const BACKSPACE: char = '\b'; +LL + pub const BACKSPACE: char = r"\b"; + | +help: if you meant to write a backspace, use a hex escape + | +LL - pub const BACKSPACE: char = '\b'; +LL + pub const BACKSPACE: char = '\x08'; + | + +error: unknown character escape: `f` + --> $DIR/foreign-escapes.rs:14:31 + | +LL | pub const FORM_FEED: char = '\f'; + | ^ unknown character escape + | + = help: for more information, visit +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const FORM_FEED: char = '\f'; +LL + pub const FORM_FEED: char = r"\f"; + | +help: if you meant to write a form feed, use a hex escape + | +LL - pub const FORM_FEED: char = '\f'; +LL + pub const FORM_FEED: char = '\x0C'; + | + +error: unknown character escape: `v` + --> $DIR/foreign-escapes.rs:15:34 + | +LL | pub const VERTICAL_TAB: char = '\v'; + | ^ unknown character escape + | + = help: for more information, visit +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const VERTICAL_TAB: char = '\v'; +LL + pub const VERTICAL_TAB: char = r"\v"; + | +help: if you meant to write a vertical tab, use a hex escape + | +LL - pub const VERTICAL_TAB: char = '\v'; +LL + pub const VERTICAL_TAB: char = '\x0B'; + | + +error: unknown character escape: `1` + --> $DIR/foreign-escapes.rs:16:27 + | +LL | pub const OCTAL: char = '\1'; + | ^ unknown character escape + | + = help: for more information, visit + = help: if you meant to write an ASCII control code, use a `\xNN` hex escape +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const OCTAL: char = '\1'; +LL + pub const OCTAL: char = r"\1"; + | + +error: unknown character escape: `1` + --> $DIR/foreign-escapes.rs:17:37 + | +LL | pub const OCTAL_TWO_DIGIT: char = '\12'; + | ^ unknown character escape + | + = help: for more information, visit + = help: if you meant to write an ASCII control code, use a `\xNN` hex escape +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const OCTAL_TWO_DIGIT: char = '\12'; +LL + pub const OCTAL_TWO_DIGIT: char = r"\12"; + | + +error: unknown character escape: `1` + --> $DIR/foreign-escapes.rs:18:39 + | +LL | pub const OCTAL_THREE_DIGIT: char = '\12'; + | ^ unknown character escape + | + = help: for more information, visit + = help: if you meant to write an ASCII control code, use a `\xNN` hex escape +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const OCTAL_THREE_DIGIT: char = '\12'; +LL + pub const OCTAL_THREE_DIGIT: char = r"\12"; + | + +error: unknown character escape: `9` + --> $DIR/foreign-escapes.rs:19:40 + | +LL | pub const OCTAL_OUT_OF_RANGE: char = '\9'; + | ^ unknown character escape + | + = help: for more information, visit +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const OCTAL_OUT_OF_RANGE: char = '\9'; +LL + pub const OCTAL_OUT_OF_RANGE: char = r"\9"; + | + +error: unknown character escape: `e` + --> $DIR/foreign-escapes.rs:23:28 + | +LL | pub const ESCAPE: char = '\e'; + | ^ unknown character escape + | + = help: for more information, visit +help: if you meant to write a literal backslash (perhaps escaping in a regular expression), consider a raw string literal + | +LL - pub const ESCAPE: char = '\e'; +LL + pub const ESCAPE: char = r"\e"; + | +help: if you meant to write an ANSI escape sequence, use a hex escape + | +LL - pub const ESCAPE: char = '\e'; +LL + pub const ESCAPE: char = '\x1B'; + | + +error: aborting due to 10 previous errors + From 2071c66f19171fbf937fba7cac1976bcc6417195 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 19 Jan 2026 18:12:38 +0900 Subject: [PATCH 13/16] Add interior-mutability suggestion to `static_mut_refs` --- compiler/rustc_lint/src/lints.rs | 18 +++ compiler/rustc_lint/src/static_mut_refs.rs | 143 ++++++++++++++++-- .../static-mut-refs-interior-mutability.fixed | 13 ++ .../static-mut-refs-interior-mutability.rs | 13 ++ ...static-mut-refs-interior-mutability.stderr | 18 +++ .../static-lazy-init-with-arena-set.stderr | 6 + 6 files changed, 200 insertions(+), 11 deletions(-) create mode 100644 tests/ui/lint/static-mut-refs-interior-mutability.fixed create mode 100644 tests/ui/lint/static-mut-refs-interior-mutability.rs create mode 100644 tests/ui/lint/static-mut-refs-interior-mutability.stderr diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 6d9f486f627f6..091b7ac228b54 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2669,6 +2669,12 @@ pub(crate) struct RefOfMutStatic<'a> { "mutable references to mutable statics are dangerous; it's undefined behavior if any other pointer to the static is used or if any other reference is created for the static while the mutable reference lives" )] pub mut_note: bool, + #[help( + "use a type that relies on \"interior mutability\" instead; to read more on this, visit " + )] + pub interior_mutability_help: bool, + #[subdiagnostic] + pub interior_mutability_sugg: Option, } #[derive(Subdiagnostic)] @@ -2693,6 +2699,18 @@ pub(crate) enum MutRefSugg { }, } +#[derive(Subdiagnostic)] +#[suggestion( + "this type already provides \"interior mutability\", so its binding doesn't need to be declared as mutable", + style = "verbose", + applicability = "maybe-incorrect", + code = "" +)] +pub(crate) struct StaticMutRefsInteriorMutabilitySugg { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag("`use` of a local item without leading `self::`, `super::`, or `crate::`")] pub(crate) struct UnqualifiedLocalImportsDiag; diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 1decb4b78e61a..64ab1f7535bff 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -1,11 +1,12 @@ use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_hir::{Expr, Stmt}; use rustc_middle::ty::{Mutability, TyKind}; use rustc_session::lint::fcw; use rustc_session::{declare_lint, declare_lint_pass}; use rustc_span::{BytePos, Span}; -use crate::lints::{MutRefSugg, RefOfMutStatic}; +use crate::lints::{MutRefSugg, RefOfMutStatic, StaticMutRefsInteriorMutabilitySugg}; use crate::{LateContext, LateLintPass, LintContext}; declare_lint! { @@ -67,7 +68,7 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { match expr.kind { hir::ExprKind::AddrOf(borrow_kind, m, ex) if matches!(borrow_kind, hir::BorrowKind::Ref) - && let Some(err_span) = path_is_static_mut(ex, err_span) => + && let Some(static_mut) = path_is_static_mut(ex, err_span) => { let source_map = cx.sess().source_map(); let snippet = source_map.span_to_snippet(err_span); @@ -86,10 +87,17 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { err_span.with_hi(ex.span.lo()) }; - emit_static_mut_refs(cx, err_span, sugg_span, m, !expr.span.from_expansion()); + emit_static_mut_refs( + cx, + static_mut.err_span, + sugg_span, + m, + !expr.span.from_expansion(), + static_mut.def_id, + ); } hir::ExprKind::MethodCall(_, e, _, _) - if let Some(err_span) = path_is_static_mut(e, expr.span) + if let Some(static_mut) = path_is_static_mut(e, expr.span) && let typeck = cx.typeck_results() && let Some(method_def_id) = typeck.type_dependent_def_id(expr.hir_id) && let inputs = @@ -97,7 +105,14 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { && let Some(receiver) = inputs.get(0) && let TyKind::Ref(_, _, m) = receiver.kind() => { - emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), *m, false); + emit_static_mut_refs( + cx, + static_mut.err_span, + static_mut.err_span.shrink_to_lo(), + *m, + false, + static_mut.def_id, + ); } _ => {} } @@ -108,14 +123,26 @@ impl<'tcx> LateLintPass<'tcx> for StaticMutRefs { && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind && let hir::ByRef::Yes(_, m) = ba.0 && let Some(init) = loc.init - && let Some(err_span) = path_is_static_mut(init, init.span) + && let Some(static_mut) = path_is_static_mut(init, init.span) { - emit_static_mut_refs(cx, err_span, err_span.shrink_to_lo(), m, false); + emit_static_mut_refs( + cx, + static_mut.err_span, + static_mut.err_span.shrink_to_lo(), + m, + false, + static_mut.def_id, + ); } } } -fn path_is_static_mut(mut expr: &hir::Expr<'_>, mut err_span: Span) -> Option { +struct StaticMutInfo { + err_span: Span, + def_id: DefId, +} + +fn path_is_static_mut(mut expr: &hir::Expr<'_>, mut err_span: Span) -> Option { if err_span.from_expansion() { err_span = expr.span; } @@ -126,11 +153,11 @@ fn path_is_static_mut(mut expr: &hir::Expr<'_>, mut err_span: Span) -> Option { @@ -155,9 +183,102 @@ fn emit_static_mut_refs( } }; + let (interior_mutability_help, interior_mutability_sugg) = + interior_mutability_suggestion(cx, def_id); + cx.emit_span_lint( STATIC_MUT_REFS, span, - RefOfMutStatic { span, sugg, shared_label, shared_note, mut_note }, + RefOfMutStatic { + span, + sugg, + shared_label, + shared_note, + mut_note, + interior_mutability_help, + interior_mutability_sugg, + }, ); } + +fn interior_mutability_suggestion( + cx: &LateContext<'_>, + def_id: DefId, +) -> (bool, Option) { + let static_ty = cx.tcx.type_of(def_id).skip_binder(); + let has_interior_mutability = !static_ty.is_freeze(cx.tcx, cx.typing_env()); + + if !has_interior_mutability { + return (false, None); + } + + let sugg = + static_mutability_span(cx, def_id).map(|span| StaticMutRefsInteriorMutabilitySugg { span }); + (true, sugg) +} + +fn static_mutability_span(cx: &LateContext<'_>, def_id: DefId) -> Option { + let hir_id = cx.tcx.hir_get_if_local(def_id)?; + let hir::Node::Item(item) = hir_id else { return None }; + let (mutability, ident) = match item.kind { + hir::ItemKind::Static(mutability, ident, _, _) => (mutability, ident), + _ => return None, + }; + if mutability != hir::Mutability::Mut { + return None; + } + + let vis_span = item.vis_span.find_ancestor_inside(item.span)?; + if !item.span.can_be_used_for_suggestions() || !vis_span.can_be_used_for_suggestions() { + return None; + } + + let header_span = vis_span.between(ident.span); + if !header_span.can_be_used_for_suggestions() { + return None; + } + + let source_map = cx.sess().source_map(); + let snippet = source_map.span_to_snippet(header_span).ok()?; + + let (_static_start, static_end) = find_word(&snippet, "static", 0)?; + let (mut_start, mut_end) = find_word(&snippet, "mut", static_end)?; + let mut_end = extend_trailing_space(&snippet, mut_end); + + Some( + header_span + .with_lo(header_span.lo() + BytePos(mut_start as u32)) + .with_hi(header_span.lo() + BytePos(mut_end as u32)), + ) +} + +fn find_word(snippet: &str, word: &str, start: usize) -> Option<(usize, usize)> { + let bytes = snippet.as_bytes(); + let word_bytes = word.as_bytes(); + let mut search = start; + while search <= snippet.len() { + let found = snippet[search..].find(word)?; + let idx = search + found; + let end = idx + word_bytes.len(); + let before_ok = idx == 0 || !is_ident_char(bytes[idx - 1]); + let after_ok = end >= bytes.len() || !is_ident_char(bytes[end]); + if before_ok && after_ok { + return Some((idx, end)); + } + search = end; + } + None +} + +fn is_ident_char(byte: u8) -> bool { + byte.is_ascii_alphanumeric() || byte == b'_' +} + +fn extend_trailing_space(snippet: &str, mut end: usize) -> usize { + if let Some(ch) = snippet[end..].chars().next() + && (ch == ' ' || ch == '\t') + { + end += ch.len_utf8(); + } + end +} diff --git a/tests/ui/lint/static-mut-refs-interior-mutability.fixed b/tests/ui/lint/static-mut-refs-interior-mutability.fixed new file mode 100644 index 0000000000000..d5b096119cce1 --- /dev/null +++ b/tests/ui/lint/static-mut-refs-interior-mutability.fixed @@ -0,0 +1,13 @@ +//@ edition:2024 +//@ run-rustfix + +#![allow(unused_unsafe)] + +use std::sync::Mutex; + +static STDINOUT_MUTEX: Mutex = Mutex::new(false); + +fn main() { + let _lock = unsafe { STDINOUT_MUTEX.lock().unwrap() }; + //~^ ERROR creating a shared reference to mutable static [static_mut_refs] +} diff --git a/tests/ui/lint/static-mut-refs-interior-mutability.rs b/tests/ui/lint/static-mut-refs-interior-mutability.rs new file mode 100644 index 0000000000000..f5d0fca5b45d7 --- /dev/null +++ b/tests/ui/lint/static-mut-refs-interior-mutability.rs @@ -0,0 +1,13 @@ +//@ edition:2024 +//@ run-rustfix + +#![allow(unused_unsafe)] + +use std::sync::Mutex; + +static mut STDINOUT_MUTEX: Mutex = Mutex::new(false); + +fn main() { + let _lock = unsafe { STDINOUT_MUTEX.lock().unwrap() }; + //~^ ERROR creating a shared reference to mutable static [static_mut_refs] +} diff --git a/tests/ui/lint/static-mut-refs-interior-mutability.stderr b/tests/ui/lint/static-mut-refs-interior-mutability.stderr new file mode 100644 index 0000000000000..5fe446cc27b26 --- /dev/null +++ b/tests/ui/lint/static-mut-refs-interior-mutability.stderr @@ -0,0 +1,18 @@ +error: creating a shared reference to mutable static + --> $DIR/static-mut-refs-interior-mutability.rs:11:26 + | +LL | let _lock = unsafe { STDINOUT_MUTEX.lock().unwrap() }; + | ^^^^^^^^^^^^^^^^^^^^^ shared reference to mutable static + | + = note: for more information, see + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = help: use a type that relies on "interior mutability" instead; to read more on this, visit + = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default +help: this type already provides "interior mutability", so its binding doesn't need to be declared as mutable + | +LL - static mut STDINOUT_MUTEX: Mutex = Mutex::new(false); +LL + static STDINOUT_MUTEX: Mutex = Mutex::new(false); + | + +error: aborting due to 1 previous error + diff --git a/tests/ui/statics/static-lazy-init-with-arena-set.stderr b/tests/ui/statics/static-lazy-init-with-arena-set.stderr index 134129f814aa7..c1d6861718545 100644 --- a/tests/ui/statics/static-lazy-init-with-arena-set.stderr +++ b/tests/ui/statics/static-lazy-init-with-arena-set.stderr @@ -10,8 +10,14 @@ LL | | }); | |______________^ shared reference to mutable static | = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = help: use a type that relies on "interior mutability" instead; to read more on this, visit = note: for more information, see = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default +help: this type already provides "interior mutability", so its binding doesn't need to be declared as mutable + | +LL - static mut ONCE: Once = Once::new(); +LL + static ONCE: Once = Once::new(); + | warning: 1 warning emitted From cbaee5df1b1e2b1f2d8a1072af9765fd2cca847d Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 6 Mar 2026 05:49:20 +0900 Subject: [PATCH 14/16] Tweak note condition --- compiler/rustc_lint/src/static_mut_refs.rs | 2 +- tests/ui/lint/static-mut-refs-interior-mutability.stderr | 3 +-- tests/ui/statics/static-lazy-init-with-arena-set.stderr | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 64ab1f7535bff..1babe16b35a30 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -214,7 +214,7 @@ fn interior_mutability_suggestion( let sugg = static_mutability_span(cx, def_id).map(|span| StaticMutRefsInteriorMutabilitySugg { span }); - (true, sugg) + (sugg.is_none(), sugg) } fn static_mutability_span(cx: &LateContext<'_>, def_id: DefId) -> Option { diff --git a/tests/ui/lint/static-mut-refs-interior-mutability.stderr b/tests/ui/lint/static-mut-refs-interior-mutability.stderr index 5fe446cc27b26..29ab5a5c404de 100644 --- a/tests/ui/lint/static-mut-refs-interior-mutability.stderr +++ b/tests/ui/lint/static-mut-refs-interior-mutability.stderr @@ -4,9 +4,8 @@ error: creating a shared reference to mutable static LL | let _lock = unsafe { STDINOUT_MUTEX.lock().unwrap() }; | ^^^^^^^^^^^^^^^^^^^^^ shared reference to mutable static | - = note: for more information, see = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives - = help: use a type that relies on "interior mutability" instead; to read more on this, visit + = note: for more information, see = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default help: this type already provides "interior mutability", so its binding doesn't need to be declared as mutable | diff --git a/tests/ui/statics/static-lazy-init-with-arena-set.stderr b/tests/ui/statics/static-lazy-init-with-arena-set.stderr index c1d6861718545..43b244607885d 100644 --- a/tests/ui/statics/static-lazy-init-with-arena-set.stderr +++ b/tests/ui/statics/static-lazy-init-with-arena-set.stderr @@ -10,7 +10,6 @@ LL | | }); | |______________^ shared reference to mutable static | = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives - = help: use a type that relies on "interior mutability" instead; to read more on this, visit = note: for more information, see = note: `#[warn(static_mut_refs)]` (part of `#[warn(rust_2024_compatibility)]`) on by default help: this type already provides "interior mutability", so its binding doesn't need to be declared as mutable From 33d92f7b52500a1426637bdd19276b7ead1d6d19 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 17 May 2026 14:58:25 +0900 Subject: [PATCH 15/16] Add test for the case span is unavailable --- ...tic-mut-refs-interior-mutability-no-sugg.rs | 18 ++++++++++++++++++ ...mut-refs-interior-mutability-no-sugg.stderr | 13 +++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.rs create mode 100644 tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.stderr diff --git a/tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.rs b/tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.rs new file mode 100644 index 0000000000000..82c6b55a7623a --- /dev/null +++ b/tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.rs @@ -0,0 +1,18 @@ +//@ edition:2024 +// Ensure that we don't make structured suggestions for interior mutability note +// when span is not available. + +use std::sync::Mutex; + +macro_rules! declare_mutex { + () => { + static mut MACRO_MUTEX: Mutex = Mutex::new(false); + }; +} + +declare_mutex!(); + +fn main() { + let _lock = unsafe { MACRO_MUTEX.lock().unwrap() }; + //~^ ERROR creating a shared reference to mutable static [static_mut_refs] +} diff --git a/tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.stderr b/tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.stderr new file mode 100644 index 0000000000000..5ce69e1a14d83 --- /dev/null +++ b/tests/ui/lint/static-mut-refs-interior-mutability-no-sugg.stderr @@ -0,0 +1,13 @@ +error: creating a shared reference to mutable static + --> $DIR/static-mut-refs-interior-mutability-no-sugg.rs:16:26 + | +LL | let _lock = unsafe { MACRO_MUTEX.lock().unwrap() }; + | ^^^^^^^^^^^^^^^^^^ shared reference to mutable static + | + = note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives + = help: use a type that relies on "interior mutability" instead; to read more on this, visit + = note: for more information, see + = note: `#[deny(static_mut_refs)]` (part of `#[deny(rust_2024_compatibility)]`) on by default + +error: aborting due to 1 previous error + From ee8949e513313e384a1ab7657eb2dd8f71b09163 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 17 May 2026 15:03:24 +0900 Subject: [PATCH 16/16] Add FIXME for `interior_mutability_suggestion` --- compiler/rustc_lint/src/static_mut_refs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_lint/src/static_mut_refs.rs b/compiler/rustc_lint/src/static_mut_refs.rs index 1babe16b35a30..67e83d0652c3d 100644 --- a/compiler/rustc_lint/src/static_mut_refs.rs +++ b/compiler/rustc_lint/src/static_mut_refs.rs @@ -201,6 +201,10 @@ fn emit_static_mut_refs( ); } +// FIXME: This builds suggestion spans by handcrafting from source text. +// Replace this with HIR-based handling once we can identify the `mut` token +// in the static declaration that way. +// Context: https://github.com/rust-lang/rust/pull/151362/changes#r3210767018 fn interior_mutability_suggestion( cx: &LateContext<'_>, def_id: DefId,