Skip to content

Commit 34e0f13

Browse files
committed
[macro_metavar_expr_concat] Add support for nested repetitions
1 parent ac00fe8 commit 34e0f13

File tree

4 files changed

+170
-22
lines changed

4 files changed

+170
-22
lines changed

compiler/rustc_expand/src/mbe/transcribe.rs

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -691,30 +691,67 @@ fn transcribe_metavar_expr<'a>(
691691
MetaVarExpr::Concat(ref elements) => {
692692
let mut concatenated = String::new();
693693
for element in elements.into_iter() {
694-
let symbol = match element {
695-
MetaVarExprConcatElem::Ident(elem) => elem.name,
696-
MetaVarExprConcatElem::Literal(elem) => *elem,
694+
match element {
695+
MetaVarExprConcatElem::Ident(elem) => {
696+
concatenated.push_str(elem.name.as_str());
697+
}
698+
MetaVarExprConcatElem::Literal(elem) => {
699+
concatenated.push_str(elem.as_str());
700+
}
697701
MetaVarExprConcatElem::Var(ident) => {
702+
fn manage_nested<'a>(
703+
concatenated: &mut String,
704+
dcx: DiagCtxtHandle<'a>,
705+
depth: usize,
706+
ident_span: Span,
707+
named_matches: &[NamedMatch],
708+
repeats: &[(usize, usize)],
709+
sp: &DelimSpan,
710+
) -> PResult<'a, ()> {
711+
let Some((curr_idx, _)) = repeats.get(depth) else {
712+
return Err(dcx.struct_span_err(sp.entire(), "invalid syntax"));
713+
};
714+
match &named_matches[*curr_idx] {
715+
MatchedSeq(named_matches) => {
716+
manage_nested(
717+
concatenated,
718+
dcx,
719+
depth + 1,
720+
ident_span,
721+
&named_matches,
722+
repeats,
723+
sp,
724+
)?;
725+
}
726+
MatchedSingle(pnr) => {
727+
concatenated.push_str(
728+
extract_symbol_from_pnr(dcx, pnr, ident_span)?.as_str(),
729+
);
730+
}
731+
}
732+
Ok(())
733+
}
734+
698735
match matched_from_ident(dcx, *ident, interp)? {
699736
NamedMatch::MatchedSeq(named_matches) => {
700-
let Some((curr_idx, _)) = repeats.last() else {
701-
return Err(dcx.struct_span_err(sp.entire(), "invalid syntax"));
702-
};
703-
match &named_matches[*curr_idx] {
704-
// FIXME(c410-f3r) Nested repetitions are unimplemented
705-
MatchedSeq(_) => unimplemented!(),
706-
MatchedSingle(pnr) => {
707-
extract_symbol_from_pnr(dcx, pnr, ident.span)?
708-
}
709-
}
737+
manage_nested(
738+
&mut concatenated,
739+
dcx,
740+
0,
741+
ident.span,
742+
&named_matches,
743+
repeats,
744+
sp,
745+
)?;
710746
}
711747
NamedMatch::MatchedSingle(pnr) => {
712-
extract_symbol_from_pnr(dcx, pnr, ident.span)?
748+
concatenated.push_str(
749+
extract_symbol_from_pnr(dcx, pnr, ident.span)?.as_str(),
750+
);
713751
}
714752
}
715753
}
716-
};
717-
concatenated.push_str(symbol.as_str());
754+
}
718755
}
719756
let symbol = nfc_normalize(&concatenated);
720757
let concatenated_span = visited_span();
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//@ run-pass
2+
3+
#![feature(macro_metavar_expr_concat)]
4+
5+
macro_rules! two_layers {
6+
(
7+
$(
8+
[
9+
$outer:ident,
10+
(
11+
$(
12+
$inner:literal
13+
),*
14+
)
15+
]
16+
),*
17+
) => {
18+
$(
19+
$(
20+
const ${concat($outer, $inner)}: i32 = 1;
21+
)*
22+
)*
23+
};
24+
}
25+
26+
macro_rules! three_layers {
27+
(
28+
$(
29+
{
30+
$outer:tt,
31+
$(
32+
[
33+
$middle:ident,
34+
(
35+
$(
36+
$inner:literal
37+
),*
38+
)
39+
]
40+
),*
41+
}
42+
),*
43+
)
44+
=> {
45+
$(
46+
$(
47+
$(
48+
const ${concat($outer, $middle, $inner)}: i32 = 1;
49+
)*
50+
)*
51+
)*
52+
};
53+
}
54+
55+
fn main() {
56+
two_layers!(
57+
[A_, ("FOO")],
58+
[B_, ("BAR", "BAZ")]
59+
);
60+
assert_eq!(A_FOO, 1);
61+
assert_eq!(B_BAR, 1);
62+
assert_eq!(B_BAZ, 1);
63+
64+
three_layers!(
65+
{
66+
A_,
67+
[B_, ("FOO")],
68+
[C_, ("BAR", "BAZ")]
69+
},
70+
{
71+
D_,
72+
[E_, ("FOO")],
73+
[F_, ("BAR", "BAZ")]
74+
}
75+
);
76+
assert_eq!(A_B_FOO, 1);
77+
assert_eq!(A_C_BAR, 1);
78+
assert_eq!(A_C_BAZ, 1);
79+
assert_eq!(D_E_FOO, 1);
80+
assert_eq!(D_F_BAR, 1);
81+
assert_eq!(D_F_BAZ, 1);
82+
}

