Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,19 @@ pub enum StmtKind {
MacCall(Box<MacCallStmt>),
}

impl StmtKind {
pub fn descr(&self) -> &'static str {
match self {
StmtKind::Let(_) => "local",
StmtKind::Item(_) => "item",
StmtKind::Expr(_) => "expression",
StmtKind::Semi(_) => "statement",
StmtKind::Empty => "semicolon",
StmtKind::MacCall(_) => "macro",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"macro call" intead of "macro"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, macro calls feel more appropriate

}
}
}

#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct MacCallStmt {
pub mac: Box<MacCall>,
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_attr_parsing/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
.label = {$descr}s are not allowed here

attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
Expand Down
70 changes: 47 additions & 23 deletions compiler/rustc_attr_parsing/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ use std::fmt::{Debug, Display};

use rustc_ast::token::{self, Delimiter, MetaVarKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
use rustc_ast::{
AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path, StmtKind, UnOp,
};
use rustc_ast_pretty::pprust;
use rustc_errors::{Diag, PResult};
use rustc_hir::{self as hir, AttrPath};
use rustc_parse::exp;
use rustc_parse::parser::{Parser, PathStyle, token_descr};
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
use rustc_session::errors::{create_lit_error, report_lit_error};
use rustc_session::parse::ParseSess;
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
Expand Down Expand Up @@ -476,33 +478,55 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
descr: token_descr(&self.parser.token),
quote_ident_sugg: None,
remove_neg_sugg: None,
label: None,
};

if let token::OpenInvisible(_) = self.parser.token.kind {
// Do not attempt to suggest anything when encountered as part of a macro expansion.
return self.parser.dcx().create_err(err);
}

// Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
// don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
// when macro metavariables are involved.
if self.parser.prev_token == token::Eq
&& let token::Ident(..) = self.parser.token.kind
{
let before = self.parser.token.span.shrink_to_lo();
while let token::Ident(..) = self.parser.token.kind {
self.parser.bump();
let snapshot = self.parser.create_snapshot_for_diagnostic();
let stmt = self.parser.parse_stmt_without_recovery(false, ForceCollect::No, false);
match stmt {
Ok(Some(stmt)) => {
// The user tried to write something like
// `#[deprecated(note = concat!("a", "b"))]`.
err.descr = stmt.kind.descr().to_string();
err.label = Some(stmt.span);
err.span = stmt.span;
if let StmtKind::Expr(expr) = &stmt.kind
&& let ExprKind::Unary(UnOp::Neg, val) = &expr.kind
&& let ExprKind::Lit(_) = val.kind
{
err.remove_neg_sugg = Some(InvalidMetaItemRemoveNegSugg {
negative_sign: expr.span.until(val.span),
});
} else if let StmtKind::Expr(expr) = &stmt.kind
&& let ExprKind::Path(None, Path { segments, .. }) = &expr.kind
&& segments.len() == 1
{
while let token::Ident(..) | token::Literal(_) | token::Dot =
self.parser.token.kind
{
// We've got a word, so we try to consume the rest of a potential sentence.
// We include `.` to correctly handle things like `A sentence here.`.
self.parser.bump();
}
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
before: expr.span.shrink_to_lo(),
after: self.parser.prev_token.span.shrink_to_hi(),
});
}
}
Ok(None) => {}
Err(e) => {
e.cancel();
self.parser.restore_snapshot(snapshot);
}
err.quote_ident_sugg = Some(InvalidMetaItemQuoteIdentSugg {
before,
after: self.parser.prev_token.span.shrink_to_hi(),
});
}

if self.parser.token == token::Minus
&& self
.parser
.look_ahead(1, |t| matches!(t.kind, rustc_ast::token::TokenKind::Literal { .. }))
{
err.remove_neg_sugg =
Some(InvalidMetaItemRemoveNegSugg { negative_sign: self.parser.token.span });
self.parser.bump();
self.parser.bump();
}

self.parser.dcx().create_err(err)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_attr_parsing/src/session_diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -829,6 +829,8 @@ pub(crate) struct InvalidMetaItem {
pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
#[subdiagnostic]
pub remove_neg_sugg: Option<InvalidMetaItemRemoveNegSugg>,
#[label]
pub label: Option<Span>,
}

#[derive(Subdiagnostic)]
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_parse/src/parser/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ impl<'a> Parser<'a> {
}

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

Expand Down
2 changes: 1 addition & 1 deletion tests/ui/attributes/malformed-fn-align.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn f3() {}
#[repr(align(16))] //~ ERROR `#[repr(align(...))]` is not supported on functions
fn f4() {}

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

#[rustc_align(3)] //~ ERROR invalid alignment value: not a power of two
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/attributes/malformed-fn-align.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ error[E0589]: invalid alignment value: not a power of two
LL | #[rustc_align(0)]
| ^

error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/malformed-fn-align.rs:29:15
|
LL | #[rustc_align(-1)]
| ^
| ^^ expressions are not allowed here
|
help: negative numbers are not literals, try removing the `-` sign
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ fn main() {
}

