Skip to content

Commit c1f610a

Browse files
authored
Rollup merge of rust-lang#146579 - estebank:issue-146325, r=jdonszelmann
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 ``` Fix rust-lang#146325.
2 parents 055d0d6 + 9ca8198 commit c1f610a

17 files changed

+136
-46
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,19 @@ pub enum StmtKind {
12561256
MacCall(Box<MacCallStmt>),
12571257
}
12581258

1259+
impl StmtKind {
1260+
pub fn descr(&self) -> &'static str {
1261+
match self {
1262+
StmtKind::Let(_) => "local",
1263+
StmtKind::Item(_) => "item",
1264+
StmtKind::Expr(_) => "expression",
1265+
StmtKind::Semi(_) => "statement",
1266+
StmtKind::Empty => "semicolon",
1267+
StmtKind::MacCall(_) => "macro call",
1268+
}
1269+
}
1270+
}
1271+
12591272
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
12601273
pub struct MacCallStmt {
12611274
pub mac: Box<MacCall>,

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 = {$descr}s are not allowed here
102103
103104
attr_parsing_invalid_predicate =
104105
invalid predicate `{$predicate}`

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 45 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use std::fmt::{Debug, Display};
88

99
use rustc_ast::token::{self, Delimiter, MetaVarKind};
1010
use rustc_ast::tokenstream::TokenStream;
11-
use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
11+
use rustc_ast::{AttrArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path, StmtKind, UnOp};
1212
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,33 +488,55 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
488488
descr: token_descr(&self.parser.token),
489489
quote_ident_sugg: None,
490490
remove_neg_sugg: None,
491+
label: None,
491492
};
492493

494+
if let token::OpenInvisible(_) = self.parser.token.kind {
495+
// Do not attempt to suggest anything when encountered as part of a macro expansion.
496+
return self.parser.dcx().create_err(err);
497+
}
498+
493499
// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
494500
// don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
495501
// when macro metavariables are involved.
496-
if self.parser.prev_token == token::Eq
497-
&& let token::Ident(..) = self.parser.token.kind
498-
{
499-
let before = self.parser.token.span.shrink_to_lo();
500-
while let token::Ident(..) = self.parser.token.kind {
501-
self.parser.bump();
502+
let snapshot = self.parser.create_snapshot_for_diagnostic();
503+
let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false);
504+
match stmt {
505+
Ok(Some(stmt)) => {
506+
// The user tried to write something like
507+
// `#[deprecated(note = concat!("a", "b"))]`.
508+
err.descr = stmt.kind.descr().to_string();
509+
err.label = Some(stmt.span);
510+
err.span = stmt.span;
511+
if let StmtKind::Expr(expr) = &stmt.kind
512+
&& let ExprKind::Unary(UnOp::Neg, val) = &expr.kind
513+
&& let ExprKind::Lit(_) = val.kind
514+
{
515+
err.remove_neg_sugg = Some(InvalidMetaItemRemoveNegSugg {
516+
negative_sign: expr.span.until(val.span),
517+
});
518+
} else if let StmtKind::Expr(expr) = &stmt.kind
519+
&& let ExprKind::Path(None, Path { segments, .. }) = &expr.kind
520+
&& segments.len() == 1
521+
{
522+
while let token::Ident(..) | token::Literal(_) | token::Dot =
523+
self.parser.token.kind
524+
{
525+
// We've got a word, so we try to consume the rest of a potential sentence.
526+
// We include `.` to correctly handle things like `A sentence here.`.
527+
self.parser.bump();
528+
}
529+
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
530+
before: expr.span.shrink_to_lo(),
531+
after: self.parser.prev_token.span.shrink_to_hi(),
532+
});
533+
}
534+
}
535+
Ok(None) => {}
536+
Err(e) => {
537+
e.cancel();
538+
self.parser.restore_snapshot(snapshot);
502539
}
503-
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
504-
before,
505-
after: self.parser.prev_token.span.shrink_to_hi(),
506-
});
507-
}
508-
509-
if self.parser.token == token::Minus
510-
&& self
511-
.parser
512-
.look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
513-
{
514-
err.remove_neg_sugg =
515-
Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });
516-
self.parser.bump();
517-
self.parser.bump();
518540
}
519541

520542
self.parser.dcx().create_err(err)

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -846,6 +846,8 @@ pub(crate) struct InvalidMetaItem {
846846
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
847847
#[subdiagnostic]
848848
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
849+
#[label]
850+
pub label: Option<Span>,
849851
}
850852

851853
#[derive(Subdiagnostic)]

compiler/rustc_parse/src/parser/diagnostics.rs

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

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

tests/ui/attributes/malformed-fn-align.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn f3() {}
2626
#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on functions
2727
fn f4() {}
2828

29-
#[rustc_align(-1)] //~ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
29+
#[rustc_align(-1)] //~ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
3030
fn f5() {}
3131

3232
#[rustc_align(3)] //~ ERROR invalid alignment value: not a power of two

tests/ui/attributes/malformed-fn-align.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ error[E0589]: invalid alignment value: not a power of two
3737
LL | #[rustc_align(0)]
3838
| ^
3939

40-
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
40+
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
4141
--> $DIR/malformed-fn-align.rs:29:15
4242
|
4343
LL | #[rustc_align(-1)]
44-
| ^
44+
| ^^ expressions are not allowed here
4545
|
4646
help: negative numbers are not literals, try removing the `-` sign
4747
|

tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ fn main() {
77
}
88

99
#[deprecated(note = test)]
10-
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test`
10+
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
1111
fn foo() {}

tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test`
1+
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
22
--> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21
33
|
44
LL | #[deprecated(note = test)]
5-
| ^^^^
5+
| ^^^^ expressions are not allowed here
66
|
77
help: surround the identifier with quotation marks to make it into a string literal
88
|

tests/ui/parser/attribute/attr-bad-meta-4.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ macro_rules! mac {
99
mac!(an(arbitrary token stream));
1010

1111
#[cfg(feature = -1)]
12-
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
12+
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
1313
fn handler() {}
1414

1515
fn main() {}

0 commit comments

Comments
 (0)