Skip to content

Commit f48a21e

Browse files
committed
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 ```
1 parent 52618eb commit f48a21e

File tree

6 files changed

+50
-12
lines changed

6 files changed

+50
-12
lines changed

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
192192
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
193193
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
194194
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
195+
.label = macros are not allowed here
195196
196197
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
197198
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust;
1313
use rustc_errors::{Diag, PResult};
1414
use rustc_hir::{self as hir, AttrPath};
1515
use rustc_parse::exp;
16-
use rustc_parse::parser::{Parser, PathStyle, token_descr};
16+
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
1717
use rustc_session::errors::{create_lit_error, report_lit_error};
1818
use rustc_session::parse::ParseSess;
1919
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
@@ -476,6 +476,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
476476
descr: token_descr(&self.parser.token),
477477
quote_ident_sugg: None,
478478
remove_neg_sugg: None,
479+
macro_call: None,
479480
};
480481

481482
// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
@@ -484,20 +485,37 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
484485
if self.parser.prev_token == token::Eq
485486
&& let token::Ident(..) = self.parser.token.kind
486487
{
487-
let before = self.parser.token.span.shrink_to_lo();
488-
while let token::Ident(..) = self.parser.token.kind {
489-
self.parser.bump();
488+
if self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Bang)) {
489+
let snapshot = self.parser.create_snapshot_for_diagnostic();
490+
let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false);
491+
match stmt {
492+
Ok(Some(stmt)) => {
493+
// The user tried to write something like
494+
// `#[deprecated(note = concat!("a", "b"))]`.
495+
err.descr = format!("macro {}", err.descr);
496+
err.macro_call = Some(stmt.span);
497+
err.span = stmt.span;
498+
}
499+
Ok(None) => {}
500+
Err(err) => {
501+
err.cancel();
502+
self.parser.restore_snapshot(snapshot);
503+
}
504+
}
505+
} else {
506+
let before = self.parser.token.span.shrink_to_lo();
507+
while let token::Ident(..) = self.parser.token.kind {
508+
self.parser.bump();
509+
}
510+
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
511+
before,
512+
after: self.parser.prev_token.span.shrink_to_hi(),
513+
});
490514
}
491-
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
492-
before,
493-
after: self.parser.prev_token.span.shrink_to_hi(),
494-
});
495515
}
496516

497517
if self.parser.token == token::Minus
498-
&& self
499-
.parser
500-
.look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
518+
&& self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Literal { .. }))
501519
{
502520
err.remove_neg_sugg =
503521
Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,8 @@ pub(crate) struct InvalidMetaItem {
801801
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
802802
#[subdiagnostic]
803803
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
804+
#[label]
805+
pub macro_call: Option<Span>,
804806
}
805807

806808
#[derive(Subdiagnostic)]

compiler/rustc_parse/src/parser/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ impl<'a> Parser<'a> {
278278
}
279279

280280
/// Replace `self` with `snapshot.parser`.
281-
pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
281+
pub fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
282282
*self = snapshot.parser;
283283
}
284284

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// Test for #146325.
2+
// Ensure that when we encounter a macro invocation in an attribute, we don't suggest nonsense.
3+
4+
#[deprecated(note = concat!("a", "b"))]
5+
struct X;
6+
//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat`
7+
//~| NOTE: macros are not allowed here
8+
9+
fn main() {}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro `concat`
2+
--> $DIR/macro-in-attribute.rs:4:21
3+
|
4+
LL | #[deprecated(note = concat!("a", "b"))]
5+
| ^^^^^^^^^^^^^^^^^ macros are not allowed here
6+
7+
error: aborting due to 1 previous error
8+

0 commit comments

Comments
 (0)