about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLeón Orell Valerian Liehr <me@fmease.dev>2024-05-06 01:25:49 +0200
committerLeón Orell Valerian Liehr <me@fmease.dev>2024-05-10 09:16:27 +0200
commit0ad3c5da72469c848e321ddee207f9a5dfbf9876 (patch)
tree0466f1bf8bf98324cf1c0c6f627266239d92aca0
parent7c4ac0603e9ee5295bc802c90575391288a69a8a (diff)
downloadrust-0ad3c5da72469c848e321ddee207f9a5dfbf9876.tar.gz
rust-0ad3c5da72469c848e321ddee207f9a5dfbf9876.zip
Fix parse error message for meta items
-rw-r--r--compiler/rustc_parse/messages.ftl6
-rw-r--r--compiler/rustc_parse/src/errors.rs14
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs56
-rw-r--r--tests/ui/attributes/nonterminal-expansion.rs2
-rw-r--r--tests/ui/attributes/nonterminal-expansion.stderr2
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs4
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr4
-rw-r--r--tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr2
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-4.rs9
-rw-r--r--tests/ui/parser/attribute/attr-bad-meta-4.stderr20
-rw-r--r--tests/ui/parser/attribute/attr-unquoted-ident.fixed17
-rw-r--r--tests/ui/parser/attribute/attr-unquoted-ident.rs14
-rw-r--r--tests/ui/parser/attribute/attr-unquoted-ident.stderr21
13 files changed, 93 insertions, 78 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 873095dca87..04f855e4f55 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -401,10 +401,8 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
     .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
     .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
 
-parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
-
-parse_invalid_meta_item_unquoted_ident = expected unsuffixed literal, found `{$token}`
-    .suggestion = surround the identifier with quotation marks to parse it as a string
+parse_invalid_meta_item = expected unsuffixed literal, found `{$token}`
+    .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
 
 parse_invalid_offset_of = offset_of expects dot-separated field and variant names
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index d06f03a7c17..2f68a299f26 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -978,21 +978,13 @@ pub(crate) struct InvalidMetaItem {
     #[primary_span]
     pub span: Span,
     pub token: Token,
-}
-
-#[derive(Diagnostic)]
-#[diag(parse_invalid_meta_item_unquoted_ident)]
-pub(crate) struct InvalidMetaItemUnquotedIdent {
-    #[primary_span]
-    pub span: Span,
-    pub token: Token,
     #[subdiagnostic]
-    pub sugg: InvalidMetaItemSuggQuoteIdent,
+    pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
-pub(crate) struct InvalidMetaItemSuggQuoteIdent {
+#[multipart_suggestion(parse_quote_ident_sugg, applicability = "machine-applicable")]
+pub(crate) struct InvalidMetaItemQuoteIdentSugg {
     #[suggestion_part(code = "\"")]
     pub before: Span,
     #[suggestion_part(code = "\"")]
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index ab5f51eedc3..d5d8060d909 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,7 +1,4 @@
-use crate::errors::{
-    InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
-    SuffixedLiteralInAttribute,
-};
+use crate::errors;
 use crate::fluent_generated as fluent;
 use crate::maybe_whole;
 
@@ -318,7 +315,7 @@ impl<'a> Parser<'a> {
         debug!("checking if {:?} is unsuffixed", lit);
 
         if !lit.kind.is_unsuffixed() {
-            self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
+            self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span });
         }
 
         Ok(lit)
@@ -356,10 +353,11 @@ impl<'a> Parser<'a> {
         Ok(nmis)
     }
 
-    /// Matches the following grammar (per RFC 1559).
+    /// Parse a meta item per RFC 1559.
+    ///
     /// ```ebnf
-    /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
-    /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
+    /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
+    /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
     /// ```
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
         // We can't use `maybe_whole` here because it would bump in the `None`
@@ -387,7 +385,6 @@ impl<'a> Parser<'a> {
         Ok(if self.eat(&token::Eq) {
             ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?)
         } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
-            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
             let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
             ast::MetaItemKind::List(list)
         } else {
@@ -395,38 +392,45 @@ impl<'a> Parser<'a> {
         })
     }
 
-    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
+    /// Parse an inner meta item per RFC 1559.
+    ///
+    /// ```ebnf
+    /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
+    /// ```
     fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
         match self.parse_unsuffixed_meta_item_lit() {
             Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
-            Err(err) => err.cancel(),
+            Err(err) => err.cancel(), // we provide a better error below
         }
 
         match self.parse_meta_item() {
             Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
-            Err(err) => err.cancel(),
+            Err(err) => err.cancel(), // we provide a better error below
         }
 
-        let token = self.token.clone();
+        let mut err = errors::InvalidMetaItem {
+            span: self.token.span,
+            token: self.token.clone(),
+            quote_ident_sugg: None,
+        };
 
-        // Check for unquoted idents in meta items, e.g.: #[cfg(key = foo)]
-        // `from_expansion()` ensures we don't suggest for cases such as
-        // `#[cfg(feature = $expr)]` in macros
-        if self.prev_token == token::Eq && !self.token.span.from_expansion() {
+        // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
+        // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
+        // when macro metavariables are involved.
+        if self.prev_token == token::Eq
+            && let token::Ident(..) = self.token.kind
+        {
             let before = self.token.span.shrink_to_lo();
-            while matches!(self.token.kind, token::Ident(..)) {
+            while let token::Ident(..) = self.token.kind {
                 self.bump();
             }
-            let after = self.prev_token.span.shrink_to_hi();
-            let sugg = InvalidMetaItemSuggQuoteIdent { before, after };
-            return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent {
-                span: token.span,
-                token,
-                sugg,
-            }));
+            err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg {
+                before,
+                after: self.prev_token.span.shrink_to_hi(),
+            });
         }
 
