From 34e0f13554317c653c7cd56fcf5a78e30164a4ed Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 4 Jan 2025 18:43:08 -0300 Subject: [PATCH] [macro_metavar_expr_concat] Add support for nested repetitions --- compiler/rustc_expand/src/mbe/transcribe.rs | 69 ++++++++++++---- .../nested-repetitions.rs | 82 +++++++++++++++++++ .../macro-metavar-expr-concat/repetitions.rs | 31 ++++++- .../repetitions.stderr | 10 +-- 4 files changed, 170 insertions(+), 22 deletions(-) create mode 100644 tests/ui/macros/macro-metavar-expr-concat/nested-repetitions.rs diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index ef209c2bce123..c59f66bb9611b 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -691,30 +691,67 @@ fn transcribe_metavar_expr<'a>( MetaVarExpr::Concat(ref elements) => { let mut concatenated = String::new(); for element in elements.into_iter() { - let symbol = match element { - MetaVarExprConcatElem::Ident(elem) => elem.name, - MetaVarExprConcatElem::Literal(elem) => *elem, + match element { + MetaVarExprConcatElem::Ident(elem) => { + concatenated.push_str(elem.name.as_str()); + } + MetaVarExprConcatElem::Literal(elem) => { + concatenated.push_str(elem.as_str()); + } MetaVarExprConcatElem::Var(ident) => { + fn manage_nested<'a>( + concatenated: &mut String, + dcx: DiagCtxtHandle<'a>, + depth: usize, + ident_span: Span, + named_matches: &[NamedMatch], + repeats: &[(usize, usize)], + sp: &DelimSpan, + ) -> PResult<'a, ()> { + let Some((curr_idx, _)) = repeats.get(depth) else { + return Err(dcx.struct_span_err(sp.entire(), "invalid syntax")); + }; + match &named_matches[*curr_idx] { + MatchedSeq(named_matches) => { + manage_nested( + concatenated, + dcx, + depth + 1, + ident_span, + &named_matches, + repeats, + sp, + )?; + } + MatchedSingle(pnr) => { + concatenated.push_str( + extract_symbol_from_pnr(dcx, pnr, ident_span)?.as_str(), + ); + } + } + Ok(()) + } + match matched_from_ident(dcx, *ident, interp)? { NamedMatch::MatchedSeq(named_matches) => { - let Some((curr_idx, _)) = repeats.last() else { - return Err(dcx.struct_span_err(sp.entire(), "invalid syntax")); - }; - match &named_matches[*curr_idx] { - // FIXME(c410-f3r) Nested repetitions are unimplemented - MatchedSeq(_) => unimplemented!(), - MatchedSingle(pnr) => { - extract_symbol_from_pnr(dcx, pnr, ident.span)? - } - } + manage_nested( + &mut concatenated, + dcx, + 0, + ident.span, + &named_matches, + repeats, + sp, + )?; } NamedMatch::MatchedSingle(pnr) => { - extract_symbol_from_pnr(dcx, pnr, ident.span)? + concatenated.push_str( + extract_symbol_from_pnr(dcx, pnr, ident.span)?.as_str(), + ); } } } - }; - concatenated.push_str(symbol.as_str()); + } } let symbol = nfc_normalize(&concatenated); let concatenated_span = visited_span(); diff --git a/tests/ui/macros/macro-metavar-expr-concat/nested-repetitions.rs b/tests/ui/macros/macro-metavar-expr-concat/nested-repetitions.rs new file mode 100644 index 0000000000000..970cf546337a7 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/nested-repetitions.rs @@ -0,0 +1,82 @@ +//@ run-pass + +#![feature(macro_metavar_expr_concat)] + +macro_rules! two_layers { + ( + $( + [ + $outer:ident, + ( + $( + $inner:literal + ),* + ) + ] + ),* + ) => { + $( + $( + const ${concat($outer, $inner)}: i32 = 1; + )* + )* + }; +} + +macro_rules! three_layers { + ( + $( + { + $outer:tt, + $( + [ + $middle:ident, + ( + $( + $inner:literal + ),* + ) + ] + ),* + } + ),* + ) + => { + $( + $( + $( + const ${concat($outer, $middle, $inner)}: i32 = 1; + )* + )* + )* + }; +} + +fn main() { + two_layers!( + [A_, ("FOO")], + [B_, ("BAR", "BAZ")] + ); + assert_eq!(A_FOO, 1); + assert_eq!(B_BAR, 1); + assert_eq!(B_BAZ, 1); + + three_layers!( + { + A_, + [B_, ("FOO")], + [C_, ("BAR", "BAZ")] + }, + { + D_, + [E_, ("FOO")], + [F_, ("BAR", "BAZ")] + } + ); + assert_eq!(A_B_FOO, 1); + assert_eq!(A_C_BAR, 1); + assert_eq!(A_C_BAZ, 1); + assert_eq!(D_E_FOO, 1); + assert_eq!(D_F_BAR, 1); + assert_eq!(D_F_BAZ, 1); +} diff --git a/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs index 52a7d5cd8a7e6..a2e654dbe646a 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs +++ b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs @@ -1,3 +1,4 @@ +#![feature(macro_metavar_expr)] #![feature(macro_metavar_expr_concat)] macro_rules! one_rep { @@ -8,6 +9,24 @@ macro_rules! one_rep { }; } +macro_rules! issue_127723 { + ($($a:ident, $c:ident;)*) => { + $( + const ${concat($a, B, $c, D)}: i32 = 3; + )* + }; +} + +macro_rules! issue_127723_ignore { + ($($a:ident, $c:ident;)*) => { + $( + ${ignore($a)} + ${ignore($c)} + const ${concat($a, B, $c, D)}: i32 = 3; + )* + }; +} + macro_rules! issue_128346 { ( $($a:ident)* ) => { A( @@ -19,7 +38,7 @@ macro_rules! issue_128346 { macro_rules! issue_131393 { ($t:ident $($en:ident)?) => { - read::<${concat($t, $en)}>() + read::<${concat($t, $en)}>(); //~^ ERROR invalid syntax //~| ERROR invalid syntax } @@ -30,6 +49,16 @@ fn main() { assert_eq!(AZ, 3); assert_eq!(BZ, 3); assert_eq!(CZ, 3); + issue_127723! { + A, D; + B, E; + C, F; + } + issue_127723_ignore! { + N, O; + P, Q; + R, S; + } issue_128346!(A B C); issue_131393!(u8); issue_131393!(u16 le); diff --git a/tests/ui/macros/macro-metavar-expr-concat/repetitions.stderr b/tests/ui/macros/macro-metavar-expr-concat/repetitions.stderr index c3006c4be5df2..d9c20fa9ebc1d 100644 --- a/tests/ui/macros/macro-metavar-expr-concat/repetitions.stderr +++ b/tests/ui/macros/macro-metavar-expr-concat/repetitions.stderr @@ -1,19 +1,19 @@ error: invalid syntax - --> $DIR/repetitions.rs:14:20 + --> $DIR/repetitions.rs:33:20 | LL | const ${concat($a, Z)}: i32 = 3; | ^^^^^^^^^^^^^^^ error: invalid syntax - --> $DIR/repetitions.rs:22:17 + --> $DIR/repetitions.rs:41:17 | -LL | read::<${concat($t, $en)}>() +LL | read::<${concat($t, $en)}>(); | ^^^^^^^^^^^^^^^^^ error: invalid syntax - --> $DIR/repetitions.rs:22:17 + --> $DIR/repetitions.rs:41:17 | -LL | read::<${concat($t, $en)}>() +LL | read::<${concat($t, $en)}>(); | ^^^^^^^^^^^^^^^^^ | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`