about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing/src/attributes
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing/src/attributes')
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs63
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs25
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs70
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/transparency.rs3
8 files changed, 113 insertions, 63 deletions
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 81192f902a2..21b01a8d071 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
@@ -13,6 +14,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
     const PATH: &[Symbol] = &[sym::allow_internal_unstable];
     type Item = (Symbol, Span);
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -29,6 +31,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
     const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
     type Item = Symbol;
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index afd3c012f05..0be9d690c32 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::template;
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
@@ -13,37 +14,41 @@ pub(crate) struct ConfusablesParser {
 }
 
 impl<S: Stage> AttributeParser<S> for ConfusablesParser {
-    const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
-        let Some(list) = args.list() else {
-            // FIXME(jdonszelmann): error when not a list? Bring validation code here.
-            //       NOTE: currently subsequent attributes are silently ignored using
-            //       tcx.get_attr().
-            return;
-        };
-
-        if list.is_empty() {
-            cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
-        }
-
-        for param in list.mixed() {
-            let span = param.span();
-
-            let Some(lit) = param.lit() else {
-                cx.emit_err(session_diagnostics::IncorrectMetaItem {
-                    span,
-                    suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion {
-                        lo: span.shrink_to_lo(),
-                        hi: span.shrink_to_hi(),
-                    }),
-                });
-                continue;
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::rustc_confusables],
+        template!(List: r#""name1", "name2", ..."#),
+        |this, cx, args| {
+            let Some(list) = args.list() else {
+                // FIXME(jdonszelmann): error when not a list? Bring validation code here.
+                //       NOTE: currently subsequent attributes are silently ignored using
+                //       tcx.get_attr().
+                return;
             };
 
-            this.confusables.push(lit.symbol);
-        }
-
-        this.first_span.get_or_insert(cx.attr_span);
-    })];
+            if list.is_empty() {
+                cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
+            }
+
+            for param in list.mixed() {
+                let span = param.span();
+
+                let Some(lit) = param.lit() else {
+                    cx.emit_err(session_diagnostics::IncorrectMetaItem {
+                        span,
+                        suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion {
+                            lo: span.shrink_to_lo(),
+                            hi: span.shrink_to_hi(),
+                        }),
+                    });
+                    continue;
+                };
+
+                this.confusables.push(lit.symbol);
+            }
+
+            this.first_span.get_or_insert(cx.attr_span);
+        },
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.confusables.is_empty() {
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 1faee41c2a9..692f587ba03 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Span, Symbol, sym};
 
 use super::util::parse_version;
@@ -45,6 +46,11 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
     const PATH: &[Symbol] = &[sym::deprecated];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(
+        Word,
+        List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
+        NameValueStr: "reason"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let features = cx.features();
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index fecddde930a..da56656e3ed 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -11,7 +11,6 @@ use super::{AcceptContext, AttributeOrder, OnDuplicate};
 use crate::attributes::SingleAttributeParser;
 use crate::context::Stage;
 use crate::parser::ArgParser;
-use crate::session_diagnostics::IncorrectMetaItem;
 
 pub(crate) struct InlineParser;
 
@@ -30,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
                     return None;
                 };
 
-                match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) {
+                match l.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
                     Some(sym::always) => {
                         Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
                     }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index 0b9e9adcfbc..fa2a6087506 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -18,6 +18,7 @@ use std::marker::PhantomData;
 
 use rustc_attr_data_structures::AttributeKind;
 use rustc_attr_data_structures::lints::AttributeLintKind;
+use rustc_feature::AttributeTemplate;
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
 
@@ -37,7 +38,7 @@ pub(crate) mod transparency;
 pub(crate) mod util;
 
 type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
-type AcceptMapping<T, S> = &'static [(&'static [Symbol], AcceptFn<T, S>)];
+type AcceptMapping<T, S> = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn<T, S>)];
 
 /// An [`AttributeParser`] is a type which searches for syntactic attributes.
 ///
@@ -89,6 +90,9 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
     const ATTRIBUTE_ORDER: AttributeOrder;
     const ON_DUPLICATE: OnDuplicate<S>;
 
+    /// The template this attribute parser should implement. Used for diagnostics.
+    const TEMPLATE: AttributeTemplate;
+
     /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
 }
@@ -105,8 +109,10 @@ impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> {
 }
 
 impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[(T::PATH, |group: &mut Single<T, S>, cx, args| {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        T::PATH,
+        <T as SingleAttributeParser<S>>::TEMPLATE,
+        |group: &mut Single<T, S>, cx, args| {
             if let Some(pa) = T::convert(cx, args) {
                 match T::ATTRIBUTE_ORDER {
                     // keep the first and report immediately. ignore this attribute
@@ -127,7 +133,8 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
 
                 group.1 = Some((pa, cx.attr_span));
             }
-        })];
+        },
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         Some(self.1?.0)
@@ -224,6 +231,9 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
     type Item;
     const CONVERT: ConvertFn<Self::Item>;
 
+    /// The template this attribute parser should implement. Used for diagnostics.
+    const TEMPLATE: AttributeTemplate;
+
     /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -243,8 +253,11 @@ impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
 }
 
 impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))];
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        T::PATH,
+        <T as CombineAttributeParser<S>>::TEMPLATE,
+        |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 753b2366b41..6fb618541e3 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -1,6 +1,7 @@
 use rustc_abi::Align;
 use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
 use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
