Skip to content

Commit 1c17332

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

File tree

4 files changed

+161
-22
lines changed

4 files changed

+161
-22
lines changed

compiler/rustc_expand/src/mbe/transcribe.rs

+52-16
Original file line numberDiff line numberDiff line change
@@ -691,30 +691,66 @@ 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+
let bbb = extract_symbol_from_pnr(dcx, pnr, ident_span)?;
728+
concatenated.push_str(bbb.as_str());
729+
}
730+
}
731+
Ok(())
732+
}
733+
698734
match matched_from_ident(dcx, *ident, interp)? {
699735
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-
}
736+
manage_nested(
737+
&mut concatenated,
738+
dcx,
739+
0,
740+
ident.span,
741+
&named_matches,
742+
repeats,
743+
sp,
744+
)?;
710745
}
711746
NamedMatch::MatchedSingle(pnr) => {
712-
extract_symbol_from_pnr(dcx, pnr, ident.span)?
747+
concatenated.push_str(
748+
extract_symbol_from_pnr(dcx, pnr, ident.span)?.as_str(),
749+
);
713750
}
714751
}
715752
}
716-
};
717-
concatenated.push_str(symbol.as_str());
753+
}
718754
}
719755
let symbol = nfc_normalize(&concatenated);
720756
let concatenated_span = visited_span();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
assert_eq!(A_B_FOO, 1);
72+
assert_eq!(A_C_BAR, 1);
73+
assert_eq!(A_C_BAZ, 1);
74+
}

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

+30-1
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

+5-5
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)