Rollup merge of #155504 - GuillaumeGomez:rm-attributelintkind, r=JonathanBrouwer

Remove `AttributeLintKind` variants - part 2

Follow-up of https://github.com/rust-lang/rust/pull/154432.
Part of https://github.com/rust-lang/rust/issues/153099.

r? @JonathanBrouwer
This commit is contained in:
Jonathan Brouwer
2026-04-19 16:04:34 +02:00
committed by GitHub
8 changed files with 190 additions and 269 deletions
@@ -13,6 +13,7 @@
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,
@@ -255,9 +256,9 @@ fn add_alias<S: Stage>(
}
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| DocAliasDuplicated { first_definition }.into_diag(dcx, level),
span,
);
}
@@ -343,9 +344,9 @@ fn parse_auto_cfg<S: Stage>(
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;
@@ -354,9 +355,9 @@ fn parse_auto_cfg<S: Stage>(
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;
@@ -666,12 +667,10 @@ fn accept_single_doc_attr<S: Stage>(
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| {
IllFormedAttributeInput::new(&suggestions, None, None).into_diag(dcx, level)
},
span,
);
+15 -5
View File
@@ -897,11 +897,18 @@ pub(crate) fn expected_specific_argument_strings(
}
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,
);
}
@@ -916,9 +923,12 @@ pub(crate) fn warn_ill_formed_attribute_input_with_help(
) {
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,
);
}
+112 -1
View File
@@ -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,114 @@ pub(crate) struct UnsafeAttrOutsideUnsafeLint {
#[subdiagnostic]
pub suggestion: Option<crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion>,
}
#[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<IllFormedAttributeInputHelp>,
}
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,
}
#[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,
}
#[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 ->
[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<Span>,
pub target: &'static str,
}
#[derive(Diagnostic)]
#[diag("doc alias is duplicated")]
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;
@@ -1,17 +1,17 @@
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;
use rustc_hir::{AttrItem, Attribute, MethodKind, Target};
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 +142,19 @@ pub(crate) fn check_target(
};
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,
);
@@ -176,15 +181,24 @@ pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess
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
@@ -8,10 +8,9 @@
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 {
+1 -53
View File
@@ -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,50 +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::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,
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(),
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,
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)
@@ -87,13 +42,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
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)
}
&AttributeLintKind::AmbiguousDeriveHelpers => {
lints::AmbiguousDeriveHelpers.into_diag(dcx, level)
+1 -95
View File
@@ -6,7 +6,7 @@
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;
@@ -3025,32 +3025,6 @@ pub(crate) enum CargoHelp {
}
}
// 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<IllFormedAttributeInputHelp>,
}
#[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> {
@@ -3308,63 +3282,6 @@ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
}
}
#[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(
"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 ->
[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<Span>,
pub target: &'static str,
}
#[derive(Diagnostic)]
#[diag("malformed `doc` attribute input")]
#[warning(
@@ -3386,17 +3303,6 @@ pub(crate) struct InvalidAttrStyle {
)]
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;
#[derive(Diagnostic)]
#[diag("there exists a built-in attribute with the same name")]
pub(crate) struct AmbiguousDeriveHelpers;
+14 -80
View File
@@ -654,98 +654,32 @@ pub enum DeprecatedSinceKind {
#[derive(Debug)]
pub enum AttributeLintKind {
IllFormedAttributeInput {
suggestions: Vec<String>,
docs: Option<&'static str>,
help: Option<String>,
},
EmptyAttribute {
first_span: Span,
attr_path: String,
valid_without_list: bool,
},
InvalidTarget {
name: String,
target: &'static str,
applied: Vec<String>,
only: &'static str,
attr_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,
},
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<Symbol>,
},
CrateTypeUnknown { span: Span, suggested: Option<Symbol> },
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,
}