@@ -23,6 +24,8 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
     type Item = (ReprAttr, Span);
     const PATH: &[Symbol] = &[sym::repr];
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
+    // FIXME(jdonszelmann): never used
+    const TEMPLATE: AttributeTemplate = template!(List: "C");
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 6589a51db2b..fba725ae164 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -5,6 +5,7 @@ use rustc_attr_data_structures::{
     StableSince, UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_errors::ErrorGuaranteed;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Span, Symbol, sym};
 
 use super::util::parse_version;
@@ -43,26 +44,39 @@ impl StabilityParser {
 
 impl<S: Stage> AttributeParser<S> for StabilityParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[
-        (&[sym::stable], |this, cx, args| {
-            reject_outside_std!(cx);
-            if !this.check_duplicate(cx)
-                && let Some((feature, level)) = parse_stability(cx, args)
-            {
-                this.stability = Some((Stability { level, feature }, cx.attr_span));
-            }
-        }),
-        (&[sym::unstable], |this, cx, args| {
-            reject_outside_std!(cx);
-            if !this.check_duplicate(cx)
-                && let Some((feature, level)) = parse_unstability(cx, args)
-            {
-                this.stability = Some((Stability { level, feature }, cx.attr_span));
-            }
-        }),
-        (&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| {
-            reject_outside_std!(cx);
-            this.allowed_through_unstable_modules = args.name_value().and_then(|i| i.value_as_str())
-        }),
+        (
+            &[sym::stable],
+            template!(List: r#"feature = "name", since = "version""#),
+            |this, cx, args| {
+                reject_outside_std!(cx);
+                if !this.check_duplicate(cx)
+                    && let Some((feature, level)) = parse_stability(cx, args)
+                {
+                    this.stability = Some((Stability { level, feature }, cx.attr_span));
+                }
+            },
+        ),
+        (
+            &[sym::unstable],
+            template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+            |this, cx, args| {
+                reject_outside_std!(cx);
+                if !this.check_duplicate(cx)
+                    && let Some((feature, level)) = parse_unstability(cx, args)
+                {
+                    this.stability = Some((Stability { level, feature }, cx.attr_span));
+                }
+            },
+        ),
+        (
+            &[sym::rustc_allowed_through_unstable_modules],
+            template!(NameValueStr: "deprecation message"),
+            |this, cx, args| {
+                reject_outside_std!(cx);
+                this.allowed_through_unstable_modules =
+                    args.name_value().and_then(|i| i.value_as_str())
+            },
+        ),
     ];
 
     fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
@@ -96,8 +110,10 @@ pub(crate) struct BodyStabilityParser {
 }
 
 impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[(&[sym::rustc_default_body_unstable], |this, cx, args| {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::rustc_default_body_unstable],
+        template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+        |this, cx, args| {
             reject_outside_std!(cx);
             if this.stability.is_some() {
                 cx.dcx()
@@ -105,7 +121,8 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
             } else if let Some((feature, level)) = parse_unstability(cx, args) {
                 this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span));
             }
-        })];
+        },
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         let (stability, span) = self.stability?;
@@ -120,6 +137,7 @@ impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
     const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
+    const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
         Some(AttributeKind::ConstStabilityIndirect)
@@ -146,7 +164,7 @@ impl ConstStabilityParser {
 
 impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[
-        (&[sym::rustc_const_stable], |this, cx, args| {
+        (&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| {
             reject_outside_std!(cx);
 
             if !this.check_duplicate(cx)
@@ -158,7 +176,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
                 ));
             }
         }),
-        (&[sym::rustc_const_unstable], |this, cx, args| {
+        (&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| {
             reject_outside_std!(cx);
             if !this.check_duplicate(cx)
                 && let Some((feature, level)) = parse_unstability(cx, args)
@@ -169,7 +187,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
                 ));
             }
         }),
-        (&[sym::rustc_promotable], |this, cx, _| {
+        (&[sym::rustc_promotable], template!(Word), |this, cx, _| {
             reject_outside_std!(cx);
             this.promotable = true;
         }),
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index 16ad9d03e50..b0f5dac7fe2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::hygiene::Transparency;
 use rustc_span::{Symbol, sym};
 
@@ -17,6 +18,8 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
         cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
     });
+    const TEMPLATE: AttributeTemplate =
+        template!(NameValueStr: "transparent|semitransparent|opaque");
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         match args.name_value().and_then(|nv| nv.value_as_str()) {