summaryrefslogtreecommitdiffstats
path: root/tests/ui/macros/rfc-3086-metavar-expr
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/macros/rfc-3086-metavar-expr')
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs271
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs28
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs148
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs102
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs43
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr20
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs44
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr93
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs165
-rw-r--r--tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr385
10 files changed, 1299 insertions, 0 deletions
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
new file mode 100644
index 000000000..ab8d95a41
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
@@ -0,0 +1,271 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+fn main() {
+ macro_rules! one_nested_count_and_length {
+ ( $( [ $( $l:literal ),* ] ),* ) => {
+ [
+ // outer-most repetition
+ $(
+ // inner-most repetition
+ $(
+ ${ignore(l)} ${index()}, ${length()},
+ )*
+ ${count(l)}, ${index()}, ${length()},
+ )*
+ ${count(l)},
+ ]
+ };
+ }
+ assert_eq!(
+ one_nested_count_and_length!(["foo"], ["bar", "baz"]),
+ [
+ // # ["foo"]
+
+ // ## inner-most repetition (first iteration)
+ //
+ // `index` is 0 because this is the first inner-most iteration.
+ // `length` is 1 because there is only one inner-most repetition, "foo".
+ 0, 1,
+
+ // ## outer-most repetition (first iteration)
+ //
+ // `count` is 1 because of "foo", i,e, `$l` has only one repetition,
+ // `index` is 0 because this is the first outer-most iteration.
+ // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+ 1, 0, 2,
+
+ // # ["bar", "baz"]
+
+ // ## inner-most repetition (first iteration)
+ //
+ // `index` is 0 because this is the first inner-most iteration
+ // `length` is 2 because there are repetitions, "bar" and "baz"
+ 0, 2,
+
+ // ## inner-most repetition (second iteration)
+ //
+ // `index` is 1 because this is the second inner-most iteration
+ // `length` is 2 because there are repetitions, "bar" and "baz"
+ 1, 2,
+
+ // ## outer-most repetition (second iteration)
+ //
+ // `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions,
+ // `index` is 1 because this is the second outer-most iteration
+ // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+ 2, 1, 2,
+
+ // # last count
+
+ // Because there are a total of 3 repetitions of `$l`, "foo", "bar" and "baz"
+ 3,
+ ]
+ );
+
+ // Based on the above explanation, the following macros should be straightforward
+
+ // Grouped from the outer-most to the inner-most
+ macro_rules! three_nested_count {
+ ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
+ &[
+ $( $( $(
+ &[
+ ${ignore(i)} ${count(i, 0)},
+ ][..],
+ )* )* )*
+
+ $( $(
+ &[
+ ${ignore(i)} ${count(i, 0)},
+ ${ignore(i)} ${count(i, 1)},
+ ][..],
+ )* )*
+
+ $(
+ &[
+ ${ignore(i)} ${count(i, 0)},
+ ${ignore(i)} ${count(i, 1)},
+ ${ignore(i)} ${count(i, 2)},
+ ][..],
+ )*
+
+ &[
+ ${count(i, 0)},
+ ${count(i, 1)},
+ ${count(i, 2)},
+ ${count(i, 3)},
+ ][..]
+ ][..]
+ }
+ }
+ assert_eq!(
+ three_nested_count!(
+ {
+ [ (a b c) (d e f) ]
+ [ (g h) (i j k l m) ]
+ [ (n) ]
+ }
+ {
+ [ (o) (p q) (r s) ]
+ [ (t u v w x y z) ]
+ }
+ ),
+ &[
+ // a b c
+ &[3][..],
+ // d e f
+ &[3][..],
+ // g h
+ &[2][..],
+ // i j k l m
+ &[5][..],
+ // n
+ &[1][..],
+ // o
+ &[1][..],
+ // p q
+ &[2][..],
+ // r s
+ &[2][..],
+ // t u v w x y z
+ &[7][..],
+
+ // (a b c) (d e f)
+ &[2, 6][..],
+ // (g h) (i j k l m)
+ &[2, 7][..],
+ // (n)
+ &[1, 1][..],
+ // (o) (p q) (r s)
+ &[3, 5][..],
+ // (t u v w x y z)
+ &[1, 7][..],
+
+ // [ (a b c) (d e f) ]
+ // [ (g h) (i j k l m) ]
+ // [ (n) ]
+ &[3, 5, 14][..],
+ // [ (o) (p q) (r s) ]
+ // [ (t u v w x y z) ]
+ &[2, 4, 12][..],
+
+ // {
+ // [ (a b c) (d e f) ]
+ // [ (g h) (i j k l m) ]
+ // [ (n) ]
+ // }
+ // {
+ // [ (o) (p q) (r s) ]
+ // [ (t u v w x y z) ]
+ // }
+ &[2, 5, 9, 26][..]
+ ][..]
+ );
+
+ // Grouped from the outer-most to the inner-most
+ macro_rules! three_nested_length {
+ ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
+ &[
+ $( $( $( $(
+ &[
+ ${ignore(i)} ${length(3)},
+ ${ignore(i)} ${length(2)},
+ ${ignore(i)} ${length(1)},
+ ${ignore(i)} ${length(0)},
+ ][..],
+ )* )* )* )*
+
+ $( $( $(
+ &[
+ ${ignore(i)} ${length(2)},
+ ${ignore(i)} ${length(1)},
+ ${ignore(i)} ${length(0)},
+ ][..],
+ )* )* )*
+
+ $( $(
+ &[
+ ${ignore(i)} ${length(1)},
+ ${ignore(i)} ${length(0)},
+ ][..],
+ )* )*
+
+ $(
+ &[
+ ${ignore(i)} ${length(0)},
+ ][..],
+ )*
+ ][..]
+ }
+ }
+ assert_eq!(
+ three_nested_length!(
+ {
+ [ (a b c) (d e f) ]
+ [ (g h) (i j k l m) ]
+ [ (n) ]
+ }
+ {
+ [ (o) (p q) (r s) ]
+ [ (t u v w x y z) ]
+ }
+ ),
+ &[
+ // a b c
+ &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+ // d e f
+ &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+ // g h
+ &[2, 3, 2, 2][..], &[2, 3, 2, 2][..],
+ // i j k l m
+ &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..],
+ &[2, 3, 2, 5][..],
+ // n
+ &[2, 3, 1, 1][..],
+ // o
+ &[2, 2, 3, 1][..],
+ // p q
+ &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+ // r s
+ &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+ // t u v w x y z
+ &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
+ &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
+
+ // (a b c) (d e f)
+ &[2, 3, 2][..], &[2, 3, 2][..],
+ // (g h) (i j k l m)
+ &[2, 3, 2][..], &[2, 3, 2][..],
+ // (n)
+ &[2, 3, 1][..],
+ // (o) (p q) (r s)
+ &[2, 2, 3][..], &[2, 2, 3][..], &[2, 2, 3][..],
+ // (t u v w x y z)
+ &[2, 2, 1][..],
+
+ // [ (a b c) (d e f) ]
+ // [ (g h) (i j k l m) ]
+ // [ (n) ]
+ &[2, 3][..], &[2, 3][..], &[2, 3,][..],
+ // [ (o) (p q) (r s) ]
+ // [ (t u v w x y z) ]
+ &[2, 2][..], &[2, 2][..],
+
+ // {
+ // [ (a b c) (d e f) ]
+ // [ (g h) (i j k l m) ]
+ // [ (n) ]
+ // }
+ // {
+ // [ (o) (p q) (r s) ]
+ // [ (t u v w x y z) ]
+ // }
+ &[2][..], &[2][..]
+ ][..]
+ );
+
+ // It is possible to say, to some degree, that count is an "amalgamation" of length (see
+ // each length line result and compare them with the count results)
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs b/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs
new file mode 100644
index 000000000..ed94c27cf
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/dollar-dollar-has-correct-behavior.rs
@@ -0,0 +1,28 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+macro_rules! nested {
+ ( $a:ident ) => {
+ macro_rules! $a {
+ ( $$( $b:ident ),* ) => {
+ $$(
+ macro_rules! $b {
+ ( $$$$( $c:ident ),* ) => {
+ $$$$(
+ fn $c() -> &'static str { stringify!($c) }
+ ),*
+ };
+ }
+ )*
+ };
+ }
+ };
+}
+
+fn main() {
+ nested!(a);
+ a!(b);
+ b!(c);
+ assert_eq!(c(), "c");
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
new file mode 100644
index 000000000..d05cd1b31
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
@@ -0,0 +1,148 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+/// Count the number of idents in a macro repetition.
+macro_rules! count_idents {
+ ( $( $i:ident ),* ) => {
+ ${count(i)}
+ };
+}
+
+/// Count the number of idents in a 2-dimensional macro repetition.
+macro_rules! count_idents_2 {
+ ( $( [ $( $i:ident ),* ] ),* ) => {
+ ${count(i)}
+ };
+}
+
+/// Mostly counts the number of OUTER-MOST repetitions
+macro_rules! count_depth_limits {
+ ( $( { $( [ $( $outer:ident : ( $( $inner:ident )* ) )* ] )* } )* ) => {
+ (
+ (
+ ${count(inner)},
+ ${count(inner, 0)},
+ ${count(inner, 1)},
+ ${count(inner, 2)},
+ ${count(inner, 3)},
+ ),
+ (
+ ${count(outer)},
+ ${count(outer, 0)},
+ ${count(outer, 1)},
+ ${count(outer, 2)},
+ ),
+ )
+ };
+}
+
+/// Produce (index, length) pairs for literals in a macro repetition.
+/// The literal is not included in the output, so this macro uses the
+/// `ignore` meta-variable expression to create a non-expanding
+/// repetition binding.
+macro_rules! enumerate_literals {
+ ( $( ($l:stmt) ),* ) => {
+ [$( ${ignore(l)} (${index()}, ${length()}) ),*]
+ };
+}
+
+/// Produce index and length tuples for literals in a 2-dimensional
+/// macro repetition.
+macro_rules! enumerate_literals_2 {
+ ( $( [ $( ($l:literal) ),* ] ),* ) => {
+ [
+ $(
+ $(
+ (
+ ${index(1)},
+ ${length(1)},
+ ${index(0)},
+ ${length(0)},
+ $l
+ ),
+ )*
+ )*
+ ]
+ };
+}
+
+/// Generate macros that count idents and then add a constant number
+/// to the count.
+///
+/// This macro uses dollar escaping to make it unambiguous as to which
+/// macro the repetition belongs to.
+macro_rules! make_count_adders {
+ ( $( $i:ident, $b:literal );* ) => {
+ $(
+ macro_rules! $i {
+ ( $$( $$j:ident ),* ) => {
+ $b + $${count(j)}
+ };
+ }
+ )*
+ };
+}
+
+make_count_adders! { plus_one, 1; plus_five, 5 }
+
+/// Generate a macro that allows selection of a particular literal
+/// from a sequence of inputs by their identifier.
+///
+/// This macro uses dollar escaping to make it unambiguous as to which
+/// macro the repetition belongs to, and to allow expansion of an
+/// identifier the name of which is not known in the definition
+/// of `make_picker`.
+macro_rules! make_picker {
+ ( $m:ident => $( $i:ident ),* ; $p:ident ) => {
+ macro_rules! $m {
+ ( $( $$ $i:literal ),* ) => {
+ $$ $p
+ };
+ }
+ };
+}
+
+make_picker!(first => a, b; a);
+
+make_picker!(second => a, b; b);
+
+fn main() {
+ assert_eq!(count_idents!(a, b, c), 3);
+ assert_eq!(count_idents_2!([a, b, c], [d, e], [f]), 6);
+ assert_eq!(
+ count_depth_limits! {
+ {
+ [ A: (a b c) D: (d e f) ]
+ [ G: (g h) I: (i j k l m) ]
+ [ N: (n) ]
+ }
+ {
+ [ O: (o) P: (p q) R: (r s) ]
+ [ T: (t u v w x y z) ]
+ }
+ },
+ ((26, 2, 5, 9, 26), (9, 2, 5, 9))
+ );
+ assert_eq!(enumerate_literals![("foo"), ("bar")], [(0, 2), (1, 2)]);
+ assert_eq!(
+ enumerate_literals_2![
+ [("foo"), ("bar"), ("baz")],
+ [("qux"), ("quux"), ("quuz"), ("xyzzy")]
+ ],
+ [
+ (0, 2, 0, 3, "foo"),
+ (0, 2, 1, 3, "bar"),
+ (0, 2, 2, 3, "baz"),
+
+ (1, 2, 0, 4, "qux"),
+ (1, 2, 1, 4, "quux"),
+ (1, 2, 2, 4, "quuz"),
+ (1, 2, 3, 4, "xyzzy"),
+ ]
+ );
+ assert_eq!(plus_one!(a, b, c), 4);
+ assert_eq!(plus_five!(a, b), 7);
+ assert_eq!(first!(1, 2), 1);
+ assert_eq!(second!(1, 2), 2);
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
new file mode 100644
index 000000000..b954967c4
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
@@ -0,0 +1,102 @@
+// run-pass
+
+#![feature(macro_metavar_expr)]
+
+#[derive(Debug)]
+struct Example<'a> {
+ _indexes: &'a [(u32, u32)],
+ _counts: &'a [u32],
+ _nested: Vec<Example<'a>>,
+}
+
+macro_rules! example {
+ ( $( [ $( ( $( $x:ident )* ) )* ] )* ) => {
+ Example {
+ _indexes: &[],
+ _counts: &[${count(x, 0)}, ${count(x, 1)}, ${count(x, 2)}],
+ _nested: vec![
+ $(
+ Example {
+ _indexes: &[(${index()}, ${length()})],
+ _counts: &[${count(x, 0)}, ${count(x, 1)}],
+ _nested: vec![
+ $(
+ Example {
+ _indexes: &[(${index(1)}, ${length(1)}), (${index()}, ${length()})],
+ _counts: &[${count(x)}],
+ _nested: vec![
+ $(
+ Example {
+ _indexes: &[
+ (${index(2)}, ${length(2)}),
+ (${index(1)}, ${length(1)}),
+ (${index()}, ${length()})
+ ],
+ _counts: &[],
+ _nested: vec![],
+ ${ignore(x)}
+ }
+ ),*
+ ]
+ }
+ ),*
+ ]
+ }
+ ),*
+ ]
+ }
+ };
+}
+
+static EXPECTED: &str = concat!(
+ "Example { _indexes: [], _counts: [2, 4, 13], _nested: [",
+ concat!(
+ "Example { _indexes: [(0, 2)], _counts: [3, 10], _nested: [",
+ concat!(
+ "Example { _indexes: [(0, 2), (0, 3)], _counts: [4], _nested: [",
+ concat!(
+ "Example { _indexes: [(0, 2), (0, 3), (0, 4)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(0, 2), (0, 3), (1, 4)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(0, 2), (0, 3), (2, 4)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(0, 2), (0, 3), (3, 4)], _counts: [], _nested: [] }",
+ ),
+ "] }, ",
+ "Example { _indexes: [(0, 2), (1, 3)], _counts: [4], _nested: [",
+ concat!(
+ "Example { _indexes: [(0, 2), (1, 3), (0, 4)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(0, 2), (1, 3), (1, 4)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(0, 2), (1, 3), (2, 4)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(0, 2), (1, 3), (3, 4)], _counts: [], _nested: [] }",
+ ),
+ "] }, ",
+ "Example { _indexes: [(0, 2), (2, 3)], _counts: [2], _nested: [",
+ concat!(
+ "Example { _indexes: [(0, 2), (2, 3), (0, 2)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(0, 2), (2, 3), (1, 2)], _counts: [], _nested: [] }",
+ ),
+ "] }",
+ ),
+ "] }, ",
+ "Example { _indexes: [(1, 2)], _counts: [1, 3], _nested: [",
+ concat!(
+ "Example { _indexes: [(1, 2), (0, 1)], _counts: [3], _nested: [",
+ concat!(
+ "Example { _indexes: [(1, 2), (0, 1), (0, 3)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(1, 2), (0, 1), (1, 3)], _counts: [], _nested: [] }, ",
+ "Example { _indexes: [(1, 2), (0, 1), (2, 3)], _counts: [], _nested: [] }",
+ ),
+ "] }",
+ ),
+ "] }",
+ ),
+ "] }",
+);
+
+fn main() {
+ let e = example! {
+ [ ( A B C D ) ( E F G H ) ( I J ) ]
+ [ ( K L M ) ]
+ };
+ let debug = format!("{:?}", e);
+ assert_eq!(debug, EXPECTED);
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
new file mode 100644
index 000000000..6a0d68bd6
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
@@ -0,0 +1,43 @@
+#![feature(macro_metavar_expr)]
+
+macro_rules! a {
+ ( $( { $( [ $( ( $( $foo:ident )* ) )* ] )* } )* ) => {
+ (
+ ${count(foo, 0)},
+ ${count(foo, 10)},
+ //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4
+ )
+ };
+}
+
+macro_rules! b {
+ ( $( { $( [ $( $foo:ident )* ] )* } )* ) => {
+ (
+ $( $( $(
+ ${ignore(foo)}
+ ${index(0)},
+ ${index(10)},
+ //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3
+ )* )* )*
+ )
+ };
+}
+
+macro_rules! c {
+ ( $( { $( $foo:ident )* } )* ) => {
+ (
+ $( $(
+ ${ignore(foo)}
+ ${length(0)}
+ ${length(10)}
+ //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2
+ )* )*
+ )
+ };
+}
+
+fn main() {
+ a!( { [ (a) ] [ (b c) ] } );
+ b!( { [ a b ] } );
+ c!({ a });
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
new file mode 100644
index 000000000..236122b64
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
@@ -0,0 +1,20 @@
+error: depth parameter on meta-variable expression `count` must be less than 4
+ --> $DIR/out-of-bounds-arguments.rs:7:14
+ |
+LL | ${count(foo, 10)},
+ | ^^^^^^^^^^^^^^^^
+
+error: depth parameter on meta-variable expression `index` must be less than 3
+ --> $DIR/out-of-bounds-arguments.rs:19:18
+ |
+LL | ${index(10)},
+ | ^^^^^^^^^^^
+
+error: depth parameter on meta-variable expression `length` must be less than 2
+ --> $DIR/out-of-bounds-arguments.rs:32:18
+ |
+LL | ${length(10)}
+ | ^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
new file mode 100644
index 000000000..b4fef11f1
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
@@ -0,0 +1,44 @@
+macro_rules! count {
+ ( $( $e:stmt ),* ) => {
+ ${ count(e) }
+ //~^ ERROR meta-variable expressions are unstable
+ };
+}
+
+macro_rules! dollar_dollar {
+ () => {
+ macro_rules! bar {
+ ( $$( $$any:tt )* ) => { $$( $$any )* };
+ //~^ ERROR meta-variable expressions are unstable
+ //~| ERROR meta-variable expressions are unstable
+ //~| ERROR meta-variable expressions are unstable
+ //~| ERROR meta-variable expressions are unstable
+ }
+ };
+}
+
+macro_rules! index {
+ ( $( $e:stmt ),* ) => {
+ $( ${ignore(e)} ${index()} )*
+ //~^ ERROR meta-variable expressions are unstable
+ //~| ERROR meta-variable expressions are unstable
+ };
+}
+
+macro_rules! ignore {
+ ( $( $i:stmt ),* ) => {{
+ 0 $( + 1 ${ignore(i)} )*
+ //~^ ERROR meta-variable expressions are unstable
+ }};
+}
+
+macro_rules! length {
+ ( $( $e:stmt ),* ) => {
+ $( ${ignore(e)} ${length()} )*
+ //~^ ERROR meta-variable expressions are unstable
+ //~| ERROR meta-variable expressions are unstable
+ };
+}
+
+fn main() {
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
new file mode 100644
index 000000000..ecf598b10
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
@@ -0,0 +1,93 @@
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:3:10
+ |
+LL | ${ count(e) }
+ | ^^^^^^^^^^^^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:11:16
+ |
+LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
+ | ^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:11:20
+ |
+LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
+ | ^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:11:39
+ |
+LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
+ | ^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:11:43
+ |
+LL | ( $$( $$any:tt )* ) => { $$( $$any )* };
+ | ^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:22:13
+ |
+LL | $( ${ignore(e)} ${index()} )*
+ | ^^^^^^^^^^^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:22:26
+ |
+LL | $( ${ignore(e)} ${index()} )*
+ | ^^^^^^^^^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:30:19
+ |
+LL | 0 $( + 1 ${ignore(i)} )*
+ | ^^^^^^^^^^^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:37:13
+ |
+LL | $( ${ignore(e)} ${length()} )*
+ | ^^^^^^^^^^^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error[E0658]: meta-variable expressions are unstable
+ --> $DIR/required-feature.rs:37:26
+ |
+LL | $( ${ignore(e)} ${length()} )*
+ | ^^^^^^^^^^
+ |
+ = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
+ = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
new file mode 100644
index 000000000..fdf16442d
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
@@ -0,0 +1,165 @@
+#![feature(macro_metavar_expr)]
+
+// `curly` = Right hand side curly brackets
+// `no_rhs_dollar` = No dollar sign at the right hand side meta variable "function"
+// `round` = Left hand side round brackets
+
+macro_rules! curly__no_rhs_dollar__round {
+ ( $( $i:ident ),* ) => { ${ count(i) } };
+}
+
+macro_rules! curly__no_rhs_dollar__no_round {
+ ( $i:ident ) => { ${ count(i) } };
+ //~^ ERROR `count` can not be placed inside the inner-most repetition
+}
+
+macro_rules! curly__rhs_dollar__round {
+ ( $( $i:ident ),* ) => { ${ count($i) } };
+ //~^ ERROR expected identifier, found `$`
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! curly__rhs_dollar__no_round {
+ ( $i:ident ) => { ${ count($i) } };
+ //~^ ERROR expected identifier, found `$`
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! no_curly__no_rhs_dollar__round {
+ ( $( $i:ident ),* ) => { count(i) };
+ //~^ ERROR cannot find function `count` in this scope
+ //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__no_rhs_dollar__no_round {
+ ( $i:ident ) => { count(i) };
+ //~^ ERROR cannot find function `count` in this scope
+ //~| ERROR cannot find value `i` in this scope
+}
+
+macro_rules! no_curly__rhs_dollar__round {
+ ( $( $i:ident ),* ) => { count($i) };
+ //~^ ERROR variable 'i' is still repeating at this depth
+}
+
+macro_rules! no_curly__rhs_dollar__no_round {
+ ( $i:ident ) => { count($i) };
+ //~^ ERROR cannot find function `count` in this scope
+}
+
+// Other scenarios
+
+macro_rules! dollar_dollar_in_the_lhs {
+ ( $$ $a:ident ) => {
+ //~^ ERROR unexpected token: $
+ };
+}
+
+macro_rules! extra_garbage_after_metavar {
+ ( $( $i:ident ),* ) => {
+ ${count() a b c}
+ //~^ ERROR unexpected token: a
+ //~| ERROR expected expression, found `$`
+ ${count(i a b c)}
+ //~^ ERROR unexpected token: a
+ ${count(i, 1 a b c)}
+ //~^ ERROR unexpected token: a
+ ${count(i) a b c}
+ //~^ ERROR unexpected token: a
+
+ ${ignore(i) a b c}
+ //~^ ERROR unexpected token: a
+ ${ignore(i a b c)}
+ //~^ ERROR unexpected token: a
+
+ ${index() a b c}
+ //~^ ERROR unexpected token: a
+ ${index(1 a b c)}
+ //~^ ERROR unexpected token: a
+
+ ${index() a b c}
+ //~^ ERROR unexpected token: a
+ ${index(1 a b c)}
+ //~^ ERROR unexpected token: a
+ };
+}
+
+const IDX: usize = 1;
+macro_rules! metavar_depth_is_not_literal {
+ ( $( $i:ident ),* ) => { ${ index(IDX) } };
+ //~^ ERROR meta-variable expression depth must be a literal
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_in_the_lhs {
+ ( ${ length() } ) => {
+ //~^ ERROR unexpected token: {
+ //~| ERROR expected one of: `*`, `+`, or `?`
+ };
+}
+
+macro_rules! metavar_token_without_ident {
+ ( $( $i:ident ),* ) => { ${ ignore() } };
+ //~^ ERROR expected identifier
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_with_literal_suffix {
+ ( $( $i:ident ),* ) => { ${ index(1u32) } };
+ //~^ ERROR only unsuffixes integer literals are supported in meta-variable expressions
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! metavar_without_parens {
+ ( $( $i:ident ),* ) => { ${ count{i} } };
+ //~^ ERROR meta-variable expression parameter must be wrapped in parentheses
+ //~| ERROR expected expression, found `$`
+}
+
+macro_rules! open_brackets_without_tokens {
+ ( $( $i:ident ),* ) => { ${ {} } };
+ //~^ ERROR expected expression, found `$`
+ //~| ERROR expected identifier
+}
+
+macro_rules! unknown_count_ident {
+ ( $( $i:ident )* ) => {
+ ${count(foo)}
+ //~^ ERROR variable `foo` is not recognized in meta-variable expression
+ };
+}
+
+macro_rules! unknown_ignore_ident {
+ ( $( $i:ident )* ) => {
+ ${ignore(bar)}
+ //~^ ERROR variable `bar` is not recognized in meta-variable expression
+ };
+}
+
+macro_rules! unknown_metavar {
+ ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+ //~^ ERROR unrecognized meta-variable expression
+ //~| ERROR expected expression
+}
+
+fn main() {
+ curly__no_rhs_dollar__round!(a, b, c);
+ curly__no_rhs_dollar__no_round!(a);
+ curly__rhs_dollar__round!(a, b, c);
+ curly__rhs_dollar__no_round!(a);
+ no_curly__no_rhs_dollar__round!(a, b, c);
+ no_curly__no_rhs_dollar__no_round!(a);
+ no_curly__rhs_dollar__round!(a, b, c);
+ no_curly__rhs_dollar__no_round!(a);
+ //~^ ERROR cannot find value `a` in this scope
+
+ extra_garbage_after_metavar!(a);
+ metavar_depth_is_not_literal!(a);
+ metavar_token_without_ident!(a);
+ metavar_with_literal_suffix!(a);
+ metavar_without_parens!(a);
+ open_brackets_without_tokens!(a);
+ unknown_count_ident!(a);
+ unknown_ignore_ident!(a);
+ unknown_metavar!(a);
+}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
new file mode 100644
index 000000000..a6cff95fd
--- /dev/null
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -0,0 +1,385 @@
+error: expected identifier, found `$`
+ --> $DIR/syntax-errors.rs:17:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ count($i) } };
+ | ^^^^^ - help: try removing `$`
+
+error: expected identifier, found `$`
+ --> $DIR/syntax-errors.rs:23:26
+ |
+LL | ( $i:ident ) => { ${ count($i) } };
+ | ^^^^^ - help: try removing `$`
+
+error: unexpected token: $
+ --> $DIR/syntax-errors.rs:53:8
+ |
+LL | ( $$ $a:ident ) => {
+ | ^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+ --> $DIR/syntax-errors.rs:53:8
+ |
+LL | ( $$ $a:ident ) => {
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:60:19
+ |
+LL | ${count() a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:60:19
+ |
+LL | ${count() a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:63:19
+ |
+LL | ${count(i a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:63:19
+ |
+LL | ${count(i a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:65:22
+ |
+LL | ${count(i, 1 a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:65:22
+ |
+LL | ${count(i, 1 a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:67:20
+ |
+LL | ${count(i) a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:67:20
+ |
+LL | ${count(i) a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:70:21
+ |
+LL | ${ignore(i) a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:70:21
+ |
+LL | ${ignore(i) a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:72:20
+ |
+LL | ${ignore(i a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:72:20
+ |
+LL | ${ignore(i a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:75:19
+ |
+LL | ${index() a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:75:19
+ |
+LL | ${index() a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:77:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:77:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:80:19
+ |
+LL | ${index() a b c}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:80:19
+ |
+LL | ${index() a b c}
+ | ^
+
+error: unexpected token: a
+ --> $DIR/syntax-errors.rs:82:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+ |
+note: meta-variable expression must not have trailing tokens
+ --> $DIR/syntax-errors.rs:82:19
+ |
+LL | ${index(1 a b c)}
+ | ^
+
+error: meta-variable expression depth must be a literal
+ --> $DIR/syntax-errors.rs:89:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(IDX) } };
+ | ^^^^^
+
+error: unexpected token: {
+ --> $DIR/syntax-errors.rs:95:8
+ |
+LL | ( ${ length() } ) => {
+ | ^^^^^^^^^^^^
+
+note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
+ --> $DIR/syntax-errors.rs:95:8
+ |
+LL | ( ${ length() } ) => {
+ | ^^^^^^^^^^^^
+
+error: expected one of: `*`, `+`, or `?`
+ --> $DIR/syntax-errors.rs:95:8
+ |
+LL | ( ${ length() } ) => {
+ | ^^^^^^^^^^^^
+
+error: expected identifier
+ --> $DIR/syntax-errors.rs:102:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ ignore() } };
+ | ^^^^^^
+
+error: only unsuffixes integer literals are supported in meta-variable expressions
+ --> $DIR/syntax-errors.rs:108:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(1u32) } };
+ | ^^^^^
+
+error: meta-variable expression parameter must be wrapped in parentheses
+ --> $DIR/syntax-errors.rs:114:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ count{i} } };
+ | ^^^^^
+
+error: expected identifier
+ --> $DIR/syntax-errors.rs:120:31
+ |
+LL | ( $( $i:ident ),* ) => { ${ {} } };
+ | ^^^^^^
+
+error: unrecognized meta-variable expression
+ --> $DIR/syntax-errors.rs:140:33
+ |
+LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+ | ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length
+
+error: `count` can not be placed inside the inner-most repetition
+ --> $DIR/syntax-errors.rs:12:24
+ |
+LL | ( $i:ident ) => { ${ count(i) } };
+ | ^^^^^^^^^^^^
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:17:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ count($i) } };
+ | ^ expected expression
+...
+LL | curly__rhs_dollar__round!(a, b, c);
+ | ---------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `curly__rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:23:23
+ |
+LL | ( $i:ident ) => { ${ count($i) } };
+ | ^ expected expression
+...
+LL | curly__rhs_dollar__no_round!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable 'i' is still repeating at this depth
+ --> $DIR/syntax-errors.rs:41:36
+ |
+LL | ( $( $i:ident ),* ) => { count($i) };
+ | ^^
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:60:9
+ |
+LL | ${count() a b c}
+ | ^ expected expression
+...
+LL | extra_garbage_after_metavar!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `extra_garbage_after_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:89:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(IDX) } };
+ | ^ expected expression
+...
+LL | metavar_depth_is_not_literal!(a);
+ | -------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_depth_is_not_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:102:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ ignore() } };
+ | ^ expected expression
+...
+LL | metavar_token_without_ident!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_token_without_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:108:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ index(1u32) } };
+ | ^ expected expression
+...
+LL | metavar_with_literal_suffix!(a);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_with_literal_suffix` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:114:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ count{i} } };
+ | ^ expected expression
+...
+LL | metavar_without_parens!(a);
+ | -------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `metavar_without_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:120:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ {} } };
+ | ^ expected expression
+...
+LL | open_brackets_without_tokens!(a);
+ | -------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `open_brackets_without_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: variable `foo` is not recognized in meta-variable expression
+ --> $DIR/syntax-errors.rs:127:17
+ |
+LL | ${count(foo)}
+ | ^^^
+
+error: variable `bar` is not recognized in meta-variable expression
+ --> $DIR/syntax-errors.rs:134:18
+ |
+LL | ${ignore(bar)}
+ | ^^^
+
+error: expected expression, found `$`
+ --> $DIR/syntax-errors.rs:140:30
+ |
+LL | ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
+ | ^ expected expression
+...
+LL | unknown_metavar!(a);
+ | ------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `unknown_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+ --> $DIR/syntax-errors.rs:29:36
+ |
+LL | ( $( $i:ident ),* ) => { count(i) };
+ | ^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__round!(a, b, c);
+ | ---------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `i` in this scope
+ --> $DIR/syntax-errors.rs:35:29
+ |
+LL | ( $i:ident ) => { count(i) };
+ | ^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__no_round!(a);
+ | ------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/syntax-errors.rs:153:37
+ |
+LL | no_curly__rhs_dollar__no_round!(a);
+ | ^ not found in this scope
+
+error[E0425]: cannot find function `count` in this scope
+ --> $DIR/syntax-errors.rs:29:30
+ |
+LL | ( $( $i:ident ),* ) => { count(i) };
+ | ^^^^^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__round!(a, b, c);
+ | ---------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+ --> $DIR/syntax-errors.rs:35:23
+ |
+LL | ( $i:ident ) => { count(i) };
+ | ^^^^^ not found in this scope
+...
+LL | no_curly__no_rhs_dollar__no_round!(a);
+ | ------------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0425]: cannot find function `count` in this scope
+ --> $DIR/syntax-errors.rs:46:23
+ |
+LL | ( $i:ident ) => { count($i) };
+ | ^^^^^ not found in this scope
+...
+LL | no_curly__rhs_dollar__no_round!(a);
+ | ---------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `no_curly__rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 40 previous errors
+
+For more information about this error, try `rustc --explain E0425`.