Handle macro invocation in attribute during parse
```
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat`
--> $DIR/macro-in-attribute.rs:4:21
|
LL | #[deprecated(note = concat!("a", "b"))]
| ^^^^^^^^^^^^^^^^^ macros are not allowed here
```
This commit is contained in:
parent
5bc345055b
commit
01e2cf8f44
6 changed files with 50 additions and 12 deletions
|
|
@ -87,6 +87,7 @@ attr_parsing_invalid_link_modifier =
|
|||
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
|
||||
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
|
||||
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
|
||||
.label = macros are not allowed here
|
||||
|
||||
attr_parsing_invalid_predicate =
|
||||
invalid predicate `{$predicate}`
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust;
|
|||
use rustc_errors::{Diag, PResult};
|
||||
use rustc_hir::{self as hir, AttrPath};
|
||||
use rustc_parse::exp;
|
||||
use rustc_parse::parser::{Parser, PathStyle, token_descr};
|
||||
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
|
||||
use rustc_session::errors::{create_lit_error, report_lit_error};
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
|
||||
|
|
@ -488,6 +488,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
|||
descr: token_descr(&self.parser.token),
|
||||
quote_ident_sugg: None,
|
||||
remove_neg_sugg: None,
|
||||
macro_call: None,
|
||||
};
|
||||
|
||||
// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
|
||||
|
|
@ -496,20 +497,37 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
|
|||
if self.parser.prev_token == token::Eq
|
||||
&& let token::Ident(..) = self.parser.token.kind
|
||||
{
|
||||
let before = self.parser.token.span.shrink_to_lo();
|
||||
while let token::Ident(..) = self.parser.token.kind {
|
||||
self.parser.bump();
|
||||
if self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Bang)) {
|
||||
let snapshot = self.parser.create_snapshot_for_diagnostic();
|
||||
let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false);
|
||||
match stmt {
|
||||
Ok(Some(stmt)) => {
|
||||
// The user tried to write something like
|
||||
// `#[deprecated(note = concat!("a", "b"))]`.
|
||||
err.descr = format!("macro {}", err.descr);
|
||||
err.macro_call = Some(stmt.span);
|
||||
err.span = stmt.span;
|
||||
}
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
err.cancel();
|
||||
self.parser.restore_snapshot(snapshot);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let before = self.parser.token.span.shrink_to_lo();
|
||||
while let token::Ident(..) = self.parser.token.kind {
|
||||
self.parser.bump();
|
||||
}
|
||||
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
|
||||
before,
|
||||
after: self.parser.prev_token.span.shrink_to_hi(),
|
||||
});
|
||||
}
|
||||
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
|
||||
before,
|
||||
after: self.parser.prev_token.span.shrink_to_hi(),
|
||||
});
|
||||
}
|
||||
|
||||
if self.parser.token == token::Minus
|
||||
&& self
|
||||
.parser
|
||||
.look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
|
||||
&& self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Literal { .. }))
|
||||
{
|
||||
err.remove_neg_sugg =
|
||||
Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });
|
||||
|
|
|
|||
|
|
@ -804,6 +804,8 @@ pub(crate) struct InvalidMetaItem {
|
|||
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
|
||||
#[subdiagnostic]
|
||||
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
|
||||
#[label]
|
||||
pub macro_call: Option<Span>,
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
/// Replace `self` with `snapshot.parser`.
|
||||
pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
|
||||
pub fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
|
||||
*self = snapshot.parser;
|
||||
}
|
||||
|
||||
|
|
|
|||
9
tests/ui/parser/macro/macro-in-attribute.rs
Normal file
9
tests/ui/parser/macro/macro-in-attribute.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Test for #146325.
|
||||
// Ensure that when we encounter a macro invocation in an attribute, we don't suggest nonsense.
|
||||
|
||||
#[deprecated(note = concat!("a", "b"))]
|
||||
struct X;
|
||||
//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat`
|
||||
//~| NOTE: macros are not allowed here
|
||||
|
||||
fn main() {}
|
||||
8
tests/ui/parser/macro/macro-in-attribute.stderr
Normal file
8
tests/ui/parser/macro/macro-in-attribute.stderr
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat`
|
||||
--> $DIR/macro-in-attribute.rs:4:21
|
||||
|
|
||||
LL | #[deprecated(note = concat!("a", "b"))]
|
||||
| ^^^^^^^^^^^^^^^^^ macros are not allowed here
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue