From 5f0ccfba88a3f9423099198441006579b5f21740 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 19 Apr 2026 00:36:20 +0200 Subject: [PATCH 1/6] Remove `AttributeLintKind::IllFormedAttributeInput` variant --- .../rustc_attr_parsing/src/attributes/doc.rs | 9 ++-- compiler/rustc_attr_parsing/src/context.rs | 7 ++- compiler/rustc_attr_parsing/src/errors.rs | 45 ++++++++++++++++++- .../rustc_attr_parsing/src/validate_attr.rs | 13 +++--- compiler/rustc_lint/src/early/diagnostics.rs | 12 ----- compiler/rustc_lint/src/lints.rs | 26 ----------- compiler/rustc_lint_defs/src/lib.rs | 5 --- 7 files changed, 59 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index a5b8c0ebe25eb..3983f892744ba 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -666,12 +666,11 @@ impl DocParser { ArgParser::NoArgs => { let suggestions = cx.adcx().suggestions(); let span = cx.attr_span; - cx.emit_lint( + cx.emit_dyn_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - AttributeLintKind::IllFormedAttributeInput { - suggestions, - docs: None, - help: None, + move |dcx, level| { + crate::errors::IllFormedAttributeInput::new(&suggestions, None, None) + .into_diag(dcx, level) }, span, ); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index aa9284e54d369..e51ffa0696e78 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -916,9 +916,12 @@ where ) { let suggestions = self.suggestions(); let span = self.attr_span; - self.emit_lint( + self.emit_dyn_lint( lint, - AttributeLintKind::IllFormedAttributeInput { suggestions, docs: None, help }, + move |dcx, level| { + crate::errors::IllFormedAttributeInput::new(&suggestions, None, help.as_deref()) + .into_diag(dcx, level) + }, span, ); } diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index 7049ffae89ab1..0750ed0e614d6 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::MultiSpan; +use rustc_errors::{DiagArgValue, MultiSpan}; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -66,3 +66,46 @@ pub(crate) struct UnsafeAttrOutsideUnsafeLint { #[subdiagnostic] pub suggestion: Option, } + +#[derive(Diagnostic)] +#[diag( + "{$num_suggestions -> + [1] attribute must be of the form {$suggestions} + *[other] valid forms for the attribute are {$suggestions} + }" +)] +pub(crate) struct IllFormedAttributeInput { + pub num_suggestions: usize, + pub suggestions: DiagArgValue, + #[note("for more information, visit <{$docs}>")] + pub has_docs: bool, + pub docs: &'static str, + #[subdiagnostic] + help: Option, +} + +impl IllFormedAttributeInput { + pub(crate) fn new( + suggestions: &[String], + docs: Option<&'static str>, + help: Option<&str>, + ) -> Self { + Self { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + has_docs: docs.is_some(), + docs: docs.unwrap_or(""), + help: help.map(|h| IllFormedAttributeInputHelp { lint: h.to_string() }), + } + } +} + +#[derive(Subdiagnostic)] +#[help( + "if you meant to silence a warning, consider using #![allow({$lint})] or #![expect({$lint})]" +)] +struct IllFormedAttributeInputHelp { + pub lint: String, +} diff --git a/compiler/rustc_attr_parsing/src/validate_attr.rs b/compiler/rustc_attr_parsing/src/validate_attr.rs index 06ff674f25389..d8c4aaa2e11ef 100644 --- a/compiler/rustc_attr_parsing/src/validate_attr.rs +++ b/compiler/rustc_attr_parsing/src/validate_attr.rs @@ -8,10 +8,9 @@ use rustc_ast::tokenstream::DelimSpan; use rustc_ast::{ self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety, }; -use rustc_errors::{Applicability, PResult}; +use rustc_errors::{Applicability, Diagnostic, PResult}; use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute, template}; use rustc_hir::AttrPath; -use rustc_hir::lints::AttributeLintKind; use rustc_parse::parse_in; use rustc_session::errors::report_lit_error; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; @@ -210,14 +209,14 @@ pub fn emit_malformed_attribute( suggestions.clear(); } if should_warn(name) { - psess.buffer_lint( + let suggestions = suggestions.clone(); + psess.dyn_buffer_lint( ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, - AttributeLintKind::IllFormedAttributeInput { - suggestions: suggestions.clone(), - docs: template.docs, - help: None, + move |dcx, level| { + crate::errors::IllFormedAttributeInput::new(&suggestions, template.docs, None) + .into_diag(dcx, level) }, ); } else { diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 7340ba0b2f391..fd7dbefcd0f7d 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -35,18 +35,6 @@ pub struct DecorateAttrLint<'a, 'sess, 'tcx> { impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { match self.diagnostic { - AttributeLintKind::IllFormedAttributeInput { suggestions, docs, help } => { - lints::IllFormedAttributeInput { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - has_docs: docs.is_some(), - docs: docs.unwrap_or(""), - help: help.clone().map(|h| lints::IllFormedAttributeInputHelp { lint: h }), - } - .into_diag(dcx, level) - } AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { lints::EmptyAttributeList { attr_span: *first_span, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 20d88505f042d..22953510e6127 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3025,32 +3025,6 @@ pub(crate) mod unexpected_cfg_value { } } -// FIXME(jdonszelmann): duplicated in rustc_attr_parsing, should be moved there completely. -#[derive(Diagnostic)] -#[diag( - "{$num_suggestions -> - [1] attribute must be of the form {$suggestions} - *[other] valid forms for the attribute are {$suggestions} - }" -)] -pub(crate) struct IllFormedAttributeInput { - pub num_suggestions: usize, - pub suggestions: DiagArgValue, - #[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)] #[diag("creating a {$shared_label}reference to mutable static")] pub(crate) struct RefOfMutStatic<'a> { diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index ea5006c7f03f3..534658ba386a9 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -654,11 +654,6 @@ pub enum DeprecatedSinceKind { #[derive(Debug)] pub enum AttributeLintKind { - IllFormedAttributeInput { - suggestions: Vec, - docs: Option<&'static str>, - help: Option, - }, EmptyAttribute { first_span: Span, attr_path: String, From b4d02996f918c1e1b421f4b94ebfcb65342e2726 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 19 Apr 2026 00:48:32 +0200 Subject: [PATCH 2/6] Remove `AttributeLintKind::EmptyAttribute` variant --- compiler/rustc_attr_parsing/src/context.rs | 13 +++++++++--- compiler/rustc_attr_parsing/src/errors.rs | 22 ++++++++++++++++++++ compiler/rustc_lint/src/early/diagnostics.rs | 8 ------- compiler/rustc_lint/src/lints.rs | 22 -------------------- compiler/rustc_lint_defs/src/lib.rs | 5 ----- 5 files changed, 32 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index e51ffa0696e78..becdaee0f3d3a 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -897,11 +897,18 @@ where } pub(crate) fn warn_empty_attribute(&mut self, span: Span) { - let attr_path = self.attr_path.clone().to_string(); + let attr_path = self.attr_path.to_string(); let valid_without_list = self.template.word; - self.emit_lint( + self.emit_dyn_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list }, + move |dcx, level| { + crate::errors::EmptyAttributeList { + attr_span: span, + attr_path: &attr_path, + valid_without_list, + } + .into_diag(dcx, level) + }, span, ); } diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index 0750ed0e614d6..12c83548b6a2b 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -109,3 +109,25 @@ impl IllFormedAttributeInput { struct IllFormedAttributeInputHelp { pub lint: String, } + +#[derive(Diagnostic)] +#[diag("unused attribute")] +#[note( + "{$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + }" +)] +pub(crate) struct EmptyAttributeList<'a> { + #[suggestion( + "{$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + }", + code = "", + applicability = "machine-applicable" + )] + pub attr_span: Span, + pub attr_path: &'a str, + pub valid_without_list: bool, +} diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index fd7dbefcd0f7d..d92be8bddf6c8 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -35,14 +35,6 @@ pub struct DecorateAttrLint<'a, 'sess, 'tcx> { impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { match self.diagnostic { - AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { - lints::EmptyAttributeList { - attr_span: *first_span, - attr_path: attr_path.clone(), - valid_without_list: *valid_without_list, - } - .into_diag(dcx, level) - } AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { lints::InvalidTargetLint { name: name.clone(), diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 22953510e6127..8bbc6ddf72cbc 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3282,28 +3282,6 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } -#[derive(Diagnostic)] -#[diag("unused attribute")] -#[note( - "{$valid_without_list -> - [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all - *[other] using `{$attr_path}` with an empty list has no effect - }" -)] -pub(crate) struct EmptyAttributeList { - #[suggestion( - "{$valid_without_list -> - [true] remove these parentheses - *[other] remove this attribute - }", - code = "", - applicability = "machine-applicable" - )] - pub attr_span: Span, - pub attr_path: String, - pub valid_without_list: bool, -} - #[derive(Diagnostic)] #[diag("`#[{$name}]` attribute cannot be used on {$target}")] #[warning( diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 534658ba386a9..24b195f07f80e 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -654,11 +654,6 @@ pub enum DeprecatedSinceKind { #[derive(Debug)] pub enum AttributeLintKind { - EmptyAttribute { - first_span: Span, - attr_path: String, - valid_without_list: bool, - }, InvalidTarget { name: String, target: &'static str, From 52653ef1c6594c73e8e1f059161614cbbeb4520a Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 19 Apr 2026 01:53:25 +0200 Subject: [PATCH 3/6] Remove `AttributeLintKind::InvalidTarget` variant --- compiler/rustc_attr_parsing/src/errors.rs | 20 +++++ .../rustc_attr_parsing/src/target_checking.rs | 24 ++++-- compiler/rustc_lint/src/early/diagnostics.rs | 15 +--- compiler/rustc_lint/src/lints.rs | 22 +---- compiler/rustc_lint_defs/src/lib.rs | 85 ++++--------------- 5 files changed, 53 insertions(+), 113 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index 12c83548b6a2b..c18caedca40ef 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -131,3 +131,23 @@ pub(crate) struct EmptyAttributeList<'a> { pub attr_path: &'a str, pub valid_without_list: bool, } + +#[derive(Diagnostic)] +#[diag("`#[{$name}]` attribute cannot be used on {$target}")] +#[warning( + "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" +)] +#[help("`#[{$name}]` can {$only}be applied to {$applied}")] +pub(crate) struct InvalidTargetLint { + pub name: String, + pub target: &'static str, + pub applied: DiagArgValue, + pub only: &'static str, + #[suggestion( + "remove the attribute", + code = "", + applicability = "machine-applicable", + style = "tool-only" + )] + pub attr_span: Span, +} diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 253a089e49f1a..81143e30c252d 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -1,7 +1,7 @@ use std::borrow::Cow; use rustc_ast::AttrStyle; -use rustc_errors::{DiagArgValue, MultiSpan, StashKey}; +use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan, StashKey}; use rustc_feature::Features; use rustc_hir::attrs::AttributeKind; use rustc_hir::lints::AttributeLintKind; @@ -11,7 +11,8 @@ use rustc_span::{BytePos, Span, Symbol, sym}; use crate::AttributeParser; use crate::context::{AcceptContext, Stage}; use crate::errors::{ - InvalidAttrAtCrateLevel, ItemFollowingInnerAttr, UnsupportedAttributesInWhere, + InvalidAttrAtCrateLevel, InvalidTargetLint, ItemFollowingInnerAttr, + UnsupportedAttributesInWhere, }; use crate::session_diagnostics::InvalidTarget; use crate::target_checking::Policy::Allow; @@ -142,14 +143,19 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { }; let attr_span = cx.attr_span; - cx.emit_lint( + cx.emit_dyn_lint( lint, - AttributeLintKind::InvalidTarget { - name: name.to_string(), - target: target.plural_name(), - only: if only { "only " } else { "" }, - applied, - attr_span, + move |dcx, level| { + InvalidTargetLint { + name: name.to_string(), + target: target.plural_name(), + only: if only { "only " } else { "" }, + applied: DiagArgValue::StrListSepByAnd( + applied.iter().map(|i| Cow::Owned(i.to_string())).collect(), + ), + attr_span, + } + .into_diag(dcx, level) }, attr_span, ); diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index d92be8bddf6c8..f617a512e414c 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,8 +1,7 @@ use std::any::Any; -use std::borrow::Cow; use rustc_data_structures::sync::DynSend; -use rustc_errors::{Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::lints::{AttributeLintKind, FormatWarning}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -35,18 +34,6 @@ pub struct DecorateAttrLint<'a, 'sess, 'tcx> { impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { match self.diagnostic { - AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { - lints::InvalidTargetLint { - name: name.clone(), - target, - applied: DiagArgValue::StrListSepByAnd( - applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), - ), - only, - attr_span: *attr_span, - } - .into_diag(dcx, level) - } &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 8bbc6ddf72cbc..2bd43588c08b4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::codes::*; use rustc_errors::formatting::DiagMessageAddArg; use rustc_errors::{ - Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, + Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, EmissionGuarantee, Level, Subdiagnostic, SuggestionStyle, msg, }; use rustc_hir as hir; @@ -3282,26 +3282,6 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } -#[derive(Diagnostic)] -#[diag("`#[{$name}]` attribute cannot be used on {$target}")] -#[warning( - "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" -)] -#[help("`#[{$name}]` can {$only}be applied to {$applied}")] -pub(crate) struct InvalidTargetLint { - pub name: String, - pub target: &'static str, - pub applied: DiagArgValue, - pub only: &'static str, - #[suggestion( - "remove the attribute", - code = "", - applicability = "machine-applicable", - style = "tool-only" - )] - pub attr_span: Span, -} - #[derive(Diagnostic)] #[diag( "{$is_used_as_inner -> diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 24b195f07f80e..8b86d1326e758 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -654,88 +654,35 @@ pub enum DeprecatedSinceKind { #[derive(Debug)] pub enum AttributeLintKind { - InvalidTarget { - name: String, - target: &'static str, - applied: Vec, - only: &'static str, - attr_span: Span, - }, - InvalidStyle { - name: String, - is_used_as_inner: bool, - target: &'static str, - target_span: Span, - }, + InvalidStyle { name: String, is_used_as_inner: bool, target: &'static str, target_span: Span }, UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), - DuplicateDocAlias { - first_definition: Span, - }, + DuplicateDocAlias { first_definition: Span }, DocAutoCfgExpectsHideOrShow, - DocAutoCfgHideShowUnexpectedItem { - attr_name: Symbol, - }, - DocAutoCfgHideShowExpectsList { - attr_name: Symbol, - }, + DocAutoCfgHideShowUnexpectedItem { attr_name: Symbol }, + DocAutoCfgHideShowExpectsList { attr_name: Symbol }, DocInvalid, AmbiguousDeriveHelpers, - DocUnknownInclude { - span: Span, - inner: &'static str, - value: Symbol, - }, - DocUnknownSpotlight { - span: Span, - }, - DocUnknownPasses { - name: Symbol, - span: Span, - }, - DocUnknownPlugins { - span: Span, - }, - DocUnknownAny { - name: Symbol, - }, + DocUnknownInclude { span: Span, inner: &'static str, value: Symbol }, + DocUnknownSpotlight { span: Span }, + DocUnknownPasses { name: Symbol, span: Span }, + DocUnknownPlugins { span: Span }, + DocUnknownAny { name: Symbol }, DocAutoCfgWrongLiteral, DocTestTakesList, - DocTestUnknown { - name: Symbol, - }, + DocTestUnknown { name: Symbol }, DocTestLiteral, AttrCrateLevelOnly, DoNotRecommendDoesNotExpectArgs, - CrateTypeUnknown { - span: Span, - suggested: Option, - }, + CrateTypeUnknown { span: Span, suggested: Option }, MalformedDoc, ExpectedNoArgs, ExpectedNameValue, - MalFormedDiagnosticAttribute { - attribute: &'static str, - options: &'static str, - span: Span, - }, - MalformedDiagnosticFormat { - warning: FormatWarning, - }, - DiagnosticWrappedParserError { - description: String, - label: String, - span: Span, - }, - IgnoredDiagnosticOption { - option_name: Symbol, - first_span: Span, - later_span: Span, - }, - MissingOptionsForDiagnosticAttribute { - attribute: &'static str, - options: &'static str, - }, + MalFormedDiagnosticAttribute { attribute: &'static str, options: &'static str, span: Span }, + MalformedDiagnosticFormat { warning: FormatWarning }, + DiagnosticWrappedParserError { description: String, label: String, span: Span }, + IgnoredDiagnosticOption { option_name: Symbol, first_span: Span, later_span: Span }, + MissingOptionsForDiagnosticAttribute { attribute: &'static str, options: &'static str }, NonMetaItemDiagnosticAttribute, } From ef3b8004113f58fec1191286a476daf47128c021 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 19 Apr 2026 02:11:28 +0200 Subject: [PATCH 4/6] Remove `AttributeLintKind::InvalidStyle` variant --- compiler/rustc_attr_parsing/src/errors.rs | 15 ++++++++++++ .../rustc_attr_parsing/src/target_checking.rs | 24 ++++++++++++------- compiler/rustc_lint/src/early/diagnostics.rs | 12 ---------- compiler/rustc_lint/src/lints.rs | 15 ------------ compiler/rustc_lint_defs/src/lib.rs | 1 - 5 files changed, 31 insertions(+), 36 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index c18caedca40ef..acdface243d23 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -151,3 +151,18 @@ pub(crate) struct InvalidTargetLint { )] pub attr_span: Span, } + +#[derive(Diagnostic)] +#[diag( + "{$is_used_as_inner -> + [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` + *[other] the `#![{$name}]` attribute can only be used at the crate root + }" +)] +pub(crate) struct InvalidAttrStyle<'a> { + pub name: &'a str, + pub is_used_as_inner: bool, + #[note("this attribute does not have an `!`, which means it is applied to this {$target}")] + pub target_span: Option, + pub target: &'static str, +} diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 81143e30c252d..65e716921f5cb 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -4,7 +4,6 @@ use rustc_ast::AttrStyle; use rustc_errors::{DiagArgValue, Diagnostic, MultiSpan, StashKey}; use rustc_feature::Features; use rustc_hir::attrs::AttributeKind; -use rustc_hir::lints::AttributeLintKind; use rustc_hir::{AttrItem, Attribute, MethodKind, Target}; use rustc_span::{BytePos, Span, Symbol, sym}; @@ -182,15 +181,24 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { return; } - let kind = AttributeLintKind::InvalidStyle { - name: cx.attr_path.to_string(), - is_used_as_inner: cx.attr_style == AttrStyle::Inner, - target: target.name(), - target_span: cx.target_span, - }; + let name = cx.attr_path.to_string(); + let is_used_as_inner = cx.attr_style == AttrStyle::Inner; + let target_span = cx.target_span; let attr_span = cx.attr_span; - cx.emit_lint(rustc_session::lint::builtin::UNUSED_ATTRIBUTES, kind, attr_span); + cx.emit_dyn_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + move |dcx, level| { + crate::errors::InvalidAttrStyle { + name: &name, + is_used_as_inner, + target_span: (!is_used_as_inner).then_some(target_span), + target: target.name(), + } + .into_diag(dcx, level) + }, + attr_span, + ); } // FIXME: Fix "Cannot determine resolution" error and remove built-in macros diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index f617a512e414c..79064c12c49be 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -34,18 +34,6 @@ pub struct DecorateAttrLint<'a, 'sess, 'tcx> { impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { match self.diagnostic { - &AttributeLintKind::InvalidStyle { - ref name, - is_used_as_inner, - target, - target_span, - } => lints::InvalidAttrStyle { - name: name.clone(), - is_used_as_inner, - target_span: (!is_used_as_inner).then_some(target_span), - target, - } - .into_diag(dcx, level), &AttributeLintKind::UnexpectedCfgName(name, value) => { check_cfg::unexpected_cfg_name(self.sess, self.tcx, name, value) .into_diag(dcx, level) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 2bd43588c08b4..ed21ed08c51be 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3282,21 +3282,6 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } -#[derive(Diagnostic)] -#[diag( - "{$is_used_as_inner -> - [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` - *[other] the `#![{$name}]` attribute can only be used at the crate root - }" -)] -pub(crate) struct InvalidAttrStyle { - pub name: String, - pub is_used_as_inner: bool, - #[note("this attribute does not have an `!`, which means it is applied to this {$target}")] - pub target_span: Option, - pub target: &'static str, -} - #[derive(Diagnostic)] #[diag("malformed `doc` attribute input")] #[warning( diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 8b86d1326e758..4f342e6072a01 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -654,7 +654,6 @@ pub enum DeprecatedSinceKind { #[derive(Debug)] pub enum AttributeLintKind { - InvalidStyle { name: String, is_used_as_inner: bool, target: &'static str, target_span: Span }, UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), DuplicateDocAlias { first_definition: Span }, From 0c93197a2847f2179a781112457f54bb2998e135 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 19 Apr 2026 02:19:30 +0200 Subject: [PATCH 5/6] Remove `AttributeLintKind::DuplicateDocAlias` variant --- compiler/rustc_attr_parsing/src/attributes/doc.rs | 6 ++++-- compiler/rustc_attr_parsing/src/errors.rs | 7 +++++++ compiler/rustc_lint/src/early/diagnostics.rs | 3 --- compiler/rustc_lint/src/lints.rs | 7 ------- compiler/rustc_lint_defs/src/lib.rs | 1 - 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index 3983f892744ba..ea5d7cf5cda80 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -255,9 +255,11 @@ impl DocParser { } if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { - cx.emit_lint( + cx.emit_dyn_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - AttributeLintKind::DuplicateDocAlias { first_definition }, + move |dcx, level| { + crate::errors::DocAliasDuplicated { first_definition }.into_diag(dcx, level) + }, span, ); } diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index acdface243d23..75a97c49f29cf 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -166,3 +166,10 @@ pub(crate) struct InvalidAttrStyle<'a> { pub target_span: Option, pub target: &'static str, } + +#[derive(Diagnostic)] +#[diag("doc alias is duplicated")] +pub(crate) struct DocAliasDuplicated { + #[label("first defined here")] + pub first_definition: Span, +} diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 79064c12c49be..2ff0ab66fde8f 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -42,9 +42,6 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value) .into_diag(dcx, level) } - &AttributeLintKind::DuplicateDocAlias { first_definition } => { - lints::DocAliasDuplicated { first_defn: first_definition }.into_diag(dcx, level) - } &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { lints::DocAutoCfgExpectsHideOrShow.into_diag(dcx, level) diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ed21ed08c51be..24c59958077b2 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3303,13 +3303,6 @@ pub(crate) struct ExpectedNoArgs; )] pub(crate) struct ExpectedNameValue; -#[derive(Diagnostic)] -#[diag("doc alias is duplicated")] -pub(crate) struct DocAliasDuplicated { - #[label("first defined here")] - pub first_defn: Span, -} - #[derive(Diagnostic)] #[diag("only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]`")] pub(crate) struct DocAutoCfgExpectsHideOrShow; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 4f342e6072a01..99efe5cfed9b3 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -656,7 +656,6 @@ pub enum DeprecatedSinceKind { pub enum AttributeLintKind { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), - DuplicateDocAlias { first_definition: Span }, DocAutoCfgExpectsHideOrShow, DocAutoCfgHideShowUnexpectedItem { attr_name: Symbol }, DocAutoCfgHideShowExpectsList { attr_name: Symbol }, From f658d2613c73f909abbf6d5cbaee702c22c14065 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 19 Apr 2026 02:31:23 +0200 Subject: [PATCH 6/6] Remove `AttributeLintKind::DocAutoCfgExpectsHideOrShow` variant --- .../rustc_attr_parsing/src/attributes/doc.rs | 16 +++++++--------- compiler/rustc_attr_parsing/src/errors.rs | 4 ++++ compiler/rustc_lint/src/early/diagnostics.rs | 4 ---- compiler/rustc_lint/src/lints.rs | 4 ---- compiler/rustc_lint_defs/src/lib.rs | 1 - 5 files changed, 11 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/doc.rs b/compiler/rustc_attr_parsing/src/attributes/doc.rs index ea5d7cf5cda80..665c516c3e8e8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/doc.rs +++ b/compiler/rustc_attr_parsing/src/attributes/doc.rs @@ -13,6 +13,7 @@ use thin_vec::ThinVec; use super::prelude::{ALL_TARGETS, AllowedTargets}; use super::{AcceptMapping, AttributeParser}; use crate::context::{AcceptContext, FinalizeContext, Stage}; +use crate::errors::{DocAliasDuplicated, DocAutoCfgExpectsHideOrShow, IllFormedAttributeInput}; use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser}; use crate::session_diagnostics::{ DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel, @@ -257,9 +258,7 @@ impl DocParser { if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() { cx.emit_dyn_lint( rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - move |dcx, level| { - crate::errors::DocAliasDuplicated { first_definition }.into_diag(dcx, level) - }, + move |dcx, level| DocAliasDuplicated { first_definition }.into_diag(dcx, level), span, ); } @@ -345,9 +344,9 @@ impl DocParser { ArgParser::List(list) => { for meta in list.mixed() { let MetaItemOrLitParser::MetaItemParser(item) = meta else { - cx.emit_lint( + cx.emit_dyn_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - AttributeLintKind::DocAutoCfgExpectsHideOrShow, + |dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level), meta.span(), ); continue; @@ -356,9 +355,9 @@ impl DocParser { Some(sym::hide) => (HideOrShow::Hide, sym::hide), Some(sym::show) => (HideOrShow::Show, sym::show), _ => { - cx.emit_lint( + cx.emit_dyn_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, - AttributeLintKind::DocAutoCfgExpectsHideOrShow, + |dcx, level| DocAutoCfgExpectsHideOrShow.into_diag(dcx, level), item.span(), ); continue; @@ -671,8 +670,7 @@ impl DocParser { cx.emit_dyn_lint( rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES, move |dcx, level| { - crate::errors::IllFormedAttributeInput::new(&suggestions, None, None) - .into_diag(dcx, level) + IllFormedAttributeInput::new(&suggestions, None, None).into_diag(dcx, level) }, span, ); diff --git a/compiler/rustc_attr_parsing/src/errors.rs b/compiler/rustc_attr_parsing/src/errors.rs index 75a97c49f29cf..8148a859958b5 100644 --- a/compiler/rustc_attr_parsing/src/errors.rs +++ b/compiler/rustc_attr_parsing/src/errors.rs @@ -173,3 +173,7 @@ pub(crate) struct DocAliasDuplicated { #[label("first defined here")] pub first_definition: Span, } + +#[derive(Diagnostic)] +#[diag("only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]`")] +pub(crate) struct DocAutoCfgExpectsHideOrShow; diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 2ff0ab66fde8f..fb59cd35ad463 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -43,10 +43,6 @@ impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { .into_diag(dcx, level) } - &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { - lints::DocAutoCfgExpectsHideOrShow.into_diag(dcx, level) - } - &AttributeLintKind::AmbiguousDeriveHelpers => { lints::AmbiguousDeriveHelpers.into_diag(dcx, level) } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 24c59958077b2..b92efc408ae81 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3303,10 +3303,6 @@ pub(crate) struct ExpectedNoArgs; )] pub(crate) struct ExpectedNameValue; -#[derive(Diagnostic)] -#[diag("only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]`")] -pub(crate) struct DocAutoCfgExpectsHideOrShow; - #[derive(Diagnostic)] #[diag("there exists a built-in attribute with the same name")] pub(crate) struct AmbiguousDeriveHelpers; diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 99efe5cfed9b3..29da46770d52b 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -656,7 +656,6 @@ pub enum DeprecatedSinceKind { pub enum AttributeLintKind { UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>), UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>), - DocAutoCfgExpectsHideOrShow, DocAutoCfgHideShowUnexpectedItem { attr_name: Symbol }, DocAutoCfgHideShowExpectsList { attr_name: Symbol }, DocInvalid,