#[deprecated(note = test)]
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test`
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
fn foo() {}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `test`
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:9:21
|
LL | #[deprecated(note = test)]
| ^^^^
| ^^^^ expressions are not allowed here
|
help: surround the identifier with quotation marks to make it into a string literal
|
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/parser/attribute/attr-bad-meta-4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ macro_rules! mac {
mac!(an(arbitrary token stream));

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

fn main() {}
4 changes: 2 additions & 2 deletions tests/ui/parser/attribute/attr-bad-meta-4.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-`
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/attr-bad-meta-4.rs:11:17
|
LL | #[cfg(feature = -1)]
| ^
| ^^ expressions are not allowed here
|
help: negative numbers are not literals, try removing the `-` sign
|
Expand Down
19 changes: 13 additions & 6 deletions tests/ui/parser/attribute/attr-unquoted-ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,29 @@

fn main() {
#[cfg(key=foo)]
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
//~| HELP surround the identifier with quotation marks to make it into a string literal
//~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
//~| HELP: surround the identifier with quotation marks to make it into a string literal
//~| NOTE: expressions are not allowed here
println!();
#[cfg(key="bar")]
println!();
#[cfg(key=foo bar baz)]
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
//~| HELP surround the identifier with quotation marks to make it into a string literal
//~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
//~| HELP: surround the identifier with quotation marks to make it into a string literal
//~| NOTE: expressions are not allowed here
println!();
#[cfg(key=foo 1 bar 2.0 baz.)]
//~^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
//~| HELP: surround the identifier with quotation marks to make it into a string literal
//~| NOTE: expressions are not allowed here
println!();
}

// Don't suggest surrounding `$name` or `nickname` with quotes:

macro_rules! make {
($name:ident) => { #[doc(alias = $name)] pub struct S; }
//~^ ERROR expected unsuffixed literal, found identifier `nickname`
//~^ ERROR: expected unsuffixed literal, found identifier `nickname`
}

make!(nickname); //~ NOTE in this expansion
make!(nickname); //~ NOTE: in this expansion
25 changes: 18 additions & 7 deletions tests/ui/parser/attribute/attr-unquoted-ident.stderr
Original file line number Diff line number Diff line change
@@ -1,27 +1,38 @@
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/attr-unquoted-ident.rs:6:15
|
LL | #[cfg(key=foo)]
| ^^^
| ^^^ expressions are not allowed here
|
help: surround the identifier with quotation marks to make it into a string literal
|
LL | #[cfg(key="foo")]
| + +

error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `foo`
--> $DIR/attr-unquoted-ident.rs:12:15
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/attr-unquoted-ident.rs:13:15
|
LL | #[cfg(key=foo bar baz)]
| ^^^
| ^^^ expressions are not allowed here
|
help: surround the identifier with quotation marks to make it into a string literal
|
LL | #[cfg(key="foo bar baz")]
| + +

error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/attr-unquoted-ident.rs:18:15
|
LL | #[cfg(key=foo 1 bar 2.0 baz.)]
| ^^^ expressions are not allowed here
|
help: surround the identifier with quotation marks to make it into a string literal
|
LL | #[cfg(key="foo 1 bar 2.0 baz.")]
| + +

error: expected unsuffixed literal, found identifier `nickname`
--> $DIR/attr-unquoted-ident.rs:21:38
--> $DIR/attr-unquoted-ident.rs:28:38
|
LL | ($name:ident) => { #[doc(alias = $name)] pub struct S; }
| ^^^^^
Expand All @@ -31,5 +42,5 @@ LL | make!(nickname);
|
= note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to 3 previous errors
error: aborting due to 4 previous errors

9 changes: 9 additions & 0 deletions tests/ui/parser/macro/expr-in-attribute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Test for #146325.
// Ensure that when we encounter an expr invocation in an attribute, we don't suggest nonsense.

#[deprecated(note = a!=b)]
struct X;
//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
//~| NOTE: expressions are not allowed here

fn main() {}
8 changes: 8 additions & 0 deletions tests/ui/parser/macro/expr-in-attribute.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/expr-in-attribute.rs:4:21
|
LL | #[deprecated(note = a!=b)]
| ^^^^ expressions are not allowed here

error: aborting due to 1 previous error

9 changes: 9 additions & 0 deletions tests/ui/parser/macro/macro-in-attribute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Test for #146325.
// Ensure that when we encounter a macro invocation in an attribute, we don't suggest nonsense.

#[deprecated(note = concat!("a", "b"))]
struct X;
//~^^ ERROR: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found
//~| NOTE: macros are not allowed here

fn main() {}
8 changes: 8 additions & 0 deletions tests/ui/parser/macro/macro-in-attribute.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found macro
--> $DIR/macro-in-attribute.rs:4:21
|
LL | #[deprecated(note = concat!("a", "b"))]
| ^^^^^^^^^^^^^^^^^ macros are not allowed here

error: aborting due to 1 previous error

Loading