about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-07-11 19:45:22 +0200
committerGitHub <noreply@github.com>2025-07-11 19:45:22 +0200
commitc8780fff6a1f3bda416231342fae0dde986ada39 (patch)
tree3da343fd13981e92c1ccfd5fc9e32d205e5b0315
parent855e0fe46e68d94e9f6147531b75ac2d488c548e (diff)
parente584ed0de2150ad11b24ed75e954825fd5b273f9 (diff)
downloadrust-c8780fff6a1f3bda416231342fae0dde986ada39.tar.gz
rust-c8780fff6a1f3bda416231342fae0dde986ada39.zip
Rollup merge of #143403 - GrigorenkoPV:attributes/traits, r=jdonszelmann
Port several trait/coherence-related attributes the new attribute system

Part of rust-lang/rust#131229

This ports:
- `#[const_trait]`
- `#[rustc_deny_explicit_impl]`
- `#[rustc_do_not_implement_via_object]`
- `#[rustc_coinductive]`
- `#[type_const]`
- `#[rustc_specialization_trait]`
- `#[rustc_unsafe_specialization_marker]`
- `#[marker]`
- `#[fundamental]`
- `#[rustc_paren_sugar]`
- `#[rustc_allow_incoherent_impl]`
- `#[rustc_coherence_is_core]`

This also changes `#[marker]` to error on duplicates instead of warning.
cc rust-lang/rust#142838, but I don't think it matters too much, since it's unstable.

r? ``@oli-obk``
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs36
-rw-r--r--compiler/rustc_attr_data_structures/src/encode_cross_crate.rs12
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs99
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs19
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs28
-rw-r--r--compiler/rustc_middle/src/hir/map.rs5
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs3
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs5
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs11
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs12
-rw-r--r--compiler/rustc_passes/src/check_attr.rs63
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr45
-rw-r--r--tests/ui/const-generics/mgca/bad-type_const-syntax.stderr18
-rw-r--r--tests/ui/marker_trait_attr/marker-attribute-with-values.stderr22
15 files changed, 299 insertions, 90 deletions
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index b656db32528..f61efcf2388 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -198,6 +198,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_allow_const_fn_unstable]`.
     AllowConstFnUnstable(ThinVec<Symbol>, Span),
 
+    /// Represents `#[rustc_allow_incoherent_impl]`.
+    AllowIncoherentImpl(Span),
+
     /// Represents `#[allow_internal_unstable]`.
     AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
 
@@ -211,6 +214,12 @@ pub enum AttributeKind {
         span: Span,
     },
 
+    /// Represents `#[rustc_coherence_is_core]`.
+    CoherenceIsCore,
+
+    /// Represents `#[rustc_coinductive]`.
+    Coinductive(Span),
+
     /// Represents `#[cold]`.
     Cold(Span),
 