tests/ui/macros/macro-metavar-expr-concat/repetitions.rs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#![feature(macro_metavar_expr)]
12
#![feature(macro_metavar_expr_concat)]
23

34
macro_rules! one_rep {
@@ -8,6 +9,24 @@ macro_rules! one_rep {
89
};
910
}
1011

12+
macro_rules! issue_127723 {
13+
($($a:ident, $c:ident;)*) => {
14+
$(
15+
const ${concat($a, B, $c, D)}: i32 = 3;
16+
)*
17+
};
18+
}
19+
20+
macro_rules! issue_127723_ignore {
21+
($($a:ident, $c:ident;)*) => {
22+
$(
23+
${ignore($a)}
24+
${ignore($c)}
25+
const ${concat($a, B, $c, D)}: i32 = 3;
26+
)*
27+
};
28+
}
29+
1130
macro_rules! issue_128346 {
1231
( $($a:ident)* ) => {
1332
A(
@@ -19,7 +38,7 @@ macro_rules! issue_128346 {
1938

2039
macro_rules! issue_131393 {
2140
($t:ident $($en:ident)?) => {
22-
read::<${concat($t, $en)}>()
41+
read::<${concat($t, $en)}>();
2342
//~^ ERROR invalid syntax
2443
//~| ERROR invalid syntax
2544
}
@@ -30,6 +49,16 @@ fn main() {
3049
assert_eq!(AZ, 3);
3150
assert_eq!(BZ, 3);
3251
assert_eq!(CZ, 3);
52+
issue_127723! {
53+
A, D;
54+
B, E;
55+
C, F;
56+
}
57+
issue_127723_ignore! {
58+
N, O;
59+
P, Q;
60+
R, S;
61+
}
3362
issue_128346!(A B C);
3463
issue_131393!(u8);
3564
issue_131393!(u16 le);

tests/ui/macros/macro-metavar-expr-concat/repetitions.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
error: invalid syntax
2-
--> $DIR/repetitions.rs:14:20
2+
--> $DIR/repetitions.rs:33:20
33
|
44
LL | const ${concat($a, Z)}: i32 = 3;
55
| ^^^^^^^^^^^^^^^
66

77
error: invalid syntax
8-
--> $DIR/repetitions.rs:22:17
8+
--> $DIR/repetitions.rs:41:17
99
|
10-
LL | read::<${concat($t, $en)}>()
10+
LL | read::<${concat($t, $en)}>();
1111
| ^^^^^^^^^^^^^^^^^
1212

1313
error: invalid syntax
14-
--> $DIR/repetitions.rs:22:17
14+
--> $DIR/repetitions.rs:41:17
1515
|
16-
LL | read::<${concat($t, $en)}>()
16+
LL | read::<${concat($t, $en)}>();
1717
| ^^^^^^^^^^^^^^^^^
1818
|
1919
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

0 commit comments

Comments
 (0)