about summary refs log tree commit diff
path: root/compiler/rustc_attr_parsing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_attr_parsing')
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs100
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs31
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs49
9 files changed, 116 insertions, 87 deletions
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 70de83f2f74..b9b386635f6 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -121,10 +121,6 @@ attr_parsing_unsupported_literal_cfg_boolean =
     literal in `cfg` predicate value must be a boolean
 attr_parsing_unsupported_literal_cfg_string =
     literal in `cfg` predicate value must be a string
-attr_parsing_unsupported_literal_deprecated_kv_pair =
-    item in `deprecated` must be a key/value pair
-attr_parsing_unsupported_literal_deprecated_string =
-    literal in `deprecated` value must be a string
 attr_parsing_unsupported_literal_generic =
     unsupported literal
 attr_parsing_unsupported_literal_suggestion =
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index f4505cbc0e1..c911908dfb3 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -30,12 +30,12 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
             for param in list.mixed() {
                 let span = param.span();
 
-                let Some(lit) = param.lit() else {
-                    cx.expected_string_literal(span);
+                let Some(lit) = param.lit().and_then(|i| i.value_str()) else {
+                    cx.expected_string_literal(span, param.lit());
                     continue;
                 };
 
-                this.confusables.push(lit.symbol);
+                this.confusables.push(lit);
             }
 
             this.first_span.get_or_insert(cx.attr_span);
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 0983a153efa..702ad66f578 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -7,7 +7,6 @@ use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
 use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
-use crate::session_diagnostics::UnsupportedLiteralReason;
 
 pub(crate) struct DeprecationParser;
 
@@ -26,13 +25,7 @@ fn get<S: Stage>(
         if let Some(value_str) = v.value_as_str() {
             Some(value_str)
         } else {
-            let lit = v.value_as_lit();
-            cx.emit_err(session_diagnostics::UnsupportedLiteral {
-                span: v.value_span,
-                reason: UnsupportedLiteralReason::DeprecatedString,
-                is_bytestr: lit.kind.is_bytestr(),
-                start_point_span: cx.sess().source_map().start_point(lit.span),
-            });
+            cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
             None
         }
     } else {
@@ -60,57 +53,60 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
 
         let is_rustc = features.staged_api();
 
-        if let Some(value) = args.name_value()
-            && let Some(value_str) = value.value_as_str()
-        {
-            note = Some(value_str)
-        } else if let Some(list) = args.list() {
-            for param in list.mixed() {
-                let param_span = param.span();
-                let Some(param) = param.meta_item() else {
-                    cx.emit_err(session_diagnostics::UnsupportedLiteral {
-                        span: param_span,
-                        reason: UnsupportedLiteralReason::DeprecatedKvPair,
-                        is_bytestr: false,
-                        start_point_span: cx.sess().source_map().start_point(param_span),
-                    });
-                    return None;
-                };
+        match args {
+            ArgParser::NoArgs => {
+                // ok
+            }
+            ArgParser::List(list) => {
+                for param in list.mixed() {
+                    let Some(param) = param.meta_item() else {
+                        cx.unexpected_literal(param.span());
+                        return None;
+                    };
 
-                let ident_name = param.path().word_sym();
+                    let ident_name = param.path().word_sym();
 
-                match ident_name {
-                    Some(name @ sym::since) => {
-                        since = Some(get(cx, name, param_span, param.args(), &since)?);
-                    }
-                    Some(name @ sym::note) => {
-                        note = Some(get(cx, name, param_span, param.args(), &note)?);
-                    }
-                    Some(name @ sym::suggestion) => {
-                        if !features.deprecated_suggestion() {
-                            cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
-                                span: param_span,
-                                is_nightly: cx.sess().is_nightly_build(),
-                                details: (),
-                            });
+                    match ident_name {
+                        Some(name @ sym::since) => {
+                            since = Some(get(cx, name, param.span(), param.args(), &since)?);
+                        }
+                        Some(name @ sym::note) => {
+                            note = Some(get(cx, name, param.span(), param.args(), &note)?);
                         }
+                        Some(name @ sym::suggestion) => {
+                            if !features.deprecated_suggestion() {
+                                cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
+                                    span: param.span(),
+                                    is_nightly: cx.sess().is_nightly_build(),
+                                    details: (),
+                                });
+                            }
 
-                        suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
-                    }
-                    _ => {
-                        cx.unknown_key(
-                            param_span,
-                            param.path().to_string(),
-                            if features.deprecated_suggestion() {
-                                &["since", "note", "suggestion"]
-                            } else {
-                                &["since", "note"]
-                            },
-                        );
-                        return None;
+                            suggestion =
+                                Some(get(cx, name, param.span(), param.args(), &suggestion)?);
+                        }
+                        _ => {
+                            cx.unknown_key(
+                                param.span(),
+                                param.path().to_string(),
+                                if features.deprecated_suggestion() {
+                                    &["since", "note", "suggestion"]
+                                } else {
+                                    &["since", "note"]
+                                },
+                            );
+                            return None;
+                        }
                     }
                 }
             }
+            ArgParser::NameValue(v) => {
+                let Some(value) = v.value_as_str() else {
+                    cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
+                    return None;
+                };
+                note = Some(value);
+            }
         }
 
         let since = if let Some(since) = since {
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index 75ae1d6a6c1..25efc3ae49b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -73,7 +73,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
                 };
 
                 let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
-                    cx.expected_string_literal(l.span());
+                    cx.expected_string_literal(l.span(), l.lit());
                     return None;
                 };
 
@@ -81,7 +81,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
             }
             ArgParser::NameValue(v) => {
                 let Some(reason) = v.value_as_str() else {
-                    cx.expected_string_literal(v.value_span);
+                    cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
                     return None;
                 };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
index 32a20d4c5b5..d4c846de56e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
@@ -9,10 +10,9 @@ pub(crate) struct AsPtrParser;
 
 impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
     const PATH: &[Symbol] = &[sym::rustc_as_ptr];
-
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
-
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
         // FIXME: check that there's no args (this is currently checked elsewhere)
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 6fb618541e3..ae9e7871874 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -34,6 +34,7 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
         let mut reprs = Vec::new();
 
         let Some(list) = args.list() else {
+            cx.expected_list(cx.attr_span);
             return reprs;
         };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 65de13972a0..6871ff4ec9f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -369,7 +369,9 @@ pub(crate) fn parse_unstability<S: Stage>(
             Some(sym::implied_by) => {
                 insert_value_into_option_or_error(cx, &param, &mut implied_by, word.unwrap())?
             }
-            Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &mut old_name)?,
+            Some(sym::old_name) => {
+                insert_value_into_option_or_error(cx, &param, &mut old_name, word.unwrap())?
+            }
             _ => {
                 cx.emit_err(session_diagnostics::UnknownMetaItem {
                     span: param.span(),
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index d6dfa2c7477..51c1760da30 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -5,8 +5,7 @@ use std::ops::{Deref, DerefMut};
 use std::sync::LazyLock;
 
 use private::Sealed;
-use rustc_ast as ast;
-use rustc_ast::NodeId;
+use rustc_ast::{self as ast, MetaItemLit, NodeId};
 use rustc_attr_data_structures::AttributeKind;
 use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
 use rustc_errors::{DiagCtxtHandle, Diagnostic};
@@ -200,13 +199,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         self.emit_err(UnknownMetaItem { span, item: found, expected: options })
     }
 
-    pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed {
+    /// error that a string literal was expected.
+    /// You can optionally give the literal you did find (which you found not to be a string literal)
+    /// which can make better errors. For example, if the literal was a byte string it will suggest
+    /// removing the `b` prefix.
+    pub(crate) fn expected_string_literal(
+        &self,
+        span: Span,
+        actual_literal: Option<&MetaItemLit>,
+    ) -> ErrorGuaranteed {
         self.emit_err(AttributeParseError {
             span,
             attr_span: self.attr_span,
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
-            reason: AttributeParseErrorReason::ExpectedStringLiteral,
+            reason: AttributeParseErrorReason::ExpectedStringLiteral {
+                byte_string: actual_literal.and_then(|i| {
+                    i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
+                }),
+            },
         })
     }
 
@@ -243,6 +254,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         })
     }
 
+    /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
+    /// was expected *not* to be a literal, but instead a meta item.
+    pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::UnexpectedLiteral,
+        })
+    }
+
     pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
         self.emit_err(AttributeParseError {
             span,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 3d865c1d14e..57ac92a0ca1 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -16,8 +16,6 @@ pub(crate) enum UnsupportedLiteralReason {
     Generic,
     CfgString,
     CfgBoolean,
-    DeprecatedString,
-    DeprecatedKvPair,
 }
 
 #[derive(Diagnostic)]
@@ -190,6 +188,7 @@ pub(crate) struct InvalidReprHintNoValue {
 }
 
 /// Error code: E0565
+// FIXME(jdonszelmann): slowly phased out
 pub(crate) struct UnsupportedLiteral {
     pub span: Span,
     pub reason: UnsupportedLiteralReason,
@@ -212,12 +211,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
                 UnsupportedLiteralReason::CfgBoolean => {
                     fluent::attr_parsing_unsupported_literal_cfg_boolean
                 }
-                UnsupportedLiteralReason::DeprecatedString => {
-                    fluent::attr_parsing_unsupported_literal_deprecated_string
-                }
-                UnsupportedLiteralReason::DeprecatedKvPair => {
-                    fluent::attr_parsing_unsupported_literal_deprecated_kv_pair
-                }
             },
         );
         diag.span(self.span);
@@ -473,9 +466,10 @@ pub(crate) struct UnrecognizedReprHint {
 }
 
 pub(crate) enum AttributeParseErrorReason {
-    ExpectedStringLiteral,
+    ExpectedStringLiteral { byte_string: Option<Span> },
     ExpectedSingleArgument,
     ExpectedList,
+    UnexpectedLiteral,
     ExpectedNameValue(Option<Symbol>),
     DuplicateKey(Symbol),
     ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
@@ -497,27 +491,44 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
         diag.span(self.attr_span);
         diag.code(E0539);
         match self.reason {
-            AttributeParseErrorReason::ExpectedStringLiteral => {
-                diag.span_note(self.span, "expected a string literal here");
+            AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => {
+                if let Some(start_point_span) = byte_string {
+                    diag.span_suggestion(
+                        start_point_span,
+                        fluent::attr_parsing_unsupported_literal_suggestion,
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.note("expected a normal string literal, not a byte string literal");
+
+                    return diag;
+                } else {
+                    diag.span_label(self.span, "expected a string literal here");
+                }
             }
             AttributeParseErrorReason::ExpectedSingleArgument => {
-                diag.span_note(self.span, "expected a single argument here");
+                diag.span_label(self.span, "expected a single argument here");
+                diag.code(E0805);
             }
             AttributeParseErrorReason::ExpectedList => {
-                diag.span_note(self.span, "expected this to be a list");
+                diag.span_label(self.span, "expected this to be a list");
             }
             AttributeParseErrorReason::DuplicateKey(key) => {
-                diag.span_note(self.span, format!("found `{key}` used as a key more than once"));
+                diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
                 diag.code(E0538);
             }
+            AttributeParseErrorReason::UnexpectedLiteral => {
+                diag.span_label(self.span, format!("didn't expect a literal here"));
+                diag.code(E0565);
+            }
             AttributeParseErrorReason::ExpectedNameValue(None) => {
-                diag.span_note(
+                diag.span_label(
                     self.span,
                     format!("expected this to be of the form `{name} = \"...\"`"),
                 );
             }
             AttributeParseErrorReason::ExpectedNameValue(Some(name)) => {
-                diag.span_note(
+                diag.span_label(
                     self.span,
                     format!("expected this to be of the form `{name} = \"...\"`"),
                 );
@@ -527,13 +538,13 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                 match possibilities.as_slice() {
                     &[] => {}
                     &[x] => {
-                        diag.span_note(
+                        diag.span_label(
                             self.span,
                             format!("the only valid argument here is {quote}{x}{quote}"),
                         );
                     }
                     [first, second] => {
-                        diag.span_note(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
+                        diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
                     }
                     [first @ .., second_to_last, last] => {
                         let mut res = String::new();
@@ -544,7 +555,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                             "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
                         ));
 
-                        diag.span_note(self.span, format!("valid arguments are {res}"));
+                        diag.span_label(self.span, format!("valid arguments are {res}"));
                     }
                 }
             }