Skip to content

Commit f183966

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 35ebdf9 commit f183966

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
@@ -99,6 +99,7 @@ attr_parsing_invalid_link_modifier =
9999
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
100100
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
101101
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
102+
.label = macros are not allowed here
102103
103104
attr_parsing_invalid_predicate =
104105
invalid predicate `{$predicate}`

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};
@@ -488,6 +488,7 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
488488
descr: token_descr(&self.parser.token),
489489
quote_ident_sugg: None,
490490
remove_neg_sugg: None,
491+
macro_call: None,
491492
};
492493

493494
// 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> {
496497
if self.parser.prev_token == token::Eq
497498
&& let token::Ident(..) = self.parser.token.kind
498499
{
499-
let before = self.parser.token.span.shrink_to_lo();
500-
while let token::Ident(..) = self.parser.token.kind {
501-
self.parser.bump();
500+
if self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Bang)) {
501+
let snapshot = self.parser.create_snapshot_for_diagnostic();
502+
let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false);
503+
match stmt {
504+
Ok(Some(stmt)) => {
505+
// The user tried to write something like
506+
// `#[deprecated(note = concat!("a", "b"))]`.
507+
err.descr = format!("macro {}", err.descr);
508+
err.macro_call = Some(stmt.span);
509+
err.span = stmt.span;
510+
}
511+
Ok(None) => {}
512+
Err(err) => {
513+
err.cancel();
514+
self.parser.restore_snapshot(snapshot);
515+
}
516+
}
517+
} else {
518+
let before = self.parser.token.span.shrink_to_lo();
519+
while let token::Ident(..) = self.parser.token.kind {
520+
self.parser.bump();
521+
}
522+
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
523+
before,
524+
after: self.parser.prev_token.span.shrink_to_hi(),
525+
});
502526
}
503-
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
504-
before,
505-
after: self.parser.prev_token.span.shrink_to_hi(),
506-
});
507527
}
508528

509529
if self.parser.token == token::Minus
510-
&& self
511-
.parser
512-
.look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
530+
&& self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Literal { .. }))
513531
{
514532
err.remove_neg_sugg =
515533
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
@@ -831,6 +831,8 @@ pub(crate) struct InvalidMetaItem {
831831
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
832832
#[subdiagnostic]
833833
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
834+
#[label]
835+
pub macro_call: Option<Span>,
834836
}
835837

836838
#[derive(Subdiagnostic)]

compiler/rustc_parse/src/parser/diagnostics.rs

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

290290
/// Replace `self` with `snapshot.parser`.
291-
pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
291+
pub fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
292292
*self = snapshot.parser;
293293
}
294294

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)