Skip to content

Commit d7b9a26

Browse files
committed
Rework attribute recovery logic
1 parent f183966 commit d7b9a26

16 files changed

+116
-64
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,19 @@ pub enum StmtKind {
12471247
MacCall(Box<MacCallStmt>),
12481248
}
12491249

1250+
impl StmtKind {
1251+
pub fn descr(&self) -> &'static str {
1252+
match self {
1253+
StmtKind::Let(_) => "local",
1254+
StmtKind::Item(_) => "item",
1255+
StmtKind::Expr(_) => "expression",
1256+
StmtKind::Semi(_) => "statement",
1257+
StmtKind::Empty => "semicolon",
1258+
StmtKind::MacCall(_) => "macro",
1259+
}
1260+
}
1261+
}
1262+
12501263
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
12511264
pub struct MacCallStmt {
12521265
pub mac: Box<MacCall>,

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +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
102+
.label = {$descr}s are not allowed here
103103
104104
attr_parsing_invalid_predicate =
105105
invalid predicate `{$predicate}`

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ 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};
@@ -488,51 +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-
macro_call: None,
491+
label: None,
492492
};
493493

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+
494499
// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
495500
// don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
496501
// when macro metavariables are involved.
497-
if self.parser.prev_token == token::Eq
498-
&& let token::Ident(..) = self.parser.token.kind
499-
{
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);
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();
515528
}
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+
});
516533
}
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-
});
526534
}
527-
}
528-
529-
if self.parser.token == token::Minus
530-
&& self.parser.look_ahead(1, |t| matches!(t.kind, token::TokenKind::Literal { .. }))
531-
{
532-
err.remove_neg_sugg =
533-
Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });
534-
self.parser.bump();
535-
self.parser.bump();
535+
Ok(None) => {}
536+
Err(e) => {
537+
e.cancel();
538+
self.parser.restore_snapshot(snapshot);
539+
}
536540
}
537541

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

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,7 @@ pub(crate) struct InvalidMetaItem {
832832
#[subdiagnostic]
833833
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
834834
#[label]
835-
pub macro_call: Option<Span>,
835+
pub label: Option<Span>,
836836
}
837837

838838
#[derive(Subdiagnostic)]

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

tests/ui/parser/attribute/attr-bad-meta-4.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 `-`
1+
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
22
--> $DIR/attr-bad-meta-4.rs:11:17
33
|
44
LL | #[cfg(feature = -1)]
5-
| ^
5+
| ^^ expressions are not allowed here
66
|
77
help: negative numbers are not literals, try removing the `-` sign
88
|

0 commit comments

Comments
 (0)