@@ -234,9 +243,18 @@ pub enum AttributeKind {
     /// Represents `#[rustc_const_stable_indirect]`.
     ConstStabilityIndirect,
 
+    /// Represents `#[const_trait]`.
+    ConstTrait(Span),
+
+    ///Represents `#[rustc_deny_explicit_impl]`.
+    DenyExplicitImpl(Span),
+
     /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
     Deprecation { deprecation: Deprecation, span: Span },
 
+    /// Represents `#[rustc_do_not_implement_via_object]`.
+    DoNotImplementViaObject(Span),
+
     /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
     DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
 
@@ -260,6 +278,9 @@ pub enum AttributeKind {
     /// Represents `#[ffi_pure]`.
     FfiPure(Span),
 
+    /// Represents `#[fundamental]`.
+    Fundamental,
+
     /// Represents `#[ignore]`
     Ignore {
         span: Span,
@@ -282,6 +303,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_macro_transparency]`.
     MacroTransparency(Transparency),
 
+    /// Represents `#[marker]`.
+    Marker(Span),
+
     /// Represents [`#[may_dangle]`](https://std-dev-guide.rust-lang.org/tricky/may-dangle.html).
     MayDangle(Span),
 
@@ -307,6 +331,9 @@ pub enum AttributeKind {
     /// Represents `#[optimize(size|speed)]`
     Optimize(OptimizeAttr, Span),
 
+    /// Represents `#[rustc_paren_sugar]`.
+    ParenSugar(Span),
+
     /// Represents `#[rustc_pass_by_value]` (used by the `rustc_pass_by_value` lint).
     PassByValue(Span),
 
@@ -331,6 +358,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_skip_during_method_dispatch]`.
     SkipDuringMethodDispatch { array: bool, boxed_slice: bool, span: Span },
 
+    /// Represents `#[rustc_specialization_trait]`.
+    SpecializationTrait(Span),
+
     /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
     Stability {
         stability: Stability,
@@ -347,6 +377,12 @@ pub enum AttributeKind {
     /// Represents `#[track_caller]`
     TrackCaller(Span),
 
+    /// Represents `#[type_const]`.
+    TypeConst(Span),
+
+    /// Represents `#[rustc_unsafe_specialization_marker]`.
+    UnsafeSpecializationMarker(Span),
+
     /// Represents `#[used]`
     Used { used_by: UsedBy, span: Span },
     // tidy-alphabetical-end
diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
index 5414c7b103b..ad587523e03 100644
--- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
+++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs
@@ -15,27 +15,35 @@ impl AttributeKind {
             // tidy-alphabetical-start
             Align { .. } => No,
             AllowConstFnUnstable(..) => No,
+            AllowIncoherentImpl(..) => No,
             AllowInternalUnstable(..) => Yes,
             AsPtr(..) => Yes,
             BodyStability { .. } => No,
+            CoherenceIsCore => No,
+            Coinductive(..) => No,
             Cold(..) => No,
             Confusables { .. } => Yes,
             ConstContinue(..) => No,
             ConstStability { .. } => Yes,
             ConstStabilityIndirect => No,
+            ConstTrait(..) => No,
+            DenyExplicitImpl(..) => No,
             Deprecation { .. } => Yes,
+            DoNotImplementViaObject(..) => No,
             DocComment { .. } => Yes,
             Dummy => No,
             ExportName { .. } => Yes,
             ExportStable => No,
             FfiConst(..) => No,
             FfiPure(..) => No,
+            Fundamental { .. } => Yes,
             Ignore { .. } => No,
             Inline(..) => No,
             LinkName { .. } => Yes,
             LinkSection { .. } => No,
             LoopMatch(..) => No,
             MacroTransparency(..) => Yes,
+            Marker(..) => No,
             MayDangle(..) => No,
             MustUse { .. } => Yes,
             Naked(..) => No,
@@ -43,6 +51,7 @@ impl AttributeKind {
             NoMangle(..) => No,
             NonExhaustive(..) => Yes,
             Optimize(..) => No,
+            ParenSugar(..) => No,
             PassByValue(..) => Yes,
             Path(..) => No,
             PubTransparent(..) => Yes,
@@ -51,10 +60,13 @@ impl AttributeKind {
             RustcLayoutScalarValidRangeStart(..) => Yes,
             RustcObjectLifetimeDefault => No,
             SkipDuringMethodDispatch { .. } => No,
+            SpecializationTrait(..) => No,
             Stability { .. } => Yes,
             StdInternalSymbol(..) => No,
             TargetFeature(..) => No,
             TrackCaller(..) => Yes,
+            TypeConst(..) => Yes,
+            UnsafeSpecializationMarker(..) => No,
             Used { .. } => No,
             // tidy-alphabetical-end
         }
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index c29dbf4d1e9..ee8a33ae9c4 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -2,14 +2,15 @@ use core::mem;
 
 use rustc_attr_data_structures::AttributeKind;
 use rustc_feature::{AttributeTemplate, template};
-use rustc_span::{Symbol, sym};
+use rustc_span::{Span, Symbol, sym};
 
-use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::attributes::{
+    AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
+};
 use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 
 pub(crate) struct SkipDuringMethodDispatchParser;
-
 impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
     const PATH: &[Symbol] = &[sym::rustc_skip_during_method_dispatch];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
@@ -52,3 +53,95 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
         Some(AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: cx.attr_span })
     }
 }
+
+pub(crate) struct ParenSugarParser;
+impl<S: Stage> NoArgsAttributeParser<S> for ParenSugarParser {
+    const PATH: &[Symbol] = &[sym::rustc_paren_sugar];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::ParenSugar;
+}
+
+pub(crate) struct TypeConstParser;
+impl<S: Stage> NoArgsAttributeParser<S> for TypeConstParser {
+    const PATH: &[Symbol] = &[sym::type_const];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::TypeConst;
+}
+
+// Markers
+
+pub(crate) struct MarkerParser;
+impl<S: Stage> NoArgsAttributeParser<S> for MarkerParser {
+    const PATH: &[Symbol] = &[sym::marker];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::Marker;
+}
+
+pub(crate) struct DenyExplicitImplParser;
+impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
+    const PATH: &[Symbol] = &[sym::rustc_deny_explicit_impl];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
+}
+
+pub(crate) struct DoNotImplementViaObjectParser;
+impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
+    const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
+}
+
+// Const traits
+
+pub(crate) struct ConstTraitParser;
+impl<S: Stage> NoArgsAttributeParser<S> for ConstTraitParser {
+    const PATH: &[Symbol] = &[sym::const_trait];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::ConstTrait;
+}
+
+// Specialization
+
+pub(crate) struct SpecializationTraitParser;
+impl<S: Stage> NoArgsAttributeParser<S> for SpecializationTraitParser {
+    const PATH: &[Symbol] = &[sym::rustc_specialization_trait];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::SpecializationTrait;
+}
+
+pub(crate) struct UnsafeSpecializationMarkerParser;
+impl<S: Stage> NoArgsAttributeParser<S> for UnsafeSpecializationMarkerParser {
+    const PATH: &[Symbol] = &[sym::rustc_unsafe_specialization_marker];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::UnsafeSpecializationMarker;
+}
+
+// Coherence
+
+pub(crate) struct CoinductiveParser;
+impl<S: Stage> NoArgsAttributeParser<S> for CoinductiveParser {
+    const PATH: &[Symbol] = &[sym::rustc_coinductive];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::Coinductive;
+}
+
+pub(crate) struct AllowIncoherentImplParser;
+impl<S: Stage> NoArgsAttributeParser<S> for AllowIncoherentImplParser {
+    const PATH: &[Symbol] = &[sym::rustc_allow_incoherent_impl];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = AttributeKind::AllowIncoherentImpl;
+}
+
+pub(crate) struct CoherenceIsCoreParser;
+impl<S: Stage> NoArgsAttributeParser<S> for CoherenceIsCoreParser {
+    const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore;
+}
+
+pub(crate) struct FundamentalParser;
+impl<S: Stage> NoArgsAttributeParser<S> for FundamentalParser {
+    const PATH: &[Symbol] = &[sym::fundamental];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Fundamental;
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index dbe1a5b2ad0..cc10bb3098a 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -43,7 +43,12 @@ use crate::attributes::stability::{
     BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
 };
 use crate::attributes::test_attrs::IgnoreParser;
-use crate::attributes::traits::SkipDuringMethodDispatchParser;
+use crate::attributes::traits::{
+    AllowIncoherentImplParser, CoherenceIsCoreParser, CoinductiveParser, ConstTraitParser,
+    DenyExplicitImplParser, DoNotImplementViaObjectParser, FundamentalParser, MarkerParser,
+    ParenSugarParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
+    UnsafeSpecializationMarkerParser,
+};
 use crate::attributes::transparency::TransparencyParser;
 use crate::attributes::{AttributeParser as _, Combine, Single, WithoutArgs};
 use crate::parser::{ArgParser, MetaItemParser, PathParser};
@@ -146,22 +151,34 @@ attribute_parsers!(
         Single<RustcObjectLifetimeDefaultParser>,
         Single<SkipDuringMethodDispatchParser>,
         Single<TransparencyParser>,
+        Single<WithoutArgs<AllowIncoherentImplParser>>,
         Single<WithoutArgs<AsPtrParser>>,
+        Single<WithoutArgs<CoherenceIsCoreParser>>,
+        Single<WithoutArgs<CoinductiveParser>>,
         Single<WithoutArgs<ColdParser>>,
         Single<WithoutArgs<ConstContinueParser>>,
         Single<WithoutArgs<ConstStabilityIndirectParser>>,
+        Single<WithoutArgs<ConstTraitParser>>,
+        Single<WithoutArgs<DenyExplicitImplParser>>,
+        Single<WithoutArgs<DoNotImplementViaObjectParser>>,
         Single<WithoutArgs<ExportStableParser>>,
         Single<WithoutArgs<FfiConstParser>>,
         Single<WithoutArgs<FfiPureParser>>,
+        Single<WithoutArgs<FundamentalParser>>,
         Single<WithoutArgs<LoopMatchParser>>,
+        Single<WithoutArgs<MarkerParser>>,
         Single<WithoutArgs<MayDangleParser>>,
         Single<WithoutArgs<NoImplicitPreludeParser>>,
         Single<WithoutArgs<NoMangleParser>>,
         Single<WithoutArgs<NonExhaustiveParser>>,
+        Single<WithoutArgs<ParenSugarParser>>,
         Single<WithoutArgs<PassByValueParser>>,
         Single<WithoutArgs<PubTransparentParser>>,
+        Single<WithoutArgs<SpecializationTraitParser>>,
         Single<WithoutArgs<StdInternalSymbolParser>>,
         Single<WithoutArgs<TrackCallerParser>>,
+        Single<WithoutArgs<TypeConstParser>>,
+        Single<WithoutArgs<UnsafeSpecializationMarkerParser>>,
         // tidy-alphabetical-end
     ];
 );
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index bd25b4a3260..80bf13dc4b7 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -7,6 +7,7 @@
 //! `tcx.inherent_impls(def_id)`). That value, however,
 //! is computed by selecting an idea from this table.
 
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -85,7 +86,10 @@ impl<'tcx> InherentCollect<'tcx> {
             }
 
             for &impl_item in items {
-                if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
+                if !find_attr!(
+                    self.tcx.get_all_attrs(impl_item),
+                    AttributeKind::AllowIncoherentImpl(_)
+                ) {
                     let impl_span = self.tcx.def_span(impl_def_id);
                     return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant {
                         span: impl_span,
@@ -116,7 +120,10 @@ impl<'tcx> InherentCollect<'tcx> {
         if !self.tcx.hir_rustc_coherence_is_core() {
             if self.tcx.features().rustc_attrs() {
                 for &impl_item in items {
-                    if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
+                    if !find_attr!(
+                        self.tcx.get_all_attrs(impl_item),
+                        AttributeKind::AllowIncoherentImpl(_)
+                    ) {
                         let span = self.tcx.def_span(impl_def_id);
                         return Err(self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive {
                             span,
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index a185291887d..431d99a572d 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -852,39 +852,41 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
+    let attrs = tcx.get_all_attrs(def_id);
     // Only regular traits can be const.
-    let constness = if !is_alias && tcx.has_attr(def_id, sym::const_trait) {
+    let constness = if !is_alias && find_attr!(attrs, AttributeKind::ConstTrait(_)) {
         hir::Constness::Const
     } else {
         hir::Constness::NotConst
     };
 
-    let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
+    let paren_sugar = find_attr!(attrs, AttributeKind::ParenSugar(_));
     if paren_sugar && !tcx.features().unboxed_closures() {
         tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
     }
 
     // Only regular traits can be marker.
-    let is_marker = !is_alias && tcx.has_attr(def_id, sym::marker);
+    let is_marker = !is_alias && find_attr!(attrs, AttributeKind::Marker(_));
 
-    let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
-    let is_fundamental = tcx.has_attr(def_id, sym::fundamental);
+    let rustc_coinductive = find_attr!(attrs, AttributeKind::Coinductive(_));
+    let is_fundamental = find_attr!(attrs, AttributeKind::Fundamental);
 
     let [skip_array_during_method_dispatch, skip_boxed_slice_during_method_dispatch] = find_attr!(
-        tcx.get_all_attrs(def_id),
-        AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span:_ } => [*array, *boxed_slice]
+        attrs,
+        AttributeKind::SkipDuringMethodDispatch { array, boxed_slice, span: _ } => [*array, *boxed_slice]
     )
     .unwrap_or([false; 2]);
 
-    let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
+    let specialization_kind = if find_attr!(attrs, AttributeKind::UnsafeSpecializationMarker(_)) {
         ty::trait_def::TraitSpecializationKind::Marker
-    } else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
+    } else if find_attr!(attrs, AttributeKind::SpecializationTrait(_)) {
         ty::trait_def::TraitSpecializationKind::AlwaysApplicable
     } else {
         ty::trait_def::TraitSpecializationKind::None
     };
-    let must_implement_one_of = tcx
-        .get_attr(def_id, sym::rustc_must_implement_one_of)
+    let must_implement_one_of = attrs
+        .iter()
+        .find(|attr| attr.has_name(sym::rustc_must_implement_one_of))
         // Check that there are at least 2 arguments of `#[rustc_must_implement_one_of]`
         // and that they are all identifiers
         .and_then(|attr| match attr.meta_item_list() {
@@ -958,8 +960,8 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
             no_dups.then_some(list)
         });
 
-    let deny_explicit_impl = tcx.has_attr(def_id, sym::rustc_deny_explicit_impl);
-    let implement_via_object = !tcx.has_attr(def_id, sym::rustc_do_not_implement_via_object);
+    let deny_explicit_impl = find_attr!(attrs, AttributeKind::DenyExplicitImpl(_));
+    let implement_via_object = !find_attr!(attrs, AttributeKind::DoNotImplementViaObject(_));
 
     ty::TraitDef {
         def_id: def_id.to_def_id(),
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index 291707878a3..84710e5e636 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -4,6 +4,7 @@
 
 use rustc_abi::ExternAbi;
 use rustc_ast::visit::{VisitorResult, walk_list};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::svh::Svh;
@@ -15,7 +16,7 @@ use rustc_hir::intravisit::Visitor;
 use rustc_hir::*;
 use rustc_hir_pretty as pprust_hir;
 use rustc_span::def_id::StableCrateId;
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spans};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, with_metavar_spans};
 
 use crate::hir::{ModuleItems, nested_filter};
 use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
@@ -369,7 +370,7 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 
     pub fn hir_rustc_coherence_is_core(self) -> bool {
-        self.hir_krate_attrs().iter().any(|attr| attr.has_name(sym::rustc_coherence_is_core))
+        find_attr!(self.hir_krate_attrs(), AttributeKind::CoherenceIsCore)
     }
 
     pub fn hir_get_module(self, module: LocalModDefId) -> (&'tcx Mod<'tcx>, Span, HirId) {
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 44165b06f1c..275458fc85f 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -17,7 +17,6 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::DataTypeKind;
-use rustc_span::sym;
 use rustc_type_ir::solve::AdtDestructorKind;
 use tracing::{debug, info, trace};
 
@@ -296,7 +295,7 @@ impl AdtDefData {
             flags |= AdtFlags::HAS_CTOR;
         }
 
-        if tcx.has_attr(did, sym::fundamental) {
+        if find_attr!(tcx.get_all_attrs(did), AttributeKind::Fundamental) {
             flags |= AdtFlags::IS_FUNDAMENTAL;
         }
         if tcx.is_lang_item(did, LangItem::PhantomData) {
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 78b2e265b48..344a81f5e24 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -1,9 +1,10 @@
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Namespace};
 use rustc_hir::def_id::DefId;
 use rustc_macros::{Decodable, Encodable, HashStable};
-use rustc_span::{Ident, Symbol, sym};
+use rustc_span::{Ident, Symbol};
 
 use super::{TyCtxt, Visibility};
 use crate::ty;
@@ -160,7 +161,7 @@ impl AssocItem {
             // Inherent impl but this attr is only applied to trait assoc items.
             (AssocItemContainer::Impl, None) => return true,
         };
-        tcx.has_attr(def_id, sym::type_const)
+        find_attr!(tcx.get_all_attrs(def_id), AttributeKind::TypeConst(_))
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index b780b1c5776..0177a95498b 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1782,21 +1782,18 @@ impl<'tcx> TyCtxt<'tcx> {
         did: impl Into<DefId>,
         attr: Symbol,
     ) -> impl Iterator<Item = &'tcx hir::Attribute> {
-        self.get_all_attrs(did).filter(move |a: &&hir::Attribute| a.has_name(attr))
+        self.get_all_attrs(did).iter().filter(move |a: &&hir::Attribute| a.has_name(attr))
     }
 
     /// Gets all attributes.
     ///
     /// To see if an item has a specific attribute, you should use [`rustc_attr_data_structures::find_attr!`] so you can use matching.
-    pub fn get_all_attrs(
-        self,
-        did: impl Into<DefId>,
-    ) -> impl Iterator<Item = &'tcx hir::Attribute> {
+    pub fn get_all_attrs(self, did: impl Into<DefId>) -> &'tcx [hir::Attribute] {
         let did: DefId = did.into();
         if let Some(did) = did.as_local() {
-            self.hir_attrs(self.local_def_id_to_hir_id(did)).iter()
+            self.hir_attrs(self.local_def_id_to_hir_id(did))
         } else {
-            self.attrs_for_def(did).iter()
+            self.attrs_for_def(did)
         }
     }
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 11424ec3724..bb5c1e0e653 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -283,6 +283,18 @@ pub fn check_builtin_meta_item(
                 | sym::rustc_confusables
                 | sym::rustc_skip_during_method_dispatch
                 | sym::rustc_pass_by_value
+                | sym::rustc_deny_explicit_impl
+                | sym::rustc_do_not_implement_via_object
+                | sym::rustc_coinductive
+                | sym::const_trait
+                | sym::rustc_specialization_trait
+                | sym::rustc_unsafe_specialization_marker
+                | sym::rustc_allow_incoherent_impl
+                | sym::rustc_coherence_is_core
+                | sym::marker
+                | sym::fundamental
+                | sym::rustc_paren_sugar
+                | sym::type_const
                 | sym::repr
                 | sym::align
                 | sym::deprecated
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 0aa6a2b41cf..2c95fead9e8 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -120,12 +120,35 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         for attr in attrs {
             let mut style = None;
             match attr {
-                Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch {
-                    span: attr_span,
-                    ..
-                }) => {
+                Attribute::Parsed(
+                    AttributeKind::SkipDuringMethodDispatch { span: attr_span, .. }
+                    | AttributeKind::Coinductive(attr_span)
+                    | AttributeKind::ConstTrait(attr_span)
+                    | AttributeKind::DenyExplicitImpl(attr_span)
+                    | AttributeKind::DoNotImplementViaObject(attr_span),
+                ) => {
                     self.check_must_be_applied_to_trait(*attr_span, span, target);
                 }
+                &Attribute::Parsed(
+                    AttributeKind::SpecializationTrait(attr_span)
+                    | AttributeKind::UnsafeSpecializationMarker(attr_span)
+                    | AttributeKind::ParenSugar(attr_span),
+                ) => {
+                    // FIXME: more validation is needed
+                    self.check_must_be_applied_to_trait(attr_span, span, target);
+                }
+                &Attribute::Parsed(AttributeKind::TypeConst(attr_span)) => {
+                    self.check_type_const(hir_id, attr_span, target)
+                }
+                &Attribute::Parsed(AttributeKind::Marker(attr_span)) => {
+                    self.check_marker(hir_id, attr_span, span, target)
+                }
+                Attribute::Parsed(AttributeKind::Fundamental | AttributeKind::CoherenceIsCore) => {
+                    // FIXME: add validation
+                }
+                &Attribute::Parsed(AttributeKind::AllowIncoherentImpl(attr_span)) => {
+                    self.check_allow_incoherent_impl(attr_span, span, target)
+                }
                 Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => {
                     self.check_confusables(*first_span, target);
                 }
@@ -259,7 +282,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::no_sanitize, ..] => {
                             self.check_no_sanitize(attr, span, target)
                         }
-                        [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
                         [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
                         [sym::doc, ..] => self.check_doc_attrs(
                             attr,
@@ -297,16 +319,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         | [sym::rustc_dirty, ..]
                         | [sym::rustc_if_this_changed, ..]
                         | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
-                        [sym::rustc_coinductive, ..]
-                        | [sym::rustc_must_implement_one_of, ..]
-                        | [sym::rustc_deny_explicit_impl, ..]
-                        | [sym::rustc_do_not_implement_via_object, ..]
-                        | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
+                        [sym::rustc_must_implement_one_of, ..] => self.check_must_be_applied_to_trait(attr.span(), span, target),
                         [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
                         [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
-                        [sym::rustc_allow_incoherent_impl, ..] => {
-                            self.check_allow_incoherent_impl(attr, span, target)
-                        }
                         [sym::rustc_has_incoherent_inherent_impls, ..] => {
                             self.check_has_incoherent_inherent_impls(attr, span, target)
                         }
@@ -339,9 +354,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::coroutine, ..] => {
                             self.check_coroutine(attr, target);
                         }
-                        [sym::type_const, ..] => {
-                            self.check_type_const(hir_id,attr, target);
-                        }
                         [sym::linkage, ..] => self.check_linkage(attr, span, target),
                         [
                             // ok
@@ -366,7 +378,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             | sym::prelude_import
                             | sym::panic_handler
                             | sym::allow_internal_unsafe
-                            | sym::fundamental
                             | sym::lang
                             | sym::needs_allocator
                             | sym::default_lib_allocator
@@ -830,7 +841,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if the `#[marker]` attribute on an `item` is valid.
-    fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+    fn check_marker(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
         match target {
             Target::Trait => {}
             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -838,13 +849,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "marker");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "marker");
             }
             _ => {
-                self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
-                    attr_span: attr.span(),
-                    defn_span: span,
-                });
+                self.dcx()
+                    .emit_err(errors::AttrShouldBeAppliedToTrait { attr_span, defn_span: span });
             }
         }
     }
@@ -1489,11 +1498,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) {
+    fn check_allow_incoherent_impl(&self, attr_span: Span, span: Span, target: Target) {
         match target {
             Target::Method(MethodKind::Inherent) => {}
             _ => {
-                self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span(), span });
+                self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span, span });
             }
         }
     }
@@ -2514,7 +2523,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_type_const(&self, hir_id: HirId, attr: &Attribute, target: Target) {
+    fn check_type_const(&self, hir_id: HirId, attr_span: Span, target: Target) {
         let tcx = self.tcx;
         if target == Target::AssocConst
             && let parent = tcx.parent(hir_id.expect_owner().to_def_id())
@@ -2524,7 +2533,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         } else {
             self.dcx()
                 .struct_span_err(
-                    attr.span(),
+                    attr_span,
                     "`#[type_const]` must only be applied to trait associated constants",
                 )
                 .emit();
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index 5bcb0c4dc0a..be529df3a49 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -116,24 +116,6 @@ error: malformed `cfi_encoding` attribute input
 LL | #[cfi_encoding]
    | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]`
 
-error: malformed `type_const` attribute input
-  --> $DIR/malformed-attrs.rs:143:5
-   |
-LL |     #[type_const = 1]
-   |     ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[type_const]`
-
-error: malformed `marker` attribute input
-  --> $DIR/malformed-attrs.rs:155:1
-   |
-LL | #[marker = 3]
-   | ^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
-
-error: malformed `fundamental` attribute input
-  --> $DIR/malformed-attrs.rs:157:1
-   |
-LL | #[fundamental()]
-   | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[fundamental]`
-
 error: malformed `link_ordinal` attribute input
   --> $DIR/malformed-attrs.rs:167:5
    |
@@ -528,6 +510,24 @@ LL | #[rustc_layout_scalar_valid_range_end]
    | expected this to be a list
    | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]`
 
+error[E0565]: malformed `marker` attribute input
+  --> $DIR/malformed-attrs.rs:155:1
+   |
+LL | #[marker = 3]
+   | ^^^^^^^^^---^
+   | |        |
+   | |        didn't expect any arguments here
+   | help: must be of the form: `#[marker]`
+
+error[E0565]: malformed `fundamental` attribute input
+  --> $DIR/malformed-attrs.rs:157:1
+   |
+LL | #[fundamental()]
+   | ^^^^^^^^^^^^^--^
+   | |            |
+   | |            didn't expect any arguments here
+   | help: must be of the form: `#[fundamental]`
+
 error[E0565]: malformed `ffi_pure` attribute input
   --> $DIR/malformed-attrs.rs:165:5
    |
@@ -555,6 +555,15 @@ LL | #[non_exhaustive = 1]
    | |                didn't expect any arguments here
    | help: must be of the form: `#[non_exhaustive]`
 
+error[E0565]: malformed `type_const` attribute input
+  --> $DIR/malformed-attrs.rs:143:5
+   |
+LL |     #[type_const = 1]
+   |     ^^^^^^^^^^^^^---^
+   |     |            |
+   |     |            didn't expect any arguments here
+   |     help: must be of the form: `#[type_const]`
+
 error: attribute should be applied to `const fn`
   --> $DIR/malformed-attrs.rs:34:1
    |
diff --git a/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr b/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr
index 579aff849d6..125c778ef1c 100644
--- a/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr
+++ b/tests/ui/const-generics/mgca/bad-type_const-syntax.stderr
@@ -1,9 +1,3 @@
-error: malformed `type_const` attribute input
-  --> $DIR/bad-type_const-syntax.rs:2:5
-   |
-LL |     #[type_const()]
-   |     ^^^^^^^^^^^^^^^ help: must be of the form: `#[type_const]`
-
 error[E0658]: the `#[type_const]` attribute is an experimental feature
   --> $DIR/bad-type_const-syntax.rs:2:5
    |
@@ -24,6 +18,15 @@ LL |     #[type_const]
    = help: add `#![feature(min_generic_const_args)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0565]: malformed `type_const` attribute input
+  --> $DIR/bad-type_const-syntax.rs:2:5
+   |
+LL |     #[type_const()]
+   |     ^^^^^^^^^^^^--^
+   |     |           |
+   |     |           didn't expect any arguments here
+   |     help: must be of the form: `#[type_const]`
+
 error: `#[type_const]` must only be applied to trait associated constants
   --> $DIR/bad-type_const-syntax.rs:11:5
    |
@@ -32,4 +35,5 @@ LL |     #[type_const]
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0565, E0658.
+For more information about an error, try `rustc --explain E0565`.
diff --git a/tests/ui/marker_trait_attr/marker-attribute-with-values.stderr b/tests/ui/marker_trait_attr/marker-attribute-with-values.stderr
index 6f9c9508e7e..9a2e5add37b 100644
--- a/tests/ui/marker_trait_attr/marker-attribute-with-values.stderr
+++ b/tests/ui/marker_trait_attr/marker-attribute-with-values.stderr
@@ -1,20 +1,30 @@
-error: malformed `marker` attribute input
+error[E0565]: malformed `marker` attribute input
   --> $DIR/marker-attribute-with-values.rs:3:1
    |
 LL | #[marker(always)]
-   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
+   | ^^^^^^^^--------^
+   | |       |
+   | |       didn't expect any arguments here
+   | help: must be of the form: `#[marker]`
 
-error: malformed `marker` attribute input
+error[E0565]: malformed `marker` attribute input
   --> $DIR/marker-attribute-with-values.rs:6:1
    |
 LL | #[marker("never")]
-   | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
+   | ^^^^^^^^---------^
+   | |       |
+   | |       didn't expect any arguments here
+   | help: must be of the form: `#[marker]`
 
-error: malformed `marker` attribute input
+error[E0565]: malformed `marker` attribute input
   --> $DIR/marker-attribute-with-values.rs:9:1
    |
 LL | #[marker(key = "value")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[marker]`
+   | ^^^^^^^^---------------^
+   | |       |
+   | |       didn't expect any arguments here
+   | help: must be of the form: `#[marker]`
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0565`.