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:
Esteban Küber 2025-09-15 02:28:43 -07:00 committed by Esteban Küber
parent 5bc345055b
commit 01e2cf8f44
6 changed files with 50 additions and 12 deletions

View file

@ -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}`

View file

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

View file

@ -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)]

View file

@ -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;
}

View 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() {}

View 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