Skip to content

Commit baf3ab6

Browse files
authored
Unrolled build for #146579
Rollup merge of #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 #146325.
2 parents c61a3a4 + 761cb57 commit baf3ab6

19 files changed

+139
-49
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,19 @@ pub enum StmtKind {
12591259
MacCall(Box<MacCallStmt>),
12601260
}
12611261

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

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ attr_parsing_invalid_link_modifier =
8787
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
8888
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
8989
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
90+
.label = {$descr}s are not allowed here
9091
9192
attr_parsing_invalid_predicate =
9293
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
@@ -804,6 +804,8 @@ pub(crate) struct InvalidMetaItem {
804804
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
805805
#[subdiagnostic]
806806
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
807+
#[label]
808+
pub label: Option<Span>,
807809
}
808810

809811
#[derive(Subdiagnostic)]

compiler/rustc_parse/src/parser/diagnostics.rs

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

286286
/// Replace `self` with `snapshot.parser`.
287-
pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
287+
pub fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) {
288288
*self = snapshot.parser;
289289
}
290290

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/macros/cfg_select.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ cfg_select! {
6868

6969
cfg_select! {
7070
() => {}
71-
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(`
71+
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
7272
}
7373

7474
cfg_select! {

0 commit comments

Comments
 (0)