-        Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token }))
+        Err(self.dcx().create_err(err))
     }
 }
 
diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs
index 6db7aea0745..1b2e92a3170 100644
--- a/tests/ui/attributes/nonterminal-expansion.rs
+++ b/tests/ui/attributes/nonterminal-expansion.rs
@@ -5,7 +5,7 @@
 macro_rules! pass_nonterminal {
     ($n:expr) => {
         #[repr(align($n))]
-        //~^ ERROR expected unsuffixed literal or identifier, found `n!()`
+        //~^ ERROR expected unsuffixed literal, found `n!()`
         struct S;
     };
 }
diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr
index 78541495b32..b640575d17d 100644
--- a/tests/ui/attributes/nonterminal-expansion.stderr
+++ b/tests/ui/attributes/nonterminal-expansion.stderr
@@ -1,4 +1,4 @@
-error: expected unsuffixed literal or identifier, found `n!()`
+error: expected unsuffixed literal, found `n!()`
   --> $DIR/nonterminal-expansion.rs:7:22
    |
 LL |         #[repr(align($n))]
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index 408eaffccf7..d8852812492 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
@@ -28,8 +28,8 @@ struct S9;
 macro_rules! generate_s10 {
     ($expr: expr) => {
         #[cfg(feature = $expr)]
-        //~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")`
-        //~| ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")`
+        //~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")`
+        //~| ERROR expected unsuffixed literal, found `concat!("nonexistent")`
         struct S10;
     }
 }
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 12557ff6360..3dd0823389c 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
@@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")]
    |           |
    |           help: consider removing the prefix
 
-error: expected unsuffixed literal or identifier, found `concat!("nonexistent")`
+error: expected unsuffixed literal, found `concat!("nonexistent")`
   --> $DIR/cfg-attr-syntax-validation.rs:30:25
    |
 LL |         #[cfg(feature = $expr)]
@@ -65,7 +65,7 @@ LL | generate_s10!(concat!("nonexistent"));
    |
    = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: expected unsuffixed literal or identifier, found `concat!("nonexistent")`
+error: expected unsuffixed literal, found `concat!("nonexistent")`
   --> $DIR/cfg-attr-syntax-validation.rs:30:25
    |
 LL |         #[cfg(feature = $expr)]
diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
index 078c766deed..a030da5068c 100644
--- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
+++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
@@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `test`
 LL | #[deprecated(note = test)]
    |                     ^^^^
    |
-help: surround the identifier with quotation marks to parse it as a string
+help: surround the identifier with quotation marks to make it into a string literal
    |
 LL | #[deprecated(note = "test")]
    |                     +    +
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs
index cedbd1d6686..2a69ae5ac06 100644
--- a/tests/ui/parser/attribute/attr-bad-meta-4.rs
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs
@@ -1,12 +1,17 @@
 macro_rules! mac {
     ($attr_item: meta) => {
         #[cfg($attr_item)]
-        //~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
-        //~| ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+        //~^ ERROR expected unsuffixed literal, found `an(arbitrary token stream)`
+        //~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)`
         struct S;
     }
 }
 
 mac!(an(arbitrary token stream));
 
