Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix parse error message for meta items #124778

Merged
merged 1 commit into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
14 changes: 3 additions & 11 deletions compiler/rustc_parse/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "\"")]
Expand Down
56 changes: 30 additions & 26 deletions compiler/rustc_parse/src/parser/attr.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::errors::{
InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
SuffixedLiteralInAttribute,
};
use crate::errors;
use crate::fluent_generated as fluent;
use crate::maybe_whole;

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -387,46 +385,52 @@ 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 {
ast::MetaItemKind::Word
})
}

/// 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))
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/attributes/nonterminal-expansion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/attributes/nonterminal-expansion.stderr
Original file line number Diff line number Diff line change
@@ -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))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
| + +
Expand Down
9 changes: 7 additions & 2 deletions tests/ui/parser/attribute/attr-bad-meta-4.rs
Original file line number Diff line number Diff line change
@@ -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() {}
20 changes: 17 additions & 3 deletions tests/ui/parser/attribute/attr-bad-meta-4.stderr
Original file line number Diff line number Diff line change
@@ -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)]
Expand All @@ -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)]
Expand All @@ -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

17 changes: 0 additions & 17 deletions tests/ui/parser/attribute/attr-unquoted-ident.fixed

This file was deleted.

14 changes: 11 additions & 3 deletions tests/ui/parser/attribute/attr-unquoted-ident.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
//@ compile-flags: -Zdeduplicate-diagnostics=yes
//@ run-rustfix
Copy link
Member Author

@fmease fmease May 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've removed the rustfix directive since I've added a negative test case and didn't want to add revisions (do they work in combination with rustfix?) or a separate test file.


#![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
21 changes: 16 additions & 5 deletions tests/ui/parser/attribute/attr-unquoted-ident.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading