From 65b88ea8ee499345aa8414f16d6cf018c6bdaed6 Mon Sep 17 00:00:00 2001 From: JayanAXHF Date: Sun, 5 Apr 2026 13:54:16 +0530 Subject: [PATCH] fix(lints): Improve ill_formed_attribute_input with better help message --- .../rustc_attr_parsing/src/attributes/doc.rs | 6 ++++- .../src/attributes/test_attrs.rs | 11 ++++++-- compiler/rustc_attr_parsing/src/context.rs | 9 ++++++- .../rustc_attr_parsing/src/validate_attr.rs | 1 + compiler/rustc_lint/src/early/diagnostics.rs | 3 ++- compiler/rustc_lint/src/lints.rs | 10 ++++++++ compiler/rustc_lint_defs/src/lib.rs | 1 + tests/ui/malformed/ignore-with-lint-name.rs | 6 +++++ .../ui/malformed/ignore-with-lint-name.stderr | 25 +++++++++++++++++++ 9 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 tests/ui/malformed/ignore-with-lint-name.rs create mode 100644 tests/ui/malformed/ignore-with-lint-name.stderr diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index a569483ea7c39..99f856684abd5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -665,7 +665,11 @@ impl DocParser { let span = cx.attr_span; cx.emit_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None }, + AttributeLintKind::IllFormedAttributeInput { + suggestions, + docs: None, + help: None, + }, span, ); } diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs index e8d2bedc37802..1f50d84869f49 100644 --- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs @@ -27,8 +27,15 @@ impl SingleAttributeParser for IgnoreParser { }; Some(str_value) } - ArgParser::List(_) => { - cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT); + ArgParser::List(list) => { + let help = list.single().and_then(|item| item.meta_item()).and_then(|item| { + item.args().no_args().ok()?; + Some(item.path().to_string()) + }); + cx.adcx().warn_ill_formed_attribute_input_with_help( + ILL_FORMED_ATTRIBUTE_INPUT, + help, + ); return None; } }, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 74eb1222078d0..b87a71bcbd92b 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -830,11 +830,18 @@ where } pub(crate) fn warn_ill_formed_attribute_input(&mut self, lint: &'static Lint) { + self.warn_ill_formed_attribute_input_with_help(lint, None) + } + pub(crate) fn warn_ill_formed_attribute_input_with_help( + &mut self, + lint: &'static Lint, + help: Option, + ) { let suggestions = self.suggestions(); let span = self.attr_span; self.emit_lint( lint, - AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None }, + AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None, help }, span, ); } diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index f56e85b110610..e2521c9abf5ff 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -211,6 +211,7 @@ fn emit_malformed_attribute( BuiltinLintDiag::AttributeLint(AttributeLintKind::IllFormedAttributeInput { suggestions: suggestions.clone(), docs: template.docs, + help: None, }), ); } else { diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index aee16526dfc0b..c1779909e67d0 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -137,7 +137,7 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { &AttributeLintKind::UnusedDuplicate { this, other, warning } => { lints::UnusedDuplicate { this, other, warning }.into_diag(dcx, level) } - AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { + AttributeLintKind::IllFormedAttributeInput { suggestions, docs, help } => { lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( @@ -145,6 +145,7 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { ), has_docs: docs.is_some(), docs: docs.unwrap_or(""), + help: help.clone().map(|h| lints::IllFormedAttributeInputHelp { lint: h }), } .into_diag(dcx, level) } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 5819f2bc151f9..ccee479f0ef6a 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3009,6 +3009,16 @@ pub(crate) struct IllFormedAttributeInput { #[note("for more information, visit <{$docs}>")] pub has_docs: bool, pub docs: &'static str, + #[subdiagnostic] + pub help: Option, +} + +#[derive(Subdiagnostic)] +#[help( + "if you meant to silence a warning, consider using #![allow({$lint})] or #![expect({$lint})]" +)] +pub(crate) struct IllFormedAttributeInputHelp { + pub lint: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 7e51029b02bb6..d00cd59ab13dc 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -690,6 +690,7 @@ pub enum AttributeLintKind { IllFormedAttributeInput { suggestions: Vec, docs: Option<&'static str>, + help: Option, }, EmptyAttribute { first_span: Span, diff --git a/tests/ui/malformed/ignore-with-lint-name.rs b/tests/ui/malformed/ignore-with-lint-name.rs new file mode 100644 index 0000000000000..eb023ea81d572 --- /dev/null +++ b/tests/ui/malformed/ignore-with-lint-name.rs @@ -0,0 +1,6 @@ +#[ignore(clippy::single_match)] +//~^ ERROR valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` +//~| HELP if you meant to silence a warning, consider using #![allow(clippy::single_match)] or #![expect(clippy::single_match)] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +fn main() {} diff --git a/tests/ui/malformed/ignore-with-lint-name.stderr b/tests/ui/malformed/ignore-with-lint-name.stderr new file mode 100644 index 0000000000000..a2f251de6fcc3 --- /dev/null +++ b/tests/ui/malformed/ignore-with-lint-name.stderr @@ -0,0 +1,25 @@ +error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` + --> $DIR/ignore-with-lint-name.rs:1:1 + | +LL | #[ignore(clippy::single_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you meant to silence a warning, consider using #![allow(clippy::single_match)] or #![expect(clippy::single_match)] + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default + +error: aborting due to 1 previous error + +Future incompatibility report: Future breakage diagnostic: +error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]` + --> $DIR/ignore-with-lint-name.rs:1:1 + | +LL | #[ignore(clippy::single_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if you meant to silence a warning, consider using #![allow(clippy::single_match)] or #![expect(clippy::single_match)] + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + = note: `#[deny(ill_formed_attribute_input)]` (part of `#[deny(future_incompatible)]`) on by default +