Fix parse error message for meta items

This commit is contained in:
León Orell Valerian Liehr 2024-05-06 01:25:49 +02:00
parent 7c4ac0603e
commit 0ad3c5da72
No known key found for this signature in database
GPG Key ID: D17A07215F68E713
13 changed files with 93 additions and 78 deletions

View File

@ -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_amp_amp_for_conjunction = use `&&` to perform logical conjunction
.use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction .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 = expected unsuffixed literal, found `{$token}`
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
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_offset_of = offset_of expects dot-separated field and variant names

View File

@ -978,21 +978,13 @@ pub(crate) struct InvalidMetaItem {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub token: Token, 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] #[subdiagnostic]
pub sugg: InvalidMetaItemSuggQuoteIdent, pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
} }
#[derive(Subdiagnostic)] #[derive(Subdiagnostic)]
#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] #[multipart_suggestion(parse_quote_ident_sugg, applicability = "machine-applicable")]
pub(crate) struct InvalidMetaItemSuggQuoteIdent { pub(crate) struct InvalidMetaItemQuoteIdentSugg {
#[suggestion_part(code = "\"")] #[suggestion_part(code = "\"")]
pub before: Span, pub before: Span,
#[suggestion_part(code = "\"")] #[suggestion_part(code = "\"")]

View File

@ -1,7 +1,4 @@
use crate::errors::{ use crate::errors;
InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
SuffixedLiteralInAttribute,
};
use crate::fluent_generated as fluent; use crate::fluent_generated as fluent;
use crate::maybe_whole; use crate::maybe_whole;
@ -318,7 +315,7 @@ impl<'a> Parser<'a> {
debug!("checking if {:?} is unsuffixed", lit); debug!("checking if {:?} is unsuffixed", lit);
if !lit.kind.is_unsuffixed() { if !lit.kind.is_unsuffixed() {
self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span }); self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span });
} }
Ok(lit) Ok(lit)
@ -356,10 +353,11 @@ impl<'a> Parser<'a> {
Ok(nmis) Ok(nmis)
} }
/// Matches the following grammar (per RFC 1559). /// Parse a meta item per RFC 1559.
///
/// ```ebnf /// ```ebnf
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ; /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
/// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ; /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
/// ``` /// ```
pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> { 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` // 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) { Ok(if self.eat(&token::Eq) {
ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?) ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?)
} else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { } 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())?; let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
ast::MetaItemKind::List(list) ast::MetaItemKind::List(list)
} else { } 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> { fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
match self.parse_unsuffixed_meta_item_lit() { match self.parse_unsuffixed_meta_item_lit() {
Ok(lit) => return Ok(ast::NestedMetaItem::Lit(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() { match self.parse_meta_item() {
Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)), 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)] // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
// `from_expansion()` ensures we don't suggest for cases such as // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
// `#[cfg(feature = $expr)]` in macros // when macro metavariables are involved.
if self.prev_token == token::Eq && !self.token.span.from_expansion() { if self.prev_token == token::Eq
&& let token::Ident(..) = self.token.kind
{
let before = self.token.span.shrink_to_lo(); let before = self.token.span.shrink_to_lo();
while matches!(self.token.kind, token::Ident(..)) { while let token::Ident(..) = self.token.kind {
self.bump(); self.bump();
} }
let after = self.prev_token.span.shrink_to_hi(); err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg {
let sugg = InvalidMetaItemSuggQuoteIdent { before, after }; before,
return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent { after: self.prev_token.span.shrink_to_hi(),
span: token.span, });
token,
sugg,
}));
} }
Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token })) Err(self.dcx().create_err(err))
} }
} }

View File

@ -5,7 +5,7 @@
macro_rules! pass_nonterminal { macro_rules! pass_nonterminal {
($n:expr) => { ($n:expr) => {
#[repr(align($n))] #[repr(align($n))]
//~^ ERROR expected unsuffixed literal or identifier, found `n!()` //~^ ERROR expected unsuffixed literal, found `n!()`
struct S; struct S;
}; };
} }

View File

@ -1,4 +1,4 @@
error: expected unsuffixed literal or identifier, found `n!()` error: expected unsuffixed literal, found `n!()`
--> $DIR/nonterminal-expansion.rs:7:22 --> $DIR/nonterminal-expansion.rs:7:22
| |
LL | #[repr(align($n))] LL | #[repr(align($n))]

View File

@ -28,8 +28,8 @@ struct S9;
macro_rules! generate_s10 { macro_rules! generate_s10 {
($expr: expr) => { ($expr: expr) => {
#[cfg(feature = $expr)] #[cfg(feature = $expr)]
//~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` //~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")`
//~| ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")` //~| ERROR expected unsuffixed literal, found `concat!("nonexistent")`
struct S10; struct S10;
} }
} }

View File

@ -54,7 +54,7 @@ LL | #[cfg(a = b"hi")]
| | | |
| help: consider removing the prefix | 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 --> $DIR/cfg-attr-syntax-validation.rs:30:25
| |
LL | #[cfg(feature = $expr)] 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) = 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 --> $DIR/cfg-attr-syntax-validation.rs:30:25
| |
LL | #[cfg(feature = $expr)] LL | #[cfg(feature = $expr)]

View File

@ -4,7 +4,7 @@ error: expected unsuffixed literal, found `test`
LL | #[deprecated(note = 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")] LL | #[deprecated(note = "test")]
| + + | + +

View File

@ -1,12 +1,17 @@
macro_rules! mac { macro_rules! mac {
($attr_item: meta) => { ($attr_item: meta) => {
#[cfg($attr_item)] #[cfg($attr_item)]
//~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)` //~^ ERROR expected unsuffixed literal, 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)`
struct S; struct S;
} }
} }
mac!(an(arbitrary token stream)); mac!(an(arbitrary token stream));
#[cfg(feature = -1)]
//~^ ERROR expected unsuffixed literal, found `-`
//~| ERROR expected unsuffixed literal, found `-`
fn handler() {}
fn main() {} fn main() {}

View File

@ -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 --> $DIR/attr-bad-meta-4.rs:3:15
| |
LL | #[cfg($attr_item)] 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) = 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 --> $DIR/attr-bad-meta-4.rs:3:15
| |
LL | #[cfg($attr_item)] 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: 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) = 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

View File

@ -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!();
}

View File

@ -1,17 +1,25 @@
//@ compile-flags: -Zdeduplicate-diagnostics=yes //@ compile-flags: -Zdeduplicate-diagnostics=yes
//@ run-rustfix
#![allow(unexpected_cfgs)] #![allow(unexpected_cfgs)]
fn main() { fn main() {
#[cfg(key=foo)] #[cfg(key=foo)]
//~^ ERROR expected unsuffixed literal, found `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!(); println!();
#[cfg(key="bar")] #[cfg(key="bar")]
println!(); println!();
#[cfg(key=foo bar baz)] #[cfg(key=foo bar baz)]
//~^ ERROR expected unsuffixed literal, found `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!(); 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

View File

@ -1,24 +1,35 @@
error: expected unsuffixed literal, found `foo` error: expected unsuffixed literal, found `foo`
--> $DIR/attr-unquoted-ident.rs:7:15 --> $DIR/attr-unquoted-ident.rs:6:15
| |
LL | #[cfg(key=foo)] 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")] LL | #[cfg(key="foo")]
| + + | + +
error: expected unsuffixed literal, found `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)] 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")] 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