+#[cfg(feature = -1)]
+//~^ ERROR expected unsuffixed literal, found `-`
+//~| ERROR expected unsuffixed literal, found `-`
+fn handler() {}
+
 fn main() {}
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
index a543bcb692e..192be28db3f 100644
--- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
@@ -1,4 +1,10 @@
-error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+error: expected unsuffixed literal, found `-`
+  --> $DIR/attr-bad-meta-4.rs:12:17
+   |
+LL | #[cfg(feature = -1)]
+   |                 ^
+
+error: expected unsuffixed literal, found `an(arbitrary token stream)`
   --> $DIR/attr-bad-meta-4.rs:3:15
    |
 LL |         #[cfg($attr_item)]
@@ -9,7 +15,7 @@ LL | mac!(an(arbitrary token stream));
    |
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+error: expected unsuffixed literal, found `an(arbitrary token stream)`
   --> $DIR/attr-bad-meta-4.rs:3:15
    |
 LL |         #[cfg($attr_item)]
@@ -21,5 +27,13 @@ LL | mac!(an(arbitrary token stream));
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error: expected unsuffixed literal, found `-`
+  --> $DIR/attr-bad-meta-4.rs:12:17
+   |
+LL | #[cfg(feature = -1)]
+   |                 ^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.fixed b/tests/ui/parser/attribute/attr-unquoted-ident.fixed
deleted file mode 100644
index bc861ef69fb..00000000000
--- a/tests/ui/parser/attribute/attr-unquoted-ident.fixed
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ compile-flags: -Zdeduplicate-diagnostics=yes
-//@ run-rustfix
-
-#![allow(unexpected_cfgs)]
-
-fn main() {
-    #[cfg(key="foo")]
-    //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
-    println!();
-    #[cfg(key="bar")]
-    println!();
-    #[cfg(key="foo bar baz")]
-    //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
-    println!();
-}
diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs
index 8bdb8605ebb..5b15b8d69fc 100644
--- a/tests/ui/parser/attribute/attr-unquoted-ident.rs
+++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs
@@ -1,17 +1,25 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
-//@ run-rustfix
 
 #![allow(unexpected_cfgs)]
 
 fn main() {
     #[cfg(key=foo)]
     //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
+    //~| HELP surround the identifier with quotation marks to make it into a string literal
     println!();
     #[cfg(key="bar")]
     println!();
     #[cfg(key=foo bar baz)]
     //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
+    //~| HELP surround the identifier with quotation marks to make it into a string literal
     println!();
 }
+
+// Don't suggest surrounding `$name` or `nickname` with quotes:
+
+macro_rules! make {
+    ($name:ident) => { #[doc(alias = $name)] pub struct S; }
+    //~^ ERROR expected unsuffixed literal, found `nickname`
+}
+
+make!(nickname); //~ NOTE in this expansion
diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr
index 99484a51110..e0f99459c44 100644
--- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr
+++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr
@@ -1,24 +1,35 @@
 error: expected unsuffixed literal, found `foo`
-  --> $DIR/attr-unquoted-ident.rs:7:15
+  --> $DIR/attr-unquoted-ident.rs:6:15
    |
 LL |     #[cfg(key=foo)]
    |               ^^^
    |
-help: surround the identifier with quotation marks to parse it as a string
+help: surround the identifier with quotation marks to make it into a string literal
    |
 LL |     #[cfg(key="foo")]
    |               +   +
 
 error: expected unsuffixed literal, found `foo`
-  --> $DIR/attr-unquoted-ident.rs:13:15
+  --> $DIR/attr-unquoted-ident.rs:12:15
    |
 LL |     #[cfg(key=foo bar baz)]
    |               ^^^
    |
-help: surround the identifier with quotation marks to parse it as a string
+help: surround the identifier with quotation marks to make it into a string literal
    |
 LL |     #[cfg(key="foo bar baz")]
    |               +           +
 
-error: aborting due to 2 previous errors
+error: expected unsuffixed literal, found `nickname`
+  --> $DIR/attr-unquoted-ident.rs:21:38
+   |
+LL |     ($name:ident) => { #[doc(alias = $name)] pub struct S; }
+   |                                      ^^^^^
+...
+LL | make!(nickname);
+   | --------------- in this macro invocation
+   |
+   = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors