about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-01-14 04:37:45 +0000
committerbors <bors@rust-lang.org>2024-01-14 04:37:45 +0000
commitaa5f781bd42340fe4f2eb4d68d2984454f600b78 (patch)
tree6166eaf013996c8d153a24edb0e347de16e7d26a
parent3deb9bbf84f6431ebcbb7cbdbe3d89bc2636bc1b (diff)
parentaa8ecd0652afbecd6549d2f6e53c0a5f6aa76d8f (diff)
downloadrust-aa5f781bd42340fe4f2eb4d68d2984454f600b78.tar.gz
rust-aa5f781bd42340fe4f2eb4d68d2984454f600b78.zip
Auto merge of #119341 - sjwang05:issue-58462, r=WaffleLapkin
Suggest quoting unquoted idents in attrs

Closes #58462
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs19
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs28
-rw-r--r--tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs2
-rw-r--r--tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr7
-rw-r--r--tests/ui/parser/attribute/attr-unquoted-ident.fixed15
-rw-r--r--tests/ui/parser/attribute/attr-unquoted-ident.rs15
-rw-r--r--tests/ui/parser/attribute/attr-unquoted-ident.stderr24
8 files changed, 107 insertions, 6 deletions
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index c11a6fab7e5..d515e86a182 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -407,6 +407,9 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
 
 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_offset_of = offset_of expects dot-separated field and variant names
 
 parse_invalid_unicode_escape = invalid unicode character escape
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 0de252707bd..34b34a1bad6 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -973,6 +973,25 @@ pub(crate) struct InvalidMetaItem {
     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,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
+pub(crate) struct InvalidMetaItemSuggQuoteIdent {
+    #[suggestion_part(code = "\"")]
+    pub before: Span,
+    #[suggestion_part(code = "\"")]
+    pub after: Span,
+}
+
 #[derive(Subdiagnostic)]
 #[suggestion(
     parse_sugg_escape_identifier,
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 02dab95233a..a92609c2c2f 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,4 +1,7 @@
-use crate::errors::{InvalidMetaItem, SuffixedLiteralInAttribute};
+use crate::errors::{
+    InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
+    SuffixedLiteralInAttribute,
+};
 use crate::fluent_generated as fluent;
 
 use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
@@ -417,9 +420,26 @@ impl<'a> Parser<'a> {
             Err(err) => err.cancel(),
         }
 
-        Err(self
-            .dcx()
-            .create_err(InvalidMetaItem { span: self.token.span, token: self.token.clone() }))
+        let token = self.token.clone();
+
+        // 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() {
+            let before = self.token.span.shrink_to_lo();
+            while matches!(self.token.kind, token::Ident(..)) {
+                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(self.dcx().create_err(InvalidMetaItem { span: token.span, token }))
     }
 }
 
diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
index c0cde75d4ca..6653bd15ddd 100644
--- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
+++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
@@ -7,5 +7,5 @@ fn main() {
 }
 
 #[deprecated(note = test)]
-//~^ ERROR expected unsuffixed literal or identifier, found `test`
+//~^ ERROR expected unsuffixed literal, found `test`
 fn foo() {}
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 48c763c50e3..078c766deed 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
@@ -1,8 +1,13 @@
-error: expected unsuffixed literal or identifier, found `test`
+error: expected unsuffixed literal, found `test`
   --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21
    |
 LL | #[deprecated(note = test)]
    |                     ^^^^
+   |
+help: surround the identifier with quotation marks to parse it as a string
+   |
+LL | #[deprecated(note = "test")]
+   |                     +    +
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.fixed b/tests/ui/parser/attribute/attr-unquoted-ident.fixed
new file mode 100644
index 00000000000..6cdf22f7ec0
--- /dev/null
+++ b/tests/ui/parser/attribute/attr-unquoted-ident.fixed
@@ -0,0 +1,15 @@
+// compile-flags: -Zdeduplicate-diagnostics=yes
+// run-rustfix
+
+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
new file mode 100644
index 00000000000..75af015c9fe
--- /dev/null
+++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs
@@ -0,0 +1,15 @@
+// compile-flags: -Zdeduplicate-diagnostics=yes
+// run-rustfix
+
+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.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr
new file mode 100644
index 00000000000..bc028f39be6
--- /dev/null
+++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr
@@ -0,0 +1,24 @@
+error: expected unsuffixed literal, found `foo`
+  --> $DIR/attr-unquoted-ident.rs:5:15
+   |
+LL |     #[cfg(key=foo)]
+   |               ^^^
+   |
+help: surround the identifier with quotation marks to parse it as a string
+   |
+LL |     #[cfg(key="foo")]
+   |               +   +
+
+error: expected unsuffixed literal, found `foo`
+  --> $DIR/attr-unquoted-ident.rs:11:15
+   |
+LL |     #[cfg(key=foo bar baz)]
+   |               ^^^
+   |
+help: surround the identifier with quotation marks to parse it as a string
+   |
+LL |     #[cfg(key="foo bar baz")]
+   |               +           +
+
+error: aborting due to 2 previous errors
+