Skip to content

Commit aa8ecd0

Browse files
committed
Suggest quoting unquoted idents in attrs
1 parent 6029085 commit aa8ecd0

8 files changed

+107
-6
lines changed

compiler/rustc_parse/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,9 @@ parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
407407
408408
parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
409409
410+
parse_invalid_meta_item_unquoted_ident = expected unsuffixed literal, found `{$token}`
411+
.suggestion = surround the identifier with quotation marks to parse it as a string
412+
410413
parse_invalid_offset_of = offset_of expects dot-separated field and variant names
411414
412415
parse_invalid_unicode_escape = invalid unicode character escape

compiler/rustc_parse/src/errors.rs

+19
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,25 @@ pub(crate) struct InvalidMetaItem {
973973
pub token: Token,
974974
}
975975

976+
#[derive(Diagnostic)]
977+
#[diag(parse_invalid_meta_item_unquoted_ident)]
978+
pub(crate) struct InvalidMetaItemUnquotedIdent {
979+
#[primary_span]
980+
pub span: Span,
981+
pub token: Token,
982+
#[subdiagnostic]
983+
pub sugg: InvalidMetaItemSuggQuoteIdent,
984+
}
985+
986+
#[derive(Subdiagnostic)]
987+
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
988+
pub(crate) struct InvalidMetaItemSuggQuoteIdent {
989+
#[suggestion_part(code = "\"")]
990+
pub before: Span,
991+
#[suggestion_part(code = "\"")]
992+
pub after: Span,
993+
}
994+
976995
#[derive(Subdiagnostic)]
977996
#[suggestion(
978997
parse_sugg_escape_identifier,

compiler/rustc_parse/src/parser/attr.rs

+24-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use crate::errors::{InvalidMetaItem, SuffixedLiteralInAttribute};
1+
use crate::errors::{
2+
InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
3+
SuffixedLiteralInAttribute,
4+
};
25
use crate::fluent_generated as fluent;
36

47
use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
@@ -417,9 +420,26 @@ impl<'a> Parser<'a> {
417420
Err(err) => err.cancel(),
418421
}
419422

420-
Err(self
421-
.dcx()
422-
.create_err(InvalidMetaItem { span: self.token.span, token: self.token.clone() }))
423+
let token = self.token.clone();
424+
425+
// Check for unquoted idents in meta items, e.g.: #[cfg(key = foo)]
426+
// `from_expansion()` ensures we don't suggest for cases such as
427+
// `#[cfg(feature = $expr)]` in macros
428+
if self.prev_token == token::Eq && !self.token.span.from_expansion() {
429+
let before = self.token.span.shrink_to_lo();
430+
while matches!(self.token.kind, token::Ident(..)) {
431+
self.bump();
432+
}
433+
let after = self.prev_token.span.shrink_to_hi();
434+
let sugg = InvalidMetaItemSuggQuoteIdent { before, after };
435+
return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent {
436+
span: token.span,
437+
token,
438+
sugg,
439+
}));
440+
}
441+
442+
Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token }))
423443
}
424444
}
425445

tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ fn main() {
77
}
88

99
#[deprecated(note = test)]
10-
//~^ ERROR expected unsuffixed literal or identifier, found `test`
10+
//~^ ERROR expected unsuffixed literal, found `test`
1111
fn foo() {}
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1-
error: expected unsuffixed literal or identifier, found `test`
1+
error: expected unsuffixed literal, found `test`
22
--> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21
33
|
44
LL | #[deprecated(note = test)]
55
| ^^^^
6+
|
7+
help: surround the identifier with quotation marks to parse it as a string
8+
|
9+
LL | #[deprecated(note = "test")]
10+
| + +
611

712
error: aborting due to 1 previous error
813

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// compile-flags: -Zdeduplicate-diagnostics=yes
2+
// run-rustfix
3+
4+
fn main() {
5+
#[cfg(key="foo")]
6+
//~^ ERROR expected unsuffixed literal, found `foo`
7+
//~| HELP surround the identifier with quotation marks to parse it as a string
8+
println!();
9+
#[cfg(key="bar")]
10+
println!();
11+
#[cfg(key="foo bar baz")]
12+
//~^ ERROR expected unsuffixed literal, found `foo`
13+
//~| HELP surround the identifier with quotation marks to parse it as a string
14+
println!();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// compile-flags: -Zdeduplicate-diagnostics=yes
2+
// run-rustfix
3+
4+
fn main() {
5+
#[cfg(key=foo)]
6+
//~^ ERROR expected unsuffixed literal, found `foo`
7+
//~| HELP surround the identifier with quotation marks to parse it as a string
8+
println!();
9+
#[cfg(key="bar")]
10+
println!();
11+
#[cfg(key=foo bar baz)]
12+
//~^ ERROR expected unsuffixed literal, found `foo`
13+
//~| HELP surround the identifier with quotation marks to parse it as a string
14+
println!();
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: expected unsuffixed literal, found `foo`
2+
--> $DIR/attr-unquoted-ident.rs:5:15
3+
|
4+
LL | #[cfg(key=foo)]
5+
| ^^^
6+
|
7+
help: surround the identifier with quotation marks to parse it as a string
8+
|
9+
LL | #[cfg(key="foo")]
10+
| + +
11+
12+
error: expected unsuffixed literal, found `foo`
13+
--> $DIR/attr-unquoted-ident.rs:11:15
14+
|
15+
LL | #[cfg(key=foo bar baz)]
16+
| ^^^
17+
|
18+
help: surround the identifier with quotation marks to parse it as a string
19+
|
20+
LL | #[cfg(key="foo bar baz")]
21+
| + +
22+
23+
error: aborting due to 2 previous errors
24+

0 commit comments

Comments
 (0)