Skip to content

Commit 8c87132

Browse files
authoredMar 12, 2022
Rollup merge of #94833 - c410-f3r:meta-take-2, r=petrochenkov
[2/2] Implement macro meta-variable expression Final part of #93545 (comment) r? `@petrochenkov`
2 parents 27e674d + d0eca08 commit 8c87132

File tree

8 files changed

+836
-93
lines changed

8 files changed

+836
-93
lines changed
 

‎compiler/rustc_expand/src/mbe/transcribe.rs

Lines changed: 147 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use crate::base::ExtCtxt;
2-
use crate::mbe;
32
use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
4-
3+
use crate::mbe::{self, MetaVarExpr};
54
use rustc_ast::mut_visit::{self, MutVisitor};
6-
use rustc_ast::token::{self, NtTT, Token};
5+
use rustc_ast::token::{self, NtTT, Token, TokenKind};
76
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
87
use rustc_data_structures::fx::FxHashMap;
98
use rustc_data_structures::sync::Lrc;
109
use rustc_errors::{pluralize, PResult};
10+
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
1111
use rustc_span::hygiene::{LocalExpnId, Transparency};
12-
use rustc_span::symbol::MacroRulesNormalizedIdent;
12+
use rustc_span::symbol::{sym, Ident, MacroRulesNormalizedIdent};
1313
use rustc_span::Span;
1414

1515
use smallvec::{smallvec, SmallVec};
@@ -411,13 +411,150 @@ fn lockstep_iter_size(
411411
}
412412
}
413413

