diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 6ada93b4c89b9..1492d50288995 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -424,7 +424,7 @@ impl MetaItem { _span, _spacing, Delimiter::Invisible(InvisibleOrigin::MetaVar( - MetaVarKind::Meta { .. } | MetaVarKind::Path, + MetaVarKind::Meta | MetaVarKind::Path, )), _stream, )) => { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 6dc6d1026f621..277aab9ce4247 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -64,10 +64,7 @@ pub enum MetaVarKind { Ident, Lifetime, Literal, - Meta { - /// Will `AttrItem::meta` succeed on this, if reparsed? - has_meta_form: bool, - }, + Meta, Path, Vis, TT, @@ -87,7 +84,7 @@ impl fmt::Display for MetaVarKind { MetaVarKind::Ident => sym::ident, MetaVarKind::Lifetime => sym::lifetime, MetaVarKind::Literal => sym::literal, - MetaVarKind::Meta { .. } => sym::meta, + MetaVarKind::Meta => sym::meta, MetaVarKind::Path => sym::path, MetaVarKind::Vis => sym::vis, MetaVarKind::TT => sym::tt, @@ -693,7 +690,7 @@ impl Token { OpenInvisible(InvisibleOrigin::MetaVar( MetaVarKind::Expr { .. } | MetaVarKind::Literal | - MetaVarKind::Meta { .. } | + MetaVarKind::Meta | MetaVarKind::Pat(_) | MetaVarKind::Path | MetaVarKind::Ty { .. } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 4f903594225e0..70ef1cb6a53b3 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -410,19 +410,18 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { } fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser<'static>> { - if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() { - return if has_meta_form { - let attr_item = self - .parser - .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { - MetaItemListParserContext { parser: this, should_emit: self.should_emit } - .parse_attr_item() - }) - .unwrap(); - Ok(attr_item) - } else { - self.parser.unexpected_any() - }; + if let Some(mv_kind @ (MetaVarKind::Meta | MetaVarKind::Expr { .. })) = + self.parser.token.is_metavar_seq() + { + return self + .parser + .eat_metavar_seq(mv_kind, |this| { + MetaItemListParserContext { parser: this, should_emit: self.should_emit } + .parse_attr_item() + }) + .ok_or_else(|| { + self.parser.unexpected_any::().unwrap_err() + }); } let path = self.parser.parse_path(PathStyle::Mod)?; diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index dddd62a4945a2..10e7f205abfcf 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -481,12 +481,7 @@ fn transcribe_pnr<'tx>( mk_delimited(ty.span, MetaVarKind::Ty { is_path }, TokenStream::from_ast(ty)) } ParseNtResult::Meta(attr_item) => { - let has_meta_form = attr_item.meta_kind().is_some(); - mk_delimited( - attr_item.span(), - MetaVarKind::Meta { has_meta_form }, - TokenStream::from_ast(attr_item), - ) + mk_delimited(attr_item.span(), MetaVarKind::Meta, TokenStream::from_ast(attr_item)) } ParseNtResult::Path(path) => { mk_delimited(path.span, MetaVarKind::Path, TokenStream::from_ast(path)) diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index acd338156ce88..c98906996d888 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -290,7 +290,7 @@ impl<'a> Parser<'a> { /// The delimiters or `=` are still put into the resulting token stream. pub fn parse_attr_item(&mut self, force_collect: ForceCollect) -> PResult<'a, ast::AttrItem> { if let Some(item) = self.eat_metavar_seq_with_matcher( - |mv_kind| matches!(mv_kind, MetaVarKind::Meta { .. }), + |mv_kind| matches!(mv_kind, MetaVarKind::Meta), |this| this.parse_attr_item(force_collect), ) { return Ok(item); @@ -421,17 +421,13 @@ impl<'a> Parser<'a> { &mut self, unsafe_allowed: AllowLeadingUnsafe, ) -> PResult<'a, ast::MetaItem> { - if let Some(MetaVarKind::Meta { has_meta_form }) = self.token.is_metavar_seq() { - return if has_meta_form { - let attr_item = self - .eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| { - this.parse_attr_item(ForceCollect::No) - }) - .unwrap(); - Ok(attr_item.meta(attr_item.path.span).unwrap()) - } else { - self.unexpected_any() - }; + if let Some(mv_kind @ (MetaVarKind::Meta | MetaVarKind::Expr { .. })) = + self.token.is_metavar_seq() + { + return self + .eat_metavar_seq(mv_kind, |this| this.parse_attr_item(ForceCollect::No)) + .map(|attr_item| attr_item.meta(attr_item.path.span).unwrap()) + .ok_or_else(|| self.unexpected_any::().unwrap_err()); } let lo = self.token.span; diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index 42eb07858c2fe..8791816077b74 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -24,7 +24,7 @@ impl<'a> Parser<'a> { | MetaVarKind::Expr { .. } | MetaVarKind::Ty { .. } | MetaVarKind::Literal // `true`, `false` - | MetaVarKind::Meta { .. } + | MetaVarKind::Meta | MetaVarKind::Path => true, MetaVarKind::Item @@ -82,7 +82,7 @@ impl<'a> Parser<'a> { MetaVarKind::Item | MetaVarKind::Pat(_) | MetaVarKind::Ty { .. } - | MetaVarKind::Meta { .. } + | MetaVarKind::Meta | MetaVarKind::Path | MetaVarKind::Vis => false, MetaVarKind::Lifetime | MetaVarKind::Ident | MetaVarKind::TT => { diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs index ff2b36f7d27d5..85ea6341c16b1 100644 --- a/tests/ui/attributes/nonterminal-expansion.rs +++ b/tests/ui/attributes/nonterminal-expansion.rs @@ -5,8 +5,7 @@ macro_rules! pass_nonterminal { ($n:expr) => { #[repr(align($n))] - //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable - struct S; + fn foo() {} }; } @@ -15,5 +14,6 @@ macro_rules! n { } pass_nonterminal!(n!()); +//~^ ERROR expected one of `(`, `::`, or `=`, found `!` fn main() {} diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr index 21912de210610..5fcb6b63ab702 100644 --- a/tests/ui/attributes/nonterminal-expansion.stderr +++ b/tests/ui/attributes/nonterminal-expansion.stderr @@ -1,13 +1,8 @@ -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `expr` metavariable - --> $DIR/nonterminal-expansion.rs:7:22 +error: expected one of `(`, `::`, or `=`, found `!` + --> $DIR/nonterminal-expansion.rs:16:20 | -LL | #[repr(align($n))] - | ^^ -... LL | pass_nonterminal!(n!()); - | ----------------------- in this macro invocation - | - = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info) + | ^ expected one of `(`, `::`, or `=` error: aborting due to 1 previous error diff --git a/tests/ui/macros/attr-expr.rs b/tests/ui/macros/attr-expr.rs new file mode 100644 index 0000000000000..b743d9d512b44 --- /dev/null +++ b/tests/ui/macros/attr-expr.rs @@ -0,0 +1,11 @@ +macro_rules! foo { + ($e:expr) => { + #[$e] + //~^ ERROR expected identifier, found metavariable + fn foo() {} + } +} + +foo!(inline); + +fn main() {} diff --git a/tests/ui/macros/attr-expr.stderr b/tests/ui/macros/attr-expr.stderr new file mode 100644 index 0000000000000..034f116d017d4 --- /dev/null +++ b/tests/ui/macros/attr-expr.stderr @@ -0,0 +1,13 @@ +error: expected identifier, found metavariable + --> $DIR/attr-expr.rs:3:11 + | +LL | #[$e] + | ^^ expected identifier, found metavariable +... +LL | foo!(inline); + | ------------ in this macro invocation + | + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/cfg_attr-expr.rs b/tests/ui/macros/cfg_attr-expr.rs new file mode 100644 index 0000000000000..7c2b021c15b10 --- /dev/null +++ b/tests/ui/macros/cfg_attr-expr.rs @@ -0,0 +1,11 @@ +macro_rules! foo { + ($e:expr) => { + #[cfg_attr(true, $e)] + //~^ ERROR expected identifier, found metavariable + fn foo() {} + } +} + +foo!(inline); + +fn main() {} diff --git a/tests/ui/macros/cfg_attr-expr.stderr b/tests/ui/macros/cfg_attr-expr.stderr new file mode 100644 index 0000000000000..a3bf7e38fe7e9 --- /dev/null +++ b/tests/ui/macros/cfg_attr-expr.stderr @@ -0,0 +1,15 @@ +error: expected identifier, found metavariable + --> $DIR/cfg_attr-expr.rs:3:26 + | +LL | #[cfg_attr(true, $e)] + | ^^ expected identifier, found metavariable +... +LL | foo!(inline); + | ------------ in this macro invocation + | + = help: the valid syntax is `#[cfg_attr(condition, attribute, other_attribute, ...)]` + = note: for more information, visit + = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error + diff --git a/tests/ui/macros/cfg_expr.rs b/tests/ui/macros/cfg_expr.rs new file mode 100644 index 0000000000000..b7c2419d05851 --- /dev/null +++ b/tests/ui/macros/cfg_expr.rs @@ -0,0 +1,26 @@ +//@ run-pass + +macro_rules! foo { + ($e:expr, $n:ident) => { + #[cfg_attr($e, allow(non_snake_case))] + #[cfg($e)] + fn $n() {} + + #[cfg_attr(not($e), allow(unused))] + #[cfg(not($e))] + fn $n() { + panic!() + } + } +} + +foo!(true, BAR); +foo!(any(true, unix, target_pointer_width = "64"), baz); +foo!(target_pointer_width = "64", quux); + +fn main() { + BAR(); + baz(); + #[cfg(target_pointer_width = "64")] + quux(); +} diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs index 606b41e89a5f5..09b56fcfcb4d5 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.rs +++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs @@ -1,12 +1,14 @@ macro_rules! mac { ($attr_item: meta) => { #[cfg($attr_item)] - //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `meta` metavariable struct S; } } mac!(an(arbitrary token stream)); +//~^ ERROR expected one of `(`, `)`, `,`, `::`, or `=`, found `token` +//~| ERROR expected one of `(`, `)`, `,`, `::`, or `=`, found `stream` +//~| ERROR [E0537] #[cfg(feature = -1)] //~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr index 1d939942fb9a9..db1b9a648999f 100644 --- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr +++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr @@ -1,5 +1,5 @@ error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `-` - --> $DIR/attr-bad-meta-4.rs:11:17 + --> $DIR/attr-bad-meta-4.rs:13:17 | LL | #[cfg(feature = -1)] | ^ @@ -10,16 +10,28 @@ LL - #[cfg(feature = -1)] LL + #[cfg(feature = 1)] | -error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `meta` metavariable - --> $DIR/attr-bad-meta-4.rs:3:15 +error: expected one of `(`, `)`, `,`, `::`, or `=`, found `token` + --> $DIR/attr-bad-meta-4.rs:8:19 | -LL | #[cfg($attr_item)] - | ^^^^^^^^^^ -... LL | mac!(an(arbitrary token stream)); - | -------------------------------- in this macro invocation + | -^^^^^ expected one of `(`, `)`, `,`, `::`, or `=` + | | + | help: missing `,` + +error: expected one of `(`, `)`, `,`, `::`, or `=`, found `stream` + --> $DIR/attr-bad-meta-4.rs:8:25 | - = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info) +LL | mac!(an(arbitrary token stream)); + | -^^^^^^ expected one of `(`, `)`, `,`, `::`, or `=` + | | + | help: missing `,` + +error[E0537]: invalid predicate `an` + --> $DIR/attr-bad-meta-4.rs:8:6 + | +LL | mac!(an(arbitrary token stream)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0537`.