about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJana Dönszelmann <jana@donsz.nl>2025-09-10 11:01:34 -0700
committerJana Dönszelmann <jana@donsz.nl>2025-09-13 22:37:20 -0700
commitf56eb060479e6dcb386f7a67fa9f13ae3c31e6f7 (patch)
tree252691dcbd59eafe22d57ad9076634a01659d382
parent60a5372753460ef0db67c2307308a741b17771f3 (diff)
downloadrust-f56eb060479e6dcb386f7a67fa9f13ae3c31e6f7.tar.gz
rust-f56eb060479e6dcb386f7a67fa9f13ae3c31e6f7.zip
merge crate-level into ALLOWED_TARGETS
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/crate_level.rs40
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs18
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/prelude.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/interface.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/target_checking.rs15
7 files changed, 23 insertions, 62 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
index 0b2c05482bf..4611de44459 100644
--- a/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/crate_level.rs
@@ -43,11 +43,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(n) = args else {
@@ -76,11 +72,7 @@ impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -103,11 +95,7 @@ impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -130,11 +118,7 @@ impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -157,11 +141,7 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
-    const TYPE: AttributeType = AttributeType::CrateLevel;
-
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ArgParser::NameValue(nv) = args else {
@@ -182,11 +162,8 @@ pub(crate) struct NoCoreParser;
 impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
     const PATH: &[Symbol] = &[sym::no_core];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
-    const TYPE: AttributeType = AttributeType::CrateLevel;
 }
 
 pub(crate) struct NoStdParser;
@@ -194,9 +171,6 @@ pub(crate) struct NoStdParser;
 impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
     const PATH: &[Symbol] = &[sym::no_std];
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    // because it's a crate-level attribute, we already warn about it.
-    // Putting target limitations here would give duplicate warnings
-    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
-    const TYPE: AttributeType = AttributeType::CrateLevel;
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 043bc925eac..4ed13d239b9 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -12,15 +12,11 @@
 //! - [`CombineAttributeParser`](crate::attributes::CombineAttributeParser): makes it easy to implement an attribute which should combine the
 //! contents of attributes, if an attribute appear multiple times in a list
 //!
-//! By default, attributes are allowed anywhere. When adding an attribute that should only be used
-//! at the crate root, consider setting the `TYPE` in the parser trait to
-//! [`AttributeType::CrateLevel`](rustc_feature::AttributeType::CrateLevel).
-//!
 //! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
 
 use std::marker::PhantomData;
 
-use rustc_feature::{AttributeTemplate, AttributeType, template};
+use rustc_feature::{AttributeTemplate, template};
 use rustc_hir::attrs::AttributeKind;
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
@@ -89,11 +85,8 @@ pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
     ///
     /// If an attribute has this symbol, the `accept` function will be called on it.
     const ATTRIBUTES: AcceptMapping<Self, S>;
-
     const ALLOWED_TARGETS: AllowedTargets;
 
-    const TYPE: AttributeType = AttributeType::Normal;
-
     /// The parser has gotten a chance to accept the attributes on an item,
     /// here it can produce an attribute.
     ///
@@ -135,8 +128,6 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
     /// The template this attribute parser should implement. Used for diagnostics.
     const TEMPLATE: AttributeTemplate;
 
-    const TYPE: AttributeType = AttributeType::Normal;
-
     /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
 }
@@ -183,8 +174,6 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
     )];
     const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
 
-    const TYPE: AttributeType = T::TYPE;
-
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         Some(self.1?.0)
     }
@@ -269,7 +258,6 @@ pub(crate) trait NoArgsAttributeParser<S: Stage>: 'static {
     const PATH: &[Symbol];
     const ON_DUPLICATE: OnDuplicate<S>;
     const ALLOWED_TARGETS: AllowedTargets;
-    const TYPE: AttributeType = AttributeType::Normal;
 
     /// Create the [`AttributeKind`] given attribute's [`Span`].
     const CREATE: fn(Span) -> AttributeKind;
@@ -289,7 +277,6 @@ impl<T: NoArgsAttributeParser<S>, S: Stage> SingleAttributeParser<S> for Without
     const ON_DUPLICATE: OnDuplicate<S> = T::ON_DUPLICATE;
     const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
     const TEMPLATE: AttributeTemplate = template!(Word);
-    const TYPE: AttributeType = T::TYPE;
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         if let Err(span) = args.no_args() {
@@ -323,8 +310,6 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
     /// The template this attribute parser should implement. Used for diagnostics.
     const TEMPLATE: AttributeTemplate;
 
-    const TYPE: AttributeType = AttributeType::Normal;
-
     /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -360,7 +345,6 @@ impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S
             group.items.extend(T::extend(cx, args))
         })];
     const ALLOWED_TARGETS: AllowedTargets = T::ALLOWED_TARGETS;