414+
/// Used solely by the `count` meta-variable expression, counts the outer-most repetitions at a
415+
/// given optional nested depth.
416+
///
417+
/// For example, a macro parameter of `$( { $( $foo:ident ),* } )*` called with `{ a, b } { c }`:
418+
///
419+
/// * `[ $( ${count(foo)} ),* ]` will return [2, 1] with a, b = 2 and c = 1
420+
/// * `[ $( ${count(foo, 0)} ),* ]` will be the same as `[ $( ${count(foo)} ),* ]`
421+
/// * `[ $( ${count(foo, 1)} ),* ]` will return an error because `${count(foo, 1)}` is
422+
/// declared inside a single repetition and the index `1` implies two nested repetitions.
423+
fn count_repetitions<'a>(
424+
cx: &ExtCtxt<'a>,
425+
depth_opt: Option<usize>,
426+
mut matched: &NamedMatch,
427+
repeats: &[(usize, usize)],
428+
sp: &DelimSpan,
429+
) -> PResult<'a, usize> {
430+
// Recursively count the number of matches in `matched` at given depth
431+
// (or at the top-level of `matched` if no depth is given).
432+
fn count<'a>(
433+
cx: &ExtCtxt<'a>,
434+
declared_lhs_depth: usize,
435+
depth_opt: Option<usize>,
436+
matched: &NamedMatch,
437+
sp: &DelimSpan,
438+
) -> PResult<'a, usize> {
439+
match matched {
440+
MatchedNonterminal(_) => {
441+
if declared_lhs_depth == 0 {
442+
return Err(cx.struct_span_err(
443+
sp.entire(),
444+
"`count` can not be placed inside the inner-most repetition",
445+
));
446+
}
447+
match depth_opt {
448+
None => Ok(1),
449+
Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
450+
}
451+
}
452+
MatchedSeq(ref named_matches) => {
453+
let new_declared_lhs_depth = declared_lhs_depth + 1;
454+
match depth_opt {
455+
None => named_matches
456+
.iter()
457+
.map(|elem| count(cx, new_declared_lhs_depth, None, elem, sp))
458+
.sum(),
459+
Some(0) => Ok(named_matches.len()),
460+
Some(depth) => named_matches
461+
.iter()
462+
.map(|elem| count(cx, new_declared_lhs_depth, Some(depth - 1), elem, sp))
463+
.sum(),
464+
}
465+
}
466+
}
467+
}
468+
// `repeats` records all of the nested levels at which we are currently
469+
// matching meta-variables. The meta-var-expr `count($x)` only counts
470+
// matches that occur in this "subtree" of the `NamedMatch` where we
471+
// are currently transcribing, so we need to descend to that subtree
472+
// before we start counting. `matched` contains the various levels of the
473+
// tree as we descend, and its final value is the subtree we are currently at.
474+
for &(idx, _) in repeats {
475+
if let MatchedSeq(ref ads) = matched {
476+
matched = &ads[idx];
477+
}
478+
}
479+
count(cx, 0, depth_opt, matched, sp)
480+
}
481+
482+
/// Returns a `NamedMatch` item declared on the RHS given an arbitrary [Ident]
483+
fn matched_from_ident<'ctx, 'interp, 'rslt>(
484+
cx: &ExtCtxt<'ctx>,
485+
ident: Ident,
486+
interp: &'interp FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
487+
) -> PResult<'ctx, &'rslt NamedMatch>
488+
where
489+
'interp: 'rslt,
490+
{
491+
let span = ident.span;
492+
let key = MacroRulesNormalizedIdent::new(ident);
493+
interp.get(&key).ok_or_else(|| {
494+
cx.struct_span_err(
495+
span,
496+
&format!("variable `{}` is not recognized in meta-variable expression", key),
497+
)
498+
})
499+
}
500+
501+
/// Used by meta-variable expressions when an user input is out of the actual declared bounds. For
502+
/// example, index(999999) in an repetition of only three elements.
503+
fn out_of_bounds_err<'a>(
504+
cx: &ExtCtxt<'a>,
505+
max: usize,
506+
span: Span,
507+
ty: &str,
508+
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
509+
cx.struct_span_err(span, &format!("{ty} depth must be less than {max}"))
510+
}
511+
414512
fn transcribe_metavar_expr<'a>(
415-
_cx: &ExtCtxt<'a>,
416-
_expr: mbe::MetaVarExpr,
417-
_interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
418-
_repeats: &[(usize, usize)],
419-
_result: &mut Vec<TreeAndSpacing>,
420-
_sp: &DelimSpan,
513+
cx: &ExtCtxt<'a>,
514+
expr: MetaVarExpr,
515+
interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>,
516+
repeats: &[(usize, usize)],
517+
result: &mut Vec<TreeAndSpacing>,
518+
sp: &DelimSpan,
421519
) -> PResult<'a, ()> {
520+
match expr {
521+
MetaVarExpr::Count(original_ident, depth_opt) => {
522+
let matched = matched_from_ident(cx, original_ident, interp)?;
523+
let count = count_repetitions(cx, depth_opt, matched, &repeats, sp)?;
524+
let tt = TokenTree::token(
525+
TokenKind::lit(token::Integer, sym::integer(count), None),
526+
sp.entire(),
527+
);
528+
result.push(tt.into());
529+
}
530+
MetaVarExpr::Ignore(original_ident) => {
531+
// Used to ensure that `original_ident` is present in the LHS
532+
let _ = matched_from_ident(cx, original_ident, interp)?;
533+
}
534+
MetaVarExpr::Index(depth) => match repeats.iter().nth_back(depth) {
535+
Some((index, _)) => {
536+
result.push(
537+
TokenTree::token(
538+
TokenKind::lit(token::Integer, sym::integer(*index), None),
539+
sp.entire(),
540+
)
541+
.into(),
542+
);
543+
}
544+
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
545+
},
546+
MetaVarExpr::Length(depth) => match repeats.iter().nth_back(depth) {
547+
Some((_, length)) => {
548+
result.push(
549+
TokenTree::token(
550+
TokenKind::lit(token::Integer, sym::integer(*length), None),
551+
sp.entire(),
552+
)
553+
.into(),
554+
);
555+
}
556+
None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "length")),
557+
},
558+
}
422559
Ok(())
423560
}
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
// run-pass
2+
3+
#![feature(macro_metavar_expr)]
4+
5+
fn main() {
6+
macro_rules! one_nested_count_and_length {
7+
( $( [ $( $l:literal ),* ] ),* ) => {
8+
[
9+
// outer-most repetition
10+
$(
11+
// inner-most repetition
12+
$(
13+
${ignore(l)} ${index()}, ${length()},
14+
)*
15+
${count(l)}, ${index()}, ${length()},
16+
)*
17+
${count(l)},
18+
]
19+
};
20+
}
21+
assert_eq!(
22+
one_nested_count_and_length!(["foo"], ["bar", "baz"]),
23+
[
24+
// # ["foo"]
25+
26+
// ## inner-most repetition (first iteration)
27+
//
28+
// `index` is 0 because this is the first inner-most iteration.
29+
// `length` is 1 because there is only one inner-most repetition, "foo".
30+
0, 1,
31+
32+
// ## outer-most repetition (first iteration)
33+
//
34+
// `count` is 1 because of "foo", i,e, `$l` has only one repetition,
35+
// `index` is 0 because this is the first outer-most iteration.
36+
// `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
37+
1, 0, 2,
38+
39+
// # ["bar", "baz"]
40+
41+
// ## inner-most repetition (first iteration)
42+
//
43+
// `index` is 0 because this is the first inner-most iteration
44+
// `length` is 2 because there are repetitions, "bar" and "baz"
45+
0, 2,
46+
47+
// ## inner-most repetition (second iteration)
48+
//
49+
// `index` is 1 because this is the second inner-most iteration
50+
// `length` is 2 because there are repetitions, "bar" and "baz"
51+
1, 2,
52+
53+
// ## outer-most repetition (second iteration)
54+
//
55+
// `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions,
56+
// `index` is 1 because this is the second outer-most iteration
57+
// `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
58+
2, 1, 2,
59+
60+
// # last count
61+
62+
// Because there are a total of 3 repetitions of `$l`, "foo", "bar" and "baz"
63+
3,
64+
]
65+
);
66+
67+
// Based on the above explanation, the following macros should be straightforward
68+
69+
// Grouped from the outer-most to the inner-most
70+
macro_rules! three_nested_count {
71+
( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
72+
&[
73+
$( $( $(
74+
&[
75+
${ignore(i)} ${count(i, 0)},
76+
][..],
77+
)* )* )*
78+
79+
$( $(
80+
&[
81+
${ignore(i)} ${count(i, 0)},
82+
${ignore(i)} ${count(i, 1)},
83+
][..],
84+
)* )*
85+
86+
$(
87+
&[
88+
${ignore(i)} ${count(i, 0)},
89+
${ignore(i)} ${count(i, 1)},
90+
${ignore(i)} ${count(i, 2)},
91+
][..],
92+
)*
93+
94+
&[
95+
${count(i, 0)},
96+
${count(i, 1)},
97+
${count(i, 2)},
98+
${count(i, 3)},
99+
][..]
100+
][..]
101+
}
102+
}
103+
assert_eq!(
104+
three_nested_count!(
105+
{
106+
[ (a b c) (d e f) ]
107+
[ (g h) (i j k l m) ]
108+
[ (n) ]
109+
}
110+
{
111+
[ (o) (p q) (r s) ]
112+
[ (t u v w x y z) ]
113+
}
114+
),
115+
&[
116+
// a b c
117+
&[3][..],
118+
// d e f
119+
&[3][..],
120+
// g h
121+
&[2][..],
122+
// i j k l m
123+
&[5][..],
124+
// n
125+
&[1][..],
126+
// o
127+
&[1][..],
128+
// p q
129+
&[2][..],
130+
// r s
131+
&[2][..],
132+
// t u v w x y z
133+
&[7][..],
134+
135+
// (a b c) (d e f)
136+
&[2, 6][..],
137+
// (g h) (i j k l m)
138+
&[2, 7][..],
139+
// (n)
140+
&[1, 1][..],
141+
// (o) (p q) (r s)
142+
&[3, 5][..],
143+
// (t u v w x y z)
144+
&[1, 7][..],
145+
146+
// [ (a b c) (d e f) ]
147+
// [ (g h) (i j k l m) ]
148+
// [ (n) ]
149+
&[3, 5, 14][..],
150+
// [ (o) (p q) (r s) ]
151+
// [ (t u v w x y z) ]
152+
&[2, 4, 12][..],
153+
154+
// {
155+
// [ (a b c) (d e f) ]
156+
// [ (g h) (i j k l m) ]
157+
// [ (n) ]
158+
// }
159+
// {
160+
// [ (o) (p q) (r s) ]
161+
// [ (t u v w x y z) ]
162+
// }
163+
&[2, 5, 9, 26][..]
164+
][..]
165+
);
166+
167+
// Grouped from the outer-most to the inner-most
168+
macro_rules! three_nested_length {
169+
( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
170+
&[
171+
$( $( $( $(
172+
&[
173+
${ignore(i)} ${length(3)},
174+
${ignore(i)} ${length(2)},
175+
${ignore(i)} ${length(1)},
176+
${ignore(i)} ${length(0)},
177+
][..],
178+
)* )* )* )*
179+
180+
$( $( $(
181+
&[
182+
${ignore(i)} ${length(2)},
183+
${ignore(i)} ${length(1)},
184+
${ignore(i)} ${length(0)},
185+
][..],
186+
)* )* )*
187+
188+
$( $(
189+
&[
190+
${ignore(i)} ${length(1)},
191+
${ignore(i)} ${length(0)},
192+
][..],
193+
)* )*
194+
195+
$(
196+
&[
197+
${ignore(i)} ${length(0)},
198+
][..],
199+
)*
200+
][..]
201+
}
202+
}
203+
assert_eq!(
204+
three_nested_length!(
205+
{
206+
[ (a b c) (d e f) ]
207+
[ (g h) (i j k l m) ]
208+
[ (n) ]
209+
}
210+
{
211+
[ (o) (p q) (r s) ]
212+
[ (t u v w x y z) ]
213+
}
214+
),
215+
&[
216+
// a b c
217+
&[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
218+
// d e f
219+
&[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
220+
// g h
221+
&[2, 3, 2, 2][..], &[2, 3, 2, 2][..],
222+
// i j k l m
223+
&[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..],
224+
&[2, 3, 2, 5][..],
225+
// n
226+
&[2, 3, 1, 1][..],
227+
// o
228+
&[2, 2, 3, 1][..],
229+
// p q
230+
&[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
231+
// r s
232+
&[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
233+
// t u v w x y z
234+
&[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
235+
&[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
236+
237+
// (a b c) (d e f)
238+
&[2, 3, 2][..], &[2, 3, 2][..],
239+
// (g h) (i j k l m)
240+
&[2, 3, 2][..], &[2, 3, 2][..],
241+
// (n)
242+
&[2, 3, 1][..],
243+
// (o) (p q) (r s)
244+
&[2, 2, 3][..], &[2, 2, 3][..], &[2, 2, 3][..],
245+
// (t u v w x y z)
246+
&[2, 2, 1][..],
247+
248+
// [ (a b c) (d e f) ]
249+
// [ (g h) (i j k l m) ]
250+
// [ (n) ]
251+
&[2, 3][..], &[2, 3][..], &[2, 3,][..],
252+
// [ (o) (p q) (r s) ]
253+
// [ (t u v w x y z) ]
254+
&[2, 2][..], &[2, 2][..],
255+
256+
// {
257+
// [ (a b c) (d e f) ]
258+
// [ (g h) (i j k l m) ]
259+
// [ (n) ]
260+
// }
261+
// {
262+
// [ (o) (p q) (r s) ]
263+
// [ (t u v w x y z) ]
264+
// }
265+
&[2][..], &[2][..]
266+
][..]
267+
);
268+
269+
// It is possible to say, to some degree, that count is an "amalgamation" of length (see
270+
// each length line result and compare them with the count results)
271+
}

‎src/test/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs

Lines changed: 140 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,147 @@
22

33
#![feature(macro_metavar_expr)]
44

5-
macro_rules! ignore {
6-
( $( $i:ident ),* ) => {{
7-
let array: [i32; 0] = [$( ${ignore(i)} )*];
8-
array
9-
}};
5+
/// Count the number of idents in a macro repetition.
6+
macro_rules! count_idents {
7+
( $( $i:ident ),* ) => {
8+
${count(i)}
9+
};
1010
}
1111

12+
/// Count the number of idents in a 2-dimensional macro repetition.
13+
macro_rules! count_idents_2 {
14+
( $( [ $( $i:ident ),* ] ),* ) => {
15+
${count(i)}
16+
};
17+
}
18+
19+
/// Mostly counts the number of OUTER-MOST repetitions
20+
macro_rules! count_depth_limits {
21+
( $( { $( [ $( $outer:ident : ( $( $inner:ident )* ) )* ] )* } )* ) => {
22+
(
23+
(
24+
${count(inner)},
25+
${count(inner, 0)},
26+
${count(inner, 1)},
27+
${count(inner, 2)},
28+
${count(inner, 3)},
29+
),
30+
(
31+
${count(outer)},
32+
${count(outer, 0)},
33+
${count(outer, 1)},
34+
${count(outer, 2)},
35+
),
36+
)
37+
};
38+
}
39+
40+
/// Produce (index, length) pairs for literals in a macro repetition.
41+
/// The literal is not included in the output, so this macro uses the
42+
/// `ignore` meta-variable expression to create a non-expanding
43+
/// repetition binding.
44+
macro_rules! enumerate_literals {
45+
( $( ($l:stmt) ),* ) => {
46+
[$( ${ignore(l)} (${index()}, ${length()}) ),*]
47+
};
48+
}
49+
50+
/// Produce index and length tuples for literals in a 2-dimensional
51+
/// macro repetition.
52+
macro_rules! enumerate_literals_2 {
53+
( $( [ $( ($l:literal) ),* ] ),* ) => {
54+
[
55+
$(
56+
$(
57+
(
58+
${index(1)},
59+
${length(1)},
60+
${index(0)},
61+
${length(0)},
62+
$l
63+
),
64+
)*
65+
)*
66+
]
67+
};
68+
}
69+
70+
/// Generate macros that count idents and then add a constant number
71+
/// to the count.
72+
///
73+
/// This macro uses dollar escaping to make it unambiguous as to which
74+
/// macro the repetition belongs to.
75+
macro_rules! make_count_adders {
76+
( $( $i:ident, $b:literal );* ) => {
77+
$(
78+
macro_rules! $i {
79+
( $$( $$j:ident ),* ) => {
80+
$b + $${count(j)}
81+
};
82+
}
83+
)*
84+
};
85+
}
86+
87+
make_count_adders! { plus_one, 1; plus_five, 5 }
88+
89+
/// Generate a macro that allows selection of a particular literal
90+
/// from a sequence of inputs by their identifier.
91+
///
92+
/// This macro uses dollar escaping to make it unambiguous as to which
93+
/// macro the repetition belongs to, and to allow expansion of an
94+
/// identifier the name of which is not known in the definition
95+
/// of `make_picker`.
96+
macro_rules! make_picker {
97+
( $m:ident => $( $i:ident ),* ; $p:ident ) => {
98+
macro_rules! $m {
99+
( $( $$ $i:literal ),* ) => {
100+
$$ $p
101+
};
102+
}
103+
};
104+
}
105+
106+
make_picker!(first => a, b; a);
107+
108+
make_picker!(second => a, b; b);
109+
12110
fn main() {
13-
assert_eq!(ignore!(a, b, c), []);
111+
assert_eq!(count_idents!(a, b, c), 3);
112+
assert_eq!(count_idents_2!([a, b, c], [d, e], [f]), 6);
113+
assert_eq!(
114+
count_depth_limits! {
115+
{
116+
[ A: (a b c) D: (d e f) ]
117+
[ G: (g h) I: (i j k l m) ]
118+
[ N: (n) ]
119+
}
120+
{
121+
[ O: (o) P: (p q) R: (r s) ]
122+
[ T: (t u v w x y z) ]
123+
}
124+
},
125+
((26, 2, 5, 9, 26), (9, 2, 5, 9))
126+
);
127+
assert_eq!(enumerate_literals![("foo"), ("bar")], [(0, 2), (1, 2)]);
128+
assert_eq!(
129+
enumerate_literals_2![
130+
[("foo"), ("bar"), ("baz")],
131+
[("qux"), ("quux"), ("quuz"), ("xyzzy")]
132+
],
133+
[
134+
(0, 2, 0, 3, "foo"),
135+
(0, 2, 1, 3, "bar"),
136+
(0, 2, 2, 3, "baz"),
137+
138+
(1, 2, 0, 4, "qux"),
139+
(1, 2, 1, 4, "quux"),
140+
(1, 2, 2, 4, "quuz"),
141+
(1, 2, 3, 4, "xyzzy"),
142+
]
143+
);
144+
assert_eq!(plus_one!(a, b, c), 4);
145+
assert_eq!(plus_five!(a, b), 7);
146+
assert_eq!(first!(1, 2), 1);
147+
assert_eq!(second!(1, 2), 2);
14148
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
// run-pass
2+
3+
#![feature(macro_metavar_expr)]
4+
5+
#[derive(Debug)]
6+
struct Example<'a> {
7+
_indexes: &'a [(u32, u32)],
8+
_counts: &'a [u32],
9+
_nested: Vec<Example<'a>>,
10+
}
11+
12+
macro_rules! example {
13+
( $( [ $( ( $( $x:ident )* ) )* ] )* ) => {
14+
Example {
15+
_indexes: &[],
16+
_counts: &[${count(x, 0)}, ${count(x, 1)}, ${count(x, 2)}],
17+
_nested: vec![
18+
$(
19+
Example {
20+
_indexes: &[(${index()}, ${length()})],
21+
_counts: &[${count(x, 0)}, ${count(x, 1)}],
22+
_nested: vec![
23+
$(
24+
Example {
25+
_indexes: &[(${index(1)}, ${length(1)}), (${index()}, ${length()})],
26+
_counts: &[${count(x)}],
27+
_nested: vec![
28+
$(
29+
Example {
30+
_indexes: &[
31+
(${index(2)}, ${length(2)}),
32+
(${index(1)}, ${length(1)}),
33+
(${index()}, ${length()})
34+
],
35+
_counts: &[],
36+
_nested: vec![],
37+
${ignore(x)}
38+
}
39+
),*
40+
]
41+
}
42+
),*
43+
]
44+
}
45+
),*
46+
]
47+
}
48+
};
49+
}
50+
51+
static EXPECTED: &str = concat!(
52+
"Example { _indexes: [], _counts: [2, 4, 13], _nested: [",
53+
concat!(
54+
"Example { _indexes: [(0, 2)], _counts: [3, 10], _nested: [",
55+
concat!(
56+
"Example { _indexes: [(0, 2), (0, 3)], _counts: [4], _nested: [",
57+
concat!(
58+
"Example { _indexes: [(0, 2), (0, 3), (0, 4)], _counts: [], _nested: [] }, ",
59+
"Example { _indexes: [(0, 2), (0, 3), (1, 4)], _counts: [], _nested: [] }, ",
60+
"Example { _indexes: [(0, 2), (0, 3), (2, 4)], _counts: [], _nested: [] }, ",
61+
"Example { _indexes: [(0, 2), (0, 3), (3, 4)], _counts: [], _nested: [] }",
62+
),
63+
"] }, ",
64+
"Example { _indexes: [(0, 2), (1, 3)], _counts: [4], _nested: [",
65+
concat!(
66+
"Example { _indexes: [(0, 2), (1, 3), (0, 4)], _counts: [], _nested: [] }, ",
67+
"Example { _indexes: [(0, 2), (1, 3), (1, 4)], _counts: [], _nested: [] }, ",
68+
"Example { _indexes: [(0, 2), (1, 3), (2, 4)], _counts: [], _nested: [] }, ",
69+
"Example { _indexes: [(0, 2), (1, 3), (3, 4)], _counts: [], _nested: [] }",
70+
),
71+
"] }, ",
72+
"Example { _indexes: [(0, 2), (2, 3)], _counts: [2], _nested: [",
73+
concat!(
74+
"Example { _indexes: [(0, 2), (2, 3), (0, 2)], _counts: [], _nested: [] }, ",
75+
"Example { _indexes: [(0, 2), (2, 3), (1, 2)], _counts: [], _nested: [] }",
76+
),
77+
"] }",
78+
),
79+
"] }, ",
80+
"Example { _indexes: [(1, 2)], _counts: [1, 3], _nested: [",
81+
concat!(
82+
"Example { _indexes: [(1, 2), (0, 1)], _counts: [3], _nested: [",
83+
concat!(
84+
"Example { _indexes: [(1, 2), (0, 1), (0, 3)], _counts: [], _nested: [] }, ",
85+
"Example { _indexes: [(1, 2), (0, 1), (1, 3)], _counts: [], _nested: [] }, ",
86+
"Example { _indexes: [(1, 2), (0, 1), (2, 3)], _counts: [], _nested: [] }",
87+
),
88+
"] }",
89+
),
90+
"] }",
91+
),
92+
"] }",
93+
);
94+
95+
fn main() {
96+
let e = example! {
97+
[ ( A B C D ) ( E F G H ) ( I J ) ]
98+
[ ( K L M ) ]
99+
};
100+
let debug = format!("{:?}", e);
101+
assert_eq!(debug, EXPECTED);
102+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#![feature(macro_metavar_expr)]
2+
3+
macro_rules! a {
4+
( $( { $( [ $( ( $( $foo:ident )* ) )* ] )* } )* ) => {
5+
(
6+
${count(foo, 0)},
7+
${count(foo, 10)},
8+
//~^ ERROR count depth must be less than 4
9+
)
10+
};
11+
}
12+
13+
macro_rules! b {
14+
( $( { $( [ $( $foo:ident )* ] )* } )* ) => {
15+
(
16+
$( $( $(
17+
${ignore(foo)}
18+
${index(0)},
19+
${index(10)},
20+
//~^ ERROR index depth must be less than 3
21+
)* )* )*
22+
)
23+
};
24+
}
25+
26+
macro_rules! c {
27+
( $( { $( $foo:ident )* } )* ) => {
28+
(
29+
$( $(
30+
${ignore(foo)}
31+
${length(0)}
32+
${length(10)}
33+
//~^ ERROR length depth must be less than 2
34+
)* )*
35+
)
36+
};
37+
}
38+
39+
40+
fn main() {
41+
a!( { [ (a) ] [ (b c) ] } );
42+
b!( { [ a b ] } );
43+
c!( { a } );
44+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: count depth must be less than 4
2+
--> $DIR/out-of-bounds-arguments.rs:7:14
3+
|
4+
LL | ${count(foo, 10)},
5+
| ^^^^^^^^^^^^^^^^
6+
7+
error: index depth must be less than 3
8+
--> $DIR/out-of-bounds-arguments.rs:19:18
9+
|
10+
LL | ${index(10)},
11+
| ^^^^^^^^^^^
12+
13+
error: length depth must be less than 2
14+
--> $DIR/out-of-bounds-arguments.rs:32:18
15+
|
16+
LL | ${length(10)}
17+
| ^^^^^^^^^^^^
18+
19+
error: aborting due to 3 previous errors
20+

‎src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ macro_rules! curly__no_rhs_dollar__round {
1010

1111
macro_rules! curly__no_rhs_dollar__no_round {
1212
( $i:ident ) => { ${ count(i) } };
13+
//~^ ERROR `count` can not be placed inside the inner-most repetition
1314
}
1415

1516
macro_rules! curly__rhs_dollar__round {
@@ -121,6 +122,20 @@ macro_rules! open_brackets_without_tokens {
121122
//~| ERROR expected identifier
122123
}
123124

125+
macro_rules! unknown_count_ident {
126+
( $( $i:ident )* ) => {
127+
${count(foo)}
128+
//~^ ERROR variable `foo` is not recognized in meta-variable expression
129+
};
130+
}
131+
132+
macro_rules! unknown_ignore_ident {
133+
( $( $i:ident )* ) => {
134+
${ignore(bar)}
135+
//~^ ERROR variable `bar` is not recognized in meta-variable expression
136+
};
137+
}
138+
124139
macro_rules! unknown_metavar {
125140
( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
126141
//~^ ERROR unrecognized meta-variable expression
@@ -139,10 +154,12 @@ fn main() {
139154
//~^ ERROR cannot find value `a` in this scope
140155

141156
extra_garbage_after_metavar!(a);
142-
unknown_metavar!(a);
143-
metavar_without_parens!(a);
144-
metavar_token_without_ident!(a);
145157
metavar_depth_is_not_literal!(a);
158+
metavar_token_without_ident!(a);
146159
metavar_with_literal_suffix!(a);
147-
open_brackets_without_tokens!(a)
160+
metavar_without_parens!(a);
161+
open_brackets_without_tokens!(a);
162+
unknown_count_ident!(a);
163+
unknown_ignore_ident!(a);
164+
unknown_metavar!(a);
148165
}

‎src/test/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr

Lines changed: 91 additions & 73 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.