From cbc661022e4954731209d63d47e22762c7e73bc0 Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Thu, 12 Feb 2026 22:14:49 +0100 Subject: [PATCH] Port `#[rustc_diagnostic_item]` to the new attribute parsers --- .../src/attributes/rustc_internal.rs | 39 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_expand/src/base.rs | 2 +- .../rustc_hir/src/attrs/data_structures.rs | 3 ++ .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- compiler/rustc_passes/src/diagnostic_items.rs | 16 +++----- compiler/rustc_resolve/src/diagnostics.rs | 12 +++--- .../rustc_resolve/src/late/diagnostics.rs | 10 ++--- 9 files changed, 61 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs index 0d19dc25d402c..ea5501af96665 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs @@ -1103,6 +1103,45 @@ impl NoArgsAttributeParser for RustcEffectiveVisibilityParser { const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility; } +pub(crate) struct RustcDiagnosticItemParser; + +impl SingleAttributeParser for RustcDiagnosticItemParser { + const PATH: &[Symbol] = &[sym::rustc_diagnostic_item]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[ + Allow(Target::Trait), + Allow(Target::Struct), + Allow(Target::Enum), + Allow(Target::MacroDef), + Allow(Target::TyAlias), + Allow(Target::AssocTy), + Allow(Target::AssocConst), + Allow(Target::Fn), + Allow(Target::Const), + Allow(Target::Mod), + Allow(Target::Impl { of_trait: false }), + Allow(Target::Method(MethodKind::Inherent)), + Allow(Target::Method(MethodKind::Trait { body: false })), + Allow(Target::Method(MethodKind::Trait { body: true })), + Allow(Target::Method(MethodKind::TraitImpl)), + Allow(Target::Crate), + ]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(value) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + Some(AttributeKind::RustcDiagnosticItem(value)) + } +} + pub(crate) struct RustcSymbolName; impl SingleAttributeParser for RustcSymbolName { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 87aa4150becd3..546654d0ce795 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -203,6 +203,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 91f98d475f00a..5efaea44b3b9d 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -919,7 +919,7 @@ impl SyntaxExtension { fn get_hide_backtrace(attrs: &[hir::Attribute]) -> bool { // FIXME(estebank): instead of reusing `#[rustc_diagnostic_item]` as a proxy, introduce a // new attribute purely for this under the `#[diagnostic]` namespace. - ast::attr::find_by_name(attrs, sym::rustc_diagnostic_item).is_some() + find_attr!(attrs, AttributeKind::RustcDiagnosticItem(..)) } /// Constructs a syntax extension with the given properties diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 8e68a3d002334..f69ee128fce87 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -1153,6 +1153,9 @@ pub enum AttributeKind { /// Represents `#[rustc_deprecated_safe_2024]` RustcDeprecatedSafe2024 { suggestion: Symbol }, + /// Represents `#[rustc_diagnostic_item]` + RustcDiagnosticItem(Symbol), + /// Represents `#[rustc_dummy]`. RustcDummy, diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e68ab1c42bafd..553c29953f9b7 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -112,6 +112,7 @@ impl AttributeKind { RustcDelayedBugFromInsideQuery => No, RustcDenyExplicitImpl(..) => No, RustcDeprecatedSafe2024 { .. } => Yes, + RustcDiagnosticItem(..) => Yes, RustcDummy => No, RustcDumpDefParents => No, RustcDumpItemBounds => No, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b6f0e9fedd6d8..e7ea27a280072 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -307,6 +307,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::RustcDelayedBugFromInsideQuery | AttributeKind::RustcDenyExplicitImpl(..) | AttributeKind::RustcDeprecatedSafe2024 {..} + | AttributeKind::RustcDiagnosticItem(..) | AttributeKind::RustcDummy | AttributeKind::RustcDumpDefParents | AttributeKind::RustcDumpItemBounds @@ -398,7 +399,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::panic_handler | sym::lang | sym::default_lib_allocator - | sym::rustc_diagnostic_item | sym::rustc_nonnull_optimization_guaranteed | sym::rustc_inherit_overflow_checks | sym::rustc_on_unimplemented diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index 8f572af02c249..c7b1dcb95e336 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -9,20 +9,21 @@ //! //! * Compiler internal types like `Ty` and `TyCtxt` +use rustc_hir::attrs::AttributeKind; use rustc_hir::diagnostic_items::DiagnosticItems; -use rustc_hir::{Attribute, CRATE_OWNER_ID, OwnerId}; +use rustc_hir::{CRATE_OWNER_ID, OwnerId, find_attr}; use rustc_middle::query::{LocalCrate, Providers}; use rustc_middle::ty::TyCtxt; +use rustc_span::Symbol; use rustc_span::def_id::{DefId, LOCAL_CRATE}; -use rustc_span::{Symbol, sym}; use crate::errors::DuplicateDiagnosticItemInCrate; fn observe_item<'tcx>(tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, owner: OwnerId) { let attrs = tcx.hir_attrs(owner.into()); - if let Some(name) = extract(attrs) { + if let Some(name) = find_attr!(attrs, AttributeKind::RustcDiagnosticItem(name) => name) { // insert into our table - collect_item(tcx, diagnostic_items, name, owner.to_def_id()); + collect_item(tcx, diagnostic_items, *name, owner.to_def_id()); } } @@ -53,13 +54,6 @@ fn report_duplicate_item( }); } -/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. -fn extract(attrs: &[Attribute]) -> Option { - attrs.iter().find_map(|attr| { - if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None } - }) -} - /// Traverse and collect the diagnostic items in the current fn diagnostic_items(tcx: TyCtxt<'_>, _: LocalCrate) -> DiagnosticItems { // Initialize the collector. diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9a88f74b5b179..ac6188c2c1523 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1425,14 +1425,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // a note about editions let note = if let Some(did) = did { let requires_note = !did.is_local() - && this.tcx.get_attrs(did, sym::rustc_diagnostic_item).any( - |attr| { - [sym::TryInto, sym::TryFrom, sym::FromIterator] - .map(|x| Some(x)) - .contains(&attr.value_str()) - }, + && find_attr!( + this.tcx.get_all_attrs(did), + AttributeKind::RustcDiagnosticItem( + sym::TryInto | sym::TryFrom | sym::FromIterator + ) ); - requires_note.then(|| { format!( "'{}' is included in the prelude starting in Edition 2021", diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 95f0d3e67ef2d..ec577a1aea83f 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -21,7 +21,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; -use rustc_hir::{MissingLifetimeKind, PrimTy}; +use rustc_hir::{MissingLifetimeKind, PrimTy, find_attr}; use rustc_middle::ty; use rustc_session::{Session, lint}; use rustc_span::edit_distance::{edit_distance, find_best_match_for_name}; @@ -2446,10 +2446,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .iter() .filter_map(|candidate| candidate.did) .find(|did| { - self.r - .tcx - .get_attrs(*did, sym::rustc_diagnostic_item) - .any(|attr| attr.value_str() == Some(sym::Default)) + find_attr!( + self.r.tcx.get_all_attrs(*did), + AttributeKind::RustcDiagnosticItem(sym::Default) + ) }); let Some(default_trait) = default_trait else { return;