diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs index 43604eb232dc..f8c1d027c604 100644 --- a/crates/mbe/src/benchmark.rs +++ b/crates/mbe/src/benchmark.rs @@ -146,7 +146,7 @@ fn invocation_fixtures( Some(MetaVarKind::Pat) => token_trees.push(make_ident("foo")), Some(MetaVarKind::Path) => token_trees.push(make_ident("foo")), Some(MetaVarKind::Literal) => token_trees.push(make_literal("1")), - Some(MetaVarKind::Expr) => token_trees.push(make_ident("foo")), + Some(MetaVarKind::Expr(_)) => token_trees.push(make_ident("foo")), Some(MetaVarKind::Lifetime) => { token_trees.push(make_punct('\'')); token_trees.push(make_ident("a")); diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs index e69d7d14e253..90f56cc31da4 100644 --- a/crates/mbe/src/expander/matcher.rs +++ b/crates/mbe/src/expander/matcher.rs @@ -69,7 +69,7 @@ use tt::{iter::TtIter, DelimSpan}; use crate::{ expander::{Binding, Bindings, ExpandResult, Fragment}, expect_fragment, - parser::{MetaVarKind, Op, RepeatKind, Separator}, + parser::{ExprKind, MetaVarKind, Op, RepeatKind, Separator}, ExpandError, ExpandErrorKind, MetaTemplate, ValueResult, }; @@ -769,23 +769,28 @@ fn match_meta_var( it.map(|it| tt::TokenTree::subtree_or_wrap(it, delim_span)).map(Fragment::Path) }); } - MetaVarKind::Expr => { - // `expr` should not match underscores, let expressions, or inline const. The latter - // two are for [backwards compatibility][0]. + MetaVarKind::Expr(expr) => { + // `expr_2021` should not match underscores, let expressions, or inline const. + // The latter two are for [backwards compatibility][0]. + // And `expr` also should not contain let expressions but may contain the other two + // since `Edition2024`. // HACK: Macro expansion should not be done using "rollback and try another alternative". // rustc [explicitly checks the next token][1]. // [0]: https://github.com/rust-lang/rust/issues/86730 // [1]: https://github.com/rust-lang/rust/blob/f0c4da499/compiler/rustc_expand/src/mbe/macro_parser.rs#L576 match input.peek_n(0) { - Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) - if it.sym == sym::underscore - || it.sym == sym::let_ - || it.sym == sym::const_ => - { - return ExpandResult::only_err(ExpandError::new( - it.span, - ExpandErrorKind::NoMatchingRule, - )) + Some(tt::TokenTree::Leaf(tt::Leaf::Ident(it))) => { + let is_err = if matches!(expr, ExprKind::Expr2021) { + it.sym == sym::underscore || it.sym == sym::let_ || it.sym == sym::const_ + } else { + it.sym == sym::let_ + }; + if is_err { + return ExpandResult::only_err(ExpandError::new( + it.span, + ExpandErrorKind::NoMatchingRule, + )); + } } _ => {} }; diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs index 286bd748cbe7..008441153559 100644 --- a/crates/mbe/src/expander/transcriber.rs +++ b/crates/mbe/src/expander/transcriber.rs @@ -97,7 +97,7 @@ impl Bindings { | MetaVarKind::Ty | MetaVarKind::Pat | MetaVarKind::PatParam - | MetaVarKind::Expr + | MetaVarKind::Expr(_) | MetaVarKind::Ident => { Fragment::Tokens(tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { sym: sym::missing.clone(), diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs index 218c04640f12..2efe318f6145 100644 --- a/crates/mbe/src/parser.rs +++ b/crates/mbe/src/parser.rs @@ -105,6 +105,16 @@ pub(crate) enum RepeatKind { ZeroOrOne, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum ExprKind { + // Matches expressions using the post-edition 2024. Was written using + // `expr` in edition 2024 or later. + Expr, + // Matches expressions using the pre-edition 2024 rules. + // Either written using `expr` in edition 2021 or earlier or.was written using `expr_2021`. + Expr2021, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub(crate) enum MetaVarKind { Path, @@ -116,7 +126,7 @@ pub(crate) enum MetaVarKind { Meta, Item, Vis, - Expr, + Expr(ExprKind), Ident, Tt, Lifetime, @@ -277,17 +287,27 @@ fn eat_fragment_kind( let kind = match ident.sym.as_str() { "path" => MetaVarKind::Path, "ty" => MetaVarKind::Ty, - "pat" => match edition(ident.span.ctx) { - Edition::Edition2015 | Edition::Edition2018 => MetaVarKind::PatParam, - Edition::Edition2021 | Edition::Edition2024 => MetaVarKind::Pat, - }, + "pat" => { + if edition(ident.span.ctx).at_least_2021() { + MetaVarKind::Pat + } else { + MetaVarKind::PatParam + } + } "pat_param" => MetaVarKind::PatParam, "stmt" => MetaVarKind::Stmt, "block" => MetaVarKind::Block, "meta" => MetaVarKind::Meta, "item" => MetaVarKind::Item, "vis" => MetaVarKind::Vis, - "expr" => MetaVarKind::Expr, + "expr" => { + if edition(ident.span.ctx).at_least_2024() { + MetaVarKind::Expr(ExprKind::Expr) + } else { + MetaVarKind::Expr(ExprKind::Expr2021) + } + } + "expr_2021" => MetaVarKind::Expr(ExprKind::Expr2021), "ident" => MetaVarKind::Ident, "tt" => MetaVarKind::Tt, "lifetime" => MetaVarKind::Lifetime, diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index 5422c9ae644b..f6f12a9f9a02 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs @@ -177,3 +177,149 @@ fn main() { }"#]], ); } + +#[test] +fn expr_2021() { + check( + Edition::Edition2024, + Edition::Edition2024, + r#" +($($e:expr),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + _, + const { 1 }, +"#, + expect![[r#" + SUBTREE $$ 1:0@0..25#0 1:0@0..25#0 + IDENT _ 1:0@5..6#0 + PUNCH ; [joint] 0:0@36..37#0 + SUBTREE () 0:0@34..35#0 0:0@34..35#0 + IDENT const 1:0@12..17#0 + SUBTREE {} 1:0@18..19#0 1:0@22..23#0 + LITERAL Integer 1 1:0@20..21#0 + PUNCH ; [alone] 0:0@39..40#0 + + _; + (const { + 1 + });"#]], + ); + check( + Edition::Edition2021, + Edition::Edition2024, + r#" +($($e:expr),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + _, +"#, + expect![[r#" + ExpandError { + inner: ( + 1:0@5..6#0, + NoMatchingRule, + ), + } + + SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 + PUNCH ; [alone] 0:0@39..40#0 + + ;"#]], + ); + check( + Edition::Edition2021, + Edition::Edition2024, + r#" +($($e:expr),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + const { 1 }, +"#, + expect![[r#" + ExpandError { + inner: ( + 1:0@5..10#0, + NoMatchingRule, + ), + } + + SUBTREE $$ 1:0@0..18#0 1:0@0..18#0 + PUNCH ; [alone] 0:0@39..40#0 + + ;"#]], + ); + check( + Edition::Edition2024, + Edition::Edition2024, + r#" +($($e:expr_2021),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + 4, + "literal", + funcall(), + future.await, + break 'foo bar, +"#, + expect![[r#" + SUBTREE $$ 1:0@0..76#0 1:0@0..76#0 + LITERAL Integer 4 1:0@5..6#0 + PUNCH ; [joint] 0:0@41..42#0 + LITERAL Str literal 1:0@12..21#0 + PUNCH ; [joint] 0:0@41..42#0 + SUBTREE () 0:0@39..40#0 0:0@39..40#0 + IDENT funcall 1:0@27..34#0 + SUBTREE () 1:0@34..35#0 1:0@35..36#0 + PUNCH ; [joint] 0:0@41..42#0 + SUBTREE () 0:0@39..40#0 0:0@39..40#0 + IDENT future 1:0@42..48#0 + PUNCH . [alone] 1:0@48..49#0 + IDENT await 1:0@49..54#0 + PUNCH ; [joint] 0:0@41..42#0 + SUBTREE () 0:0@39..40#0 0:0@39..40#0 + IDENT break 1:0@60..65#0 + PUNCH ' [joint] 1:0@66..67#0 + IDENT foo 1:0@67..70#0 + IDENT bar 1:0@71..74#0 + PUNCH ; [alone] 0:0@44..45#0 + + 4; + "literal"; + (funcall()); + (future.await); + (break 'foo bar);"#]], + ); + check( + Edition::Edition2024, + Edition::Edition2024, + r#" +($($e:expr_2021),* $(,)?) => { + $($e);* ; +}; +"#, + r#" + _, +"#, + expect![[r#" + ExpandError { + inner: ( + 1:0@5..6#0, + NoMatchingRule, + ), + } + + SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 + PUNCH ; [alone] 0:0@44..45#0 + + ;"#]], + ); +}