-    const TYPE: AttributeType = T::TYPE;
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if let Some(first_span) = self.first_span {
diff --git a/compiler/rustc_attr_parsing/src/attributes/prelude.rs b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
index 8f040ffb9d4..980366b5c37 100644
--- a/compiler/rustc_attr_parsing/src/attributes/prelude.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/prelude.rs
@@ -1,6 +1,6 @@
 // data structures
 #[doc(hidden)]
-pub(super) use rustc_feature::{AttributeTemplate, AttributeType, template};
+pub(super) use rustc_feature::{AttributeTemplate, template};
 #[doc(hidden)]
 pub(super) use rustc_hir::attrs::AttributeKind;
 #[doc(hidden)]
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index fbd9a480fbb..c756bce96e2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -1,7 +1,5 @@
 use std::mem;
 
-use rustc_feature::AttributeType;
-
 use super::prelude::*;
 use crate::attributes::{
     AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
@@ -155,8 +153,7 @@ 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 ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
-    const TYPE: AttributeType = AttributeType::CrateLevel;
+    const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
     const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CoherenceIsCore;
 }
 
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index b3ab1d3edd6..d7998048be5 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -6,7 +6,7 @@ use std::sync::LazyLock;
 use private::Sealed;
 use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
 use rustc_errors::{Diag, Diagnostic, Level};
-use rustc_feature::{AttributeTemplate, AttributeType};
+use rustc_feature::AttributeTemplate;
 use rustc_hir::attrs::AttributeKind;
 use rustc_hir::lints::{AttributeLint, AttributeLintKind};
 use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
@@ -83,7 +83,6 @@ pub(super) struct GroupTypeInnerAccept<S: Stage> {
     pub(super) template: AttributeTemplate,
     pub(super) accept_fn: AcceptFn<S>,
     pub(super) allowed_targets: AllowedTargets,
-    pub(super) attribute_type: AttributeType,
 }
 
 type AcceptFn<S> =
@@ -133,7 +132,6 @@ macro_rules! attribute_parsers {
                                 })
                             }),
                             allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
-                            attribute_type: <$names as crate::attributes::AttributeParser<$stage>>::TYPE,
                         });
                     }
 
diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs
index 0fe3c209421..8f2de4af14e 100644
--- a/compiler/rustc_attr_parsing/src/interface.rs
+++ b/compiler/rustc_attr_parsing/src/interface.rs
@@ -272,7 +272,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
 
                             (accept.accept_fn)(&mut cx, args);
                             if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
-                                Self::check_type(accept.attribute_type, target, &mut cx);
                                 Self::check_target(&accept.allowed_targets, target, &mut cx);
                             }
                         }
diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs
index edc496b460c..c52253699b5 100644
--- a/compiler/rustc_attr_parsing/src/target_checking.rs
+++ b/compiler/rustc_attr_parsing/src/target_checking.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
 
 use rustc_ast::AttrStyle;
 use rustc_errors::DiagArgValue;
-use rustc_feature::{AttributeType, Features};
+use rustc_feature::Features;
 use rustc_hir::lints::AttributeLintKind;
 use rustc_hir::{MethodKind, Target};
 
@@ -14,6 +14,11 @@ use crate::session_diagnostics::InvalidTarget;
 pub(crate) enum AllowedTargets {
     AllowList(&'static [Policy]),
     AllowListWarnRest(&'static [Policy]),
+    /// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`.
+    /// For crate-level attributes we emit a specific set of lints to warn
+    /// people about accidentally not using them on the crate.
+    /// Only use this for attributes that are *exclusively* valid at the crate level.
+    CrateLevel,
 }
 
 pub(crate) enum AllowedResult {
@@ -43,6 +48,7 @@ impl AllowedTargets {
                     AllowedResult::Warn
                 }
             }
+            AllowedTargets::CrateLevel => AllowedResult::Allowed,
         }
     }
 
@@ -50,6 +56,7 @@ impl AllowedTargets {
         match self {
             AllowedTargets::AllowList(list) => list,
             AllowedTargets::AllowListWarnRest(list) => list,
+            AllowedTargets::CrateLevel => ALL_TARGETS,
         }
         .iter()
         .filter_map(|target| match target {
@@ -74,6 +81,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
         target: Target,
         cx: &mut AcceptContext<'_, 'sess, S>,
     ) {
+        Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx);
+
         match allowed_targets.is_allowed(target) {
             AllowedResult::Allowed => {}
             AllowedResult::Warn => {
@@ -109,7 +118,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
     }
 
     pub(crate) fn check_type(
-        attribute_type: AttributeType,
+        crate_level: bool,
         target: Target,
         cx: &mut AcceptContext<'_, 'sess, S>,
     ) {
@@ -119,7 +128,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
             return;
         }
 
-        if attribute_type != AttributeType::CrateLevel {
+        if !crate_level {
             return;
         }