diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
index cb7f7d318dc..cafa91c8b8b 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
@@ -81,6 +81,7 @@
 ///     E::A,
 /// }
 /// ```
+#[cfg(bootstrap)]
 #[macro_export]
 macro_rules! impl_tag {
     (
@@ -140,5 +141,148 @@ macro_rules! impl_tag {
     };
 }
 
+/// Implements [`Tag`] for a given type.
+///
+/// You can use `impl_tag` on structs and enums.
+/// You need to specify the type and all its possible values,
+/// which can only be paths with optional fields.
+///
+/// [`Tag`]: crate::tagged_ptr::Tag
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// #![feature(macro_metavar_expr)]
+/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
+///
+/// #[derive(Copy, Clone, PartialEq, Debug)]
+/// enum SomeTag {
+///     A,
+///     B,
+///     X { v: bool },
+///     Y(bool, bool),
+/// }
+///
+/// impl_tag! {
+///     // The type for which the `Tag` will be implemented
+///     impl Tag for SomeTag;
+///     // You need to specify all possible tag values:
+///     SomeTag::A, // 0
+///     SomeTag::B, // 1
+///     // For variants with fields, you need to specify the fields:
+///     SomeTag::X { v: true  }, // 2
+///     SomeTag::X { v: false }, // 3
+///     // For tuple variants use named syntax:
+///     SomeTag::Y { 0: true,  1: true  }, // 4
+///     SomeTag::Y { 0: false, 1: true  }, // 5
+///     SomeTag::Y { 0: true,  1: false }, // 6
+///     SomeTag::Y { 0: false, 1: false }, // 7
+/// }
+///
+/// // Tag values are assigned in order:
+/// assert_eq!(SomeTag::A.into_usize(), 0);
+/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
+/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
+///
+/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B);
+/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true });
+/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false));
+/// ```
+///
+/// Structs are supported:
+///
+/// ```
+/// #![feature(macro_metavar_expr)]
+/// # use rustc_data_structures::impl_tag;
+/// #[derive(Copy, Clone)]
+/// struct Flags { a: bool, b: bool }
+///
+/// impl_tag! {
+///     impl Tag for Flags;
+///     Flags { a: true,  b: true  },
+///     Flags { a: false, b: true  },
+///     Flags { a: true,  b: false },
+///     Flags { a: false, b: false },
+/// }
+/// ```
+///
+/// Not specifying all values results in a compile error:
+///
+/// ```compile_fail,E0004
+/// #![feature(macro_metavar_expr)]
+/// # use rustc_data_structures::impl_tag;
+/// #[derive(Copy, Clone)]
+/// enum E {
+///     A,
+///     B,
+/// }
+///
+/// impl_tag! {
+///     impl Tag for E;
+///     E::A,
+/// }
+/// ```
+#[cfg(not(bootstrap))]
+#[macro_export]
+macro_rules! impl_tag {
+    (
+        impl Tag for $Self:ty;
+        $(
+            $($path:ident)::* $( { $( $fields:tt )* })?,
+        )*
+    ) => {
+        // Safety:
+        // `bits_for_tags` is called on the same `${index()}`-es as
+        // `into_usize` returns, thus `BITS` constant is correct.
+        unsafe impl $crate::tagged_ptr::Tag for $Self {
+            const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
+                $(
+                    ${index()},
+                    $( ${ignore($path)} )*
+                )*
+            ]);
+
+            #[inline]
+            fn into_usize(self) -> usize {
+                // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc)
+                // (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
+                #[forbid(unreachable_patterns)]
+                match self {
+                    // `match` is doing heavy lifting here, by requiring exhaustiveness
+                    $(
+                        $($path)::* $( { $( $fields )* } )? => ${index()},
+                    )*
+                }
+            }
+
+            #[inline]
+            unsafe fn from_usize(tag: usize) -> Self {
+                match tag {
+                    $(
+                        ${index()} => $($path)::* $( { $( $fields )* } )?,
+                    )*
+
+                    // Safety:
+                    // `into_usize` only returns `${index()}` of the same
+                    // repetition as we are filtering above, thus if this is
+                    // reached, the safety contract of this function was
+                    // already breached.
+                    _ => unsafe {
+                        debug_assert!(
+                            false,
+                            "invalid tag: {tag}\
+                             (this is a bug in the caller of `from_usize`)"
+                        );
+                        std::hint::unreachable_unchecked()
+                    },
+                }
+            }
+
+        }
+    };
+}
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 47d4b802c0f..89caf8aa231 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -41,6 +41,7 @@ use std::path::PathBuf;
 use std::rc::Rc;
 use std::{iter, mem};
 
+#[cfg(bootstrap)]
 macro_rules! ast_fragments {
     (
         $($Kind:ident($AstTy:ty) {
@@ -165,6 +166,131 @@ macro_rules! ast_fragments {
     }
 }
 
+#[cfg(not(bootstrap))]
+macro_rules! ast_fragments {
+    (
+        $($Kind:ident($AstTy:ty) {
+            $kind_name:expr;
+            $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
+            $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
+            fn $make_ast:ident;
+        })*
+    ) => {
+        /// A fragment of AST that can be produced by a single macro expansion.
+        /// Can also serve as an input and intermediate result for macro expansion operations.
+        pub enum AstFragment {
+            OptExpr(Option<P<ast::Expr>>),
+            MethodReceiverExpr(P<ast::Expr>),
+            $($Kind($AstTy),)*
+        }
+
+        /// "Discriminant" of an AST fragment.
+        #[derive(Copy, Clone, PartialEq, Eq)]
+        pub enum AstFragmentKind {
+            OptExpr,
+            MethodReceiverExpr,
+            $($Kind,)*
+        }
+
+        impl AstFragmentKind {
+            pub fn name(self) -> &'static str {
+                match self {
+                    AstFragmentKind::OptExpr => "expression",
+                    AstFragmentKind::MethodReceiverExpr => "expression",
+                    $(AstFragmentKind::$Kind => $kind_name,)*
+                }
+            }
+
+            fn make_from<'a>(self, result: Box<dyn MacResult + 'a>) -> Option<AstFragment> {
+                match self {
+                    AstFragmentKind::OptExpr =>
+                        result.make_expr().map(Some).map(AstFragment::OptExpr),
+                    AstFragmentKind::MethodReceiverExpr =>
+                        result.make_expr().map(AstFragment::MethodReceiverExpr),
+                    $(AstFragmentKind::$Kind => result.$make_ast().map(AstFragment::$Kind),)*
+                }
+            }
+        }
+
+        impl AstFragment {
+            pub fn add_placeholders(&mut self, placeholders: &[NodeId]) {
+                if placeholders.is_empty() {
+                    return;
+                }
+                match self {
+                    $($(AstFragment::$Kind(ast) => ast.extend(placeholders.iter().flat_map(|id| {
+                        ${ignore($flat_map_ast_elt)}
+                        placeholder(AstFragmentKind::$Kind, *id, None).$make_ast()
+                    })),)?)*
+                    _ => panic!("unexpected AST fragment kind")
+                }
+            }
+
+            pub fn make_opt_expr(self) -> Option<P<ast::Expr>> {
+                match self {
+                    AstFragment::OptExpr(expr) => expr,
+                    _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+                }
+            }
+
+            pub fn make_method_receiver_expr(self) -> P<ast::Expr> {
+                match self {
+                    AstFragment::MethodReceiverExpr(expr) => expr,
+                    _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+                }
+            }
+
+            $(pub fn $make_ast(self) -> $AstTy {
+                match self {
+                    AstFragment::$Kind(ast) => ast,
+                    _ => panic!("AstFragment::make_* called on the wrong kind of fragment"),
+                }
+            })*
+
+            fn make_ast<T: InvocationCollectorNode>(self) -> T::OutputTy {
+                T::fragment_to_output(self)
+            }
+
+            pub fn mut_visit_with<F: MutVisitor>(&mut self, vis: &mut F) {
+                match self {
+                    AstFragment::OptExpr(opt_expr) => {
+                        visit_clobber(opt_expr, |opt_expr| {
+                            if let Some(expr) = opt_expr {
+                                vis.filter_map_expr(expr)
+                            } else {
+                                None
+                            }
+                        });
+                    }
+                    AstFragment::MethodReceiverExpr(expr) => vis.visit_method_receiver_expr(expr),
+                    $($(AstFragment::$Kind(ast) => vis.$mut_visit_ast(ast),)?)*
+                    $($(AstFragment::$Kind(ast) =>
+                        ast.flat_map_in_place(|ast| vis.$flat_map_ast_elt(ast)),)?)*
+                }
+            }
+
+            pub fn visit_with<'a, V: Visitor<'a>>(&'a self, visitor: &mut V) {
+                match self {
+                    AstFragment::OptExpr(Some(expr)) => visitor.visit_expr(expr),
+                    AstFragment::OptExpr(None) => {}
+                    AstFragment::MethodReceiverExpr(expr) => visitor.visit_method_receiver_expr(expr),
+                    $($(AstFragment::$Kind(ast) => visitor.$visit_ast(ast),)?)*
+                    $($(AstFragment::$Kind(ast) => for ast_elt in &ast[..] {
+                        visitor.$visit_ast_elt(ast_elt, $($args)*);
+                    })?)*
+                }
+            }
+        }
+
+        impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
+            $(fn $make_ast(self: Box<crate::mbe::macro_rules::ParserAnyMacro<'a>>)
+                           -> Option<$AstTy> {
+                Some(self.make(AstFragmentKind::$Kind).$make_ast())
+            })*
+        }
+    }
+}
+
 ast_fragments! {
     Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
     Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index c29edc3dc9f..4b8c6feb93e 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -10,9 +10,8 @@ use rustc_span::Span;
 /// A meta-variable expression, for expansions based on properties of meta-variables.
 #[derive(Debug, Clone, PartialEq, Encodable, Decodable)]
 pub(crate) enum MetaVarExpr {
-    /// The number of repetitions of an identifier, optionally limited to a number
-    /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited.
-    Count(Ident, Option<usize>),
+    /// The number of repetitions of an identifier.
+    Count(Ident, usize),
 
     /// Ignore a meta-variable for repetition without expansion.
     Ignore(Ident),
@@ -43,7 +42,10 @@ impl MetaVarExpr {
         let mut iter = args.trees();
         let rslt = match ident.as_str() {
             "count" => parse_count(&mut iter, sess, ident.span)?,
-            "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?),
+            "ignore" => {
+                eat_dollar(&mut iter, sess, ident.span)?;
+                MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?)
+            }
             "index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?),
             "length" => MetaVarExpr::Length(parse_depth(&mut iter, sess, ident.span)?),
             _ => {
@@ -92,6 +94,7 @@ fn parse_count<'sess>(
     sess: &'sess ParseSess,
     span: Span,
 ) -> PResult<'sess, MetaVarExpr> {
+    eat_dollar(iter, sess, span)?;
     let ident = parse_ident(iter, sess, span)?;
     let depth = if try_eat_comma(iter) {
         if iter.look_ahead(0).is_none() {
@@ -100,9 +103,9 @@ fn parse_count<'sess>(
                 "`count` followed by a comma must have an associated index indicating its depth",
             ));
         }
-        Some(parse_depth(iter, sess, span)?)
+        parse_depth(iter, sess, span)?
     } else {
-        None
+        0
     };
     Ok(MetaVarExpr::Count(ident, depth))
 }
@@ -166,3 +169,20 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool {
     }
     false
 }
+
+/// Expects that the next item is a dollar sign.
+fn eat_dollar<'sess>(
+    iter: &mut RefTokenTreeCursor<'_>,
+    sess: &'sess ParseSess,
+    span: Span,
+) -> PResult<'sess, ()> {
+    if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0)
+    {
+        let _ = iter.next();
+        return Ok(());
+    }
+    Err(sess.span_diagnostic.struct_span_err(
+        span,
+        "meta-variables within meta-variable expressions must be referenced using a dollar sign",
+    ))
+}
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 18707cebcd5..80fd82e0302 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -440,7 +440,7 @@ fn lockstep_iter_size(
 ///   declared inside a single repetition and the index `1` implies two nested repetitions.
 fn count_repetitions<'a>(
     cx: &ExtCtxt<'a>,
-    depth_opt: Option<usize>,
+    depth_user: usize,
     mut matched: &NamedMatch,
     repeats: &[(usize, usize)],
     sp: &DelimSpan,
@@ -449,37 +449,45 @@ fn count_repetitions<'a>(
     // (or at the top-level of `matched` if no depth is given).
     fn count<'a>(
         cx: &ExtCtxt<'a>,
-        declared_lhs_depth: usize,
-        depth_opt: Option<usize>,
+        depth_curr: usize,
+        depth_max: usize,
         matched: &NamedMatch,
         sp: &DelimSpan,
     ) -> PResult<'a, usize> {
         match matched {
-            MatchedTokenTree(_) | MatchedNonterminal(_) => {
-                if declared_lhs_depth == 0 {
-                    return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
-                }
-                match depth_opt {
-                    None => Ok(1),
-                    Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
-                }
-            }
+            MatchedTokenTree(_) | MatchedNonterminal(_) => Ok(1),
             MatchedSeq(named_matches) => {
-                let new_declared_lhs_depth = declared_lhs_depth + 1;
-                match depth_opt {
-                    None => named_matches
+                if depth_curr == depth_max {
+                    Ok(named_matches.len())
+                } else {
+                    named_matches
                         .iter()
-                        .map(|elem| count(cx, new_declared_lhs_depth, None, elem, sp))
-                        .sum(),
-                    Some(0) => Ok(named_matches.len()),
-                    Some(depth) => named_matches
-                        .iter()
-                        .map(|elem| count(cx, new_declared_lhs_depth, Some(depth - 1), elem, sp))
-                        .sum(),
+                        .map(|elem| count(cx, depth_curr + 1, depth_max, elem, sp))
+                        .sum()
                 }
             }
         }
     }
+
+    /// Maximum depth
+    fn depth(counter: usize, matched: &NamedMatch) -> usize {
+        match matched {
+            MatchedTokenTree(_) | MatchedNonterminal(_) => counter,
+            MatchedSeq(named_matches) => {
+                let rslt = counter + 1;
+                if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt }
+            }
+        }
+    }
+
+    let depth_max = depth(0, matched)
+        .checked_sub(1)
+        .and_then(|el| el.checked_sub(repeats.len()))
+        .unwrap_or_default();
+    if depth_user > depth_max {
+        return Err(out_of_bounds_err(cx, depth_max + 1, sp.entire(), "count"));
+    }
+
     // `repeats` records all of the nested levels at which we are currently
     // matching meta-variables. The meta-var-expr `count($x)` only counts
     // matches that occur in this "subtree" of the `NamedMatch` where we
@@ -491,7 +499,12 @@ fn count_repetitions<'a>(
             matched = &ads[idx];
         }
     }
-    count(cx, 0, depth_opt, matched, sp)
+
+    if let MatchedTokenTree(_) | MatchedNonterminal(_) = matched {
+        return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
+    }
+
+    count(cx, depth_user, depth_max, matched, sp)
 }
 
 /// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident]
@@ -523,7 +536,7 @@ fn out_of_bounds_err<'a>(
         )
     } else {
         format!(
-            "depth parameter on meta-variable expression `{ty}` \
+            "depth parameter of meta-variable expression `{ty}` \
              must be less than {max}"
         )
     };
@@ -545,9 +558,9 @@ fn transcribe_metavar_expr<'a>(
         span
     };
     match *expr {
-        MetaVarExpr::Count(original_ident, depth_opt) => {
+        MetaVarExpr::Count(original_ident, depth) => {
             let matched = matched_from_ident(cx, original_ident, interp)?;
-            let count = count_repetitions(cx, depth_opt, matched, repeats, sp)?;
+            let count = count_repetitions(cx, depth, matched, repeats, sp)?;
             let tt = TokenTree::token_alone(
                 TokenKind::lit(token::Integer, sym::integer(count), None),
                 visited_span(),
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 765f73636fb..3689312e6ae 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -8,6 +8,7 @@ use crate::marker::{StructuralEq, StructuralPartialEq};
 //
 // Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C)
 // will implement everything for (A, B, C), (A, B) and (A,).
+#[cfg(bootstrap)]
 macro_rules! tuple_impls {
     // Stopping criteria (1-ary tuple)
     ($T:ident) => {
@@ -142,6 +143,148 @@ macro_rules! tuple_impls {
     }
 }
 
+// Recursive macro for implementing n-ary tuple functions and operations
+//
+// Also provides implementations for tuples with lesser arity. For example, tuple_impls!(A B C)
+// will implement everything for (A, B, C), (A, B) and (A,).
+#[cfg(not(bootstrap))]
+macro_rules! tuple_impls {
+    // Stopping criteria (1-ary tuple)
+    ($T:ident) => {
+        tuple_impls!(@impl $T);
+    };
+    // Running criteria (n-ary tuple, with n >= 2)
+    ($T:ident $( $U:ident )+) => {
+        tuple_impls!($( $U )+);
+        tuple_impls!(@impl $T $( $U )+);
+    };
+    // "Private" internal implementation
+    (@impl $( $T:ident )+) => {
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[stable(feature = "rust1", since = "1.0.0")]
+            impl<$($T: PartialEq),+> PartialEq for ($($T,)+)
+            where
+                last_type!($($T,)+): ?Sized
+            {
+                #[inline]
+                fn eq(&self, other: &($($T,)+)) -> bool {
+                    $( ${ignore($T)} self.${index()} == other.${index()} )&&+
+                }
+                #[inline]
+                fn ne(&self, other: &($($T,)+)) -> bool {
+                    $( ${ignore($T)} self.${index()} != other.${index()} )||+
+                }
+            }
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[stable(feature = "rust1", since = "1.0.0")]
+            impl<$($T: Eq),+> Eq for ($($T,)+)
+            where
+                last_type!($($T,)+): ?Sized
+            {}
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[unstable(feature = "structural_match", issue = "31434")]
+            impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+)
+            {}
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[unstable(feature = "structural_match", issue = "31434")]
+            impl<$($T),+> StructuralPartialEq for ($($T,)+)
+            {}
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[unstable(feature = "structural_match", issue = "31434")]
+            impl<$($T),+> StructuralEq for ($($T,)+)
+            {}
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[stable(feature = "rust1", since = "1.0.0")]
+            impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
+            where
+                last_type!($($T,)+): ?Sized
+            {
+                #[inline]
+                fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
+                    lexical_partial_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+                #[inline]
+                fn lt(&self, other: &($($T,)+)) -> bool {
+                    lexical_ord!(lt, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+                #[inline]
+                fn le(&self, other: &($($T,)+)) -> bool {
+                    lexical_ord!(le, Less, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+                #[inline]
+                fn ge(&self, other: &($($T,)+)) -> bool {
+                    lexical_ord!(ge, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+                #[inline]
+                fn gt(&self, other: &($($T,)+)) -> bool {
+                    lexical_ord!(gt, Greater, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+            }
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[stable(feature = "rust1", since = "1.0.0")]
+            impl<$($T: Ord),+> Ord for ($($T,)+)
+            where
+                last_type!($($T,)+): ?Sized
+            {
+                #[inline]
+                fn cmp(&self, other: &($($T,)+)) -> Ordering {
+                    lexical_cmp!($( ${ignore($T)} self.${index()}, other.${index()} ),+)
+                }
+            }
+        }
+
+        maybe_tuple_doc! {
+            $($T)+ @
+            #[stable(feature = "rust1", since = "1.0.0")]
+            impl<$($T: Default),+> Default for ($($T,)+) {
+                #[inline]
+                fn default() -> ($($T,)+) {
+                    ($({ let x: $T = Default::default(); x},)+)
+                }
+            }
+        }
+
+        #[stable(feature = "array_tuple_conv", since = "1.71.0")]
+        impl<T> From<[T; ${count($T)}]> for ($(${ignore($T)} T,)+) {
+            #[inline]
+            #[allow(non_snake_case)]
+            fn from(array: [T; ${count($T)}]) -> Self {
+                let [$($T,)+] = array;
+                ($($T,)+)
+            }
+        }
+
+        #[stable(feature = "array_tuple_conv", since = "1.71.0")]
+        impl<T> From<($(${ignore($T)} T,)+)> for [T; ${count($T)}] {
+            #[inline]
+            #[allow(non_snake_case)]
+            fn from(tuple: ($(${ignore($T)} T,)+)) -> Self {
+                let ($($T,)+) = tuple;
+                [$($T,)+]
+            }
+        }
+    }
+}
+
 // If this is a unary tuple, it adds a doc comment.
 // Otherwise, it hides the docs entirely.
 macro_rules! maybe_tuple_doc {
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
index ab8d95a41d0..1b8ce10ccce 100644
--- 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
@@ -10,11 +10,11 @@ fn main() {
                 $(
                     // inner-most repetition
                     $(
-                        ${ignore(l)} ${index()}, ${length()},
+                        ${ignore($l)} ${index()}, ${length()},
                     )*
-                    ${count(l)}, ${index()}, ${length()},
+                    ${count($l)}, ${index()}, ${length()},
                 )*
-                ${count(l)},
+                ${count($l)},
             ]
         };
     }
@@ -72,30 +72,30 @@ fn main() {
             &[
                 $( $( $(
                     &[
-                        ${ignore(i)} ${count(i, 0)},
+                        ${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, 0)},
-                        ${ignore(i)} ${count(i, 1)},
-                        ${ignore(i)} ${count(i, 2)},
+                        ${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)},
+                    ${count($i, 0)},
+                    ${count($i, 1)},
+                    ${count($i, 2)},
+                    ${count($i, 3)},
                 ][..]
             ][..]
         }
@@ -133,23 +133,23 @@ fn main() {
             &[7][..],
 
             // (a b c) (d e f)
-            &[2, 6][..],
+            &[6, 2][..],
             // (g h) (i j k l m)
-            &[2, 7][..],
+            &[7, 2][..],
             // (n)
             &[1, 1][..],
             // (o) (p q) (r s)
-            &[3, 5][..],
+            &[5, 3][..],
             // (t u v w x y z)
-            &[1, 7][..],
+            &[7, 1][..],
 
             // [ (a b c) (d e f) ]
             // [ (g h) (i j k l m) ]
             // [ (n) ]
-            &[3, 5, 14][..],
+            &[14, 5, 3][..],
             // [ (o) (p q) (r s) ]
             // [ (t u v w x y z) ]
-            &[2, 4, 12][..],
+            &[12, 4, 2][..],
 
             // {
             //     [ (a b c) (d e f) ]
@@ -160,7 +160,7 @@ fn main() {
             //     [ (o) (p q) (r s) ]
             //     [ (t u v w x y z) ]
             // }
-            &[2, 5, 9, 26][..]
+            &[26, 9, 5, 2][..]
         ][..]
     );
 
@@ -170,31 +170,31 @@ fn main() {
             &[
                 $( $( $( $(
                     &[
-                        ${ignore(i)} ${length(3)},
-                        ${ignore(i)} ${length(2)},
-                        ${ignore(i)} ${length(1)},
-                        ${ignore(i)} ${length(0)},
+                        ${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(2)},
+                        ${ignore($i)} ${length(1)},
+                        ${ignore($i)} ${length(0)},
                     ][..],
                 )* )* )*
 
                 $( $(
                     &[
-                        ${ignore(i)} ${length(1)},
-                        ${ignore(i)} ${length(0)},
+                        ${ignore($i)} ${length(1)},
+                        ${ignore($i)} ${length(0)},
                     ][..],
                 )* )*
 
                 $(
                     &[
-                        ${ignore(i)} ${length(0)},
+                        ${ignore($i)} ${length(0)},
                     ][..],
                 )*
             ][..]
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
index d05cd1b31bc..950e70153ba 100644
--- 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
@@ -5,14 +5,14 @@
 /// Count the number of idents in a macro repetition.
 macro_rules! count_idents {
     ( $( $i:ident ),* ) => {
-        ${count(i)}
+        ${count($i)}
     };
 }
 
 /// Count the number of idents in a 2-dimensional macro repetition.
 macro_rules! count_idents_2 {
     ( $( [ $( $i:ident ),* ] ),* ) => {
-        ${count(i)}
+        ${count($i)}
     };
 }
 
@@ -21,17 +21,17 @@ macro_rules! count_depth_limits {
     ( $( { $( [ $( $outer:ident : ( $( $inner:ident )* ) )* ] )* } )* ) => {
         (
             (
-                ${count(inner)},
-                ${count(inner, 0)},
-                ${count(inner, 1)},
-                ${count(inner, 2)},
-                ${count(inner, 3)},
+                ${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)},
+                ${count($outer)},
+                ${count($outer, 0)},
+                ${count($outer, 1)},
+                ${count($outer, 2)},
             ),
         )
     };
@@ -43,7 +43,7 @@ macro_rules! count_depth_limits {
 /// repetition binding.
 macro_rules! enumerate_literals {
     ( $( ($l:stmt) ),* ) => {
-        [$( ${ignore(l)} (${index()}, ${length()}) ),*]
+        [$( ${ignore($l)} (${index()}, ${length()}) ),*]
     };
 }
 
@@ -77,7 +77,7 @@ macro_rules! make_count_adders {
         $(
             macro_rules! $i {
                 ( $$( $$j:ident ),* ) => {
-                    $b + $${count(j)}
+                    $b + $${count($j)}
                 };
             }
         )*
@@ -122,7 +122,7 @@ fn main() {
                 [ T: (t u v w x y z) ]
             }
         },
-        ((26, 2, 5, 9, 26), (9, 2, 5, 9))
+        ((26, 26, 9, 5, 2), (9, 9, 5, 2))
     );
     assert_eq!(enumerate_literals![("foo"), ("bar")], [(0, 2), (1, 2)]);
     assert_eq!(
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs
index 9cc572c23a1..3000bfed6a8 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.rs
@@ -1,7 +1,7 @@
 #![feature(macro_metavar_expr)]
 
 macro_rules! foo {
-    ( $( $($t:ident),* );* ) => { ${count(t,)} }
+    ( $( $($t:ident),* );* ) => { ${count($t,)} }
     //~^ ERROR `count` followed by a comma must have an associated
     //~| ERROR expected expression, found `$`
 }
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr
index e9317a5c347..fd53c1686cf 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/issue-111904.stderr
@@ -1,13 +1,13 @@
 error: `count` followed by a comma must have an associated index indicating its depth
   --> $DIR/issue-111904.rs:4:37
    |
-LL |     ( $( $($t:ident),* );* ) => { ${count(t,)} }
+LL |     ( $( $($t:ident),* );* ) => { ${count($t,)} }
    |                                     ^^^^^
 
 error: expected expression, found `$`
   --> $DIR/issue-111904.rs:4:35
    |
-LL |     ( $( $($t:ident),* );* ) => { ${count(t,)} }
+LL |     ( $( $($t:ident),* );* ) => { ${count($t,)} }
    |                                   ^ expected expression
 ...
 LL |     foo!(a, a; b, b);
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
index b954967c4fe..04924f0efa6 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
@@ -13,17 +13,17 @@ macro_rules! example {
     ( $( [ $( ( $( $x:ident )* ) )* ] )* ) => {
         Example {
             _indexes: &[],
-            _counts: &[${count(x, 0)}, ${count(x, 1)}, ${count(x, 2)}],
+            _counts: &[${count($x, 0)}, ${count($x, 1)}, ${count($x, 2)}],
             _nested: vec![
             $(
                 Example {
                     _indexes: &[(${index()}, ${length()})],
-                    _counts: &[${count(x, 0)}, ${count(x, 1)}],
+                    _counts: &[${count($x, 0)}, ${count($x, 1)}],
                     _nested: vec![
                     $(
                         Example {
                             _indexes: &[(${index(1)}, ${length(1)}), (${index()}, ${length()})],
-                            _counts: &[${count(x)}],
+                            _counts: &[${count($x)}],
                             _nested: vec![
                             $(
                                 Example {
@@ -34,7 +34,7 @@ macro_rules! example {
                                     ],
                                     _counts: &[],
                                     _nested: vec![],
-                                    ${ignore(x)}
+                                    ${ignore($x)}
                                 }
                             ),*
                             ]
@@ -49,9 +49,9 @@ macro_rules! example {
 }
 
 static EXPECTED: &str = concat!(
-    "Example { _indexes: [], _counts: [2, 4, 13], _nested: [",
+    "Example { _indexes: [], _counts: [13, 4, 2], _nested: [",
     concat!(
-        "Example { _indexes: [(0, 2)], _counts: [3, 10], _nested: [",
+        "Example { _indexes: [(0, 2)], _counts: [10, 3], _nested: [",
         concat!(
             "Example { _indexes: [(0, 2), (0, 3)], _counts: [4], _nested: [",
             concat!(
@@ -77,7 +77,7 @@ static EXPECTED: &str = concat!(
             "] }",
         ),
         "] }, ",
-        "Example { _indexes: [(1, 2)], _counts: [1, 3], _nested: [",
+        "Example { _indexes: [(1, 2)], _counts: [3, 1], _nested: [",
         concat!(
             "Example { _indexes: [(1, 2), (0, 1)], _counts: [3], _nested: [",
             concat!(
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
index 6a0d68bd6b1..d195506af36 100644
--- 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
@@ -3,9 +3,9 @@
 macro_rules! a {
     ( $( { $( [ $( ( $( $foo:ident )* ) )* ] )* } )* ) => {
         (
-            ${count(foo, 0)},
-            ${count(foo, 10)},
-            //~^ ERROR depth parameter on meta-variable expression `count` must be less than 4
+            ${count($foo, 0)},
+            ${count($foo, 10)},
+            //~^ ERROR depth parameter of meta-variable expression `count` must be less than 4
         )
     };
 }
@@ -14,10 +14,10 @@ macro_rules! b {
     ( $( { $( [ $( $foo:ident )* ] )* } )* ) => {
         (
             $( $( $(
-                ${ignore(foo)}
+                ${ignore($foo)}
                 ${index(0)},
                 ${index(10)},
-                //~^ ERROR depth parameter on meta-variable expression `index` must be less than 3
+                //~^ ERROR depth parameter of meta-variable expression `index` must be less than 3
             )* )* )*
         )
     };
@@ -27,10 +27,10 @@ macro_rules! c {
     ( $( { $( $foo:ident )* } )* ) => {
         (
             $( $(
-                ${ignore(foo)}
+                ${ignore($foo)}
                 ${length(0)}
                 ${length(10)}
-                //~^ ERROR depth parameter on meta-variable expression `length` must be less than 2
+                //~^ ERROR depth parameter of meta-variable expression `length` must be less than 2
             )* )*
         )
     };
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
index 236122b6465..f757b8af219 100644
--- 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
@@ -1,16 +1,16 @@
-error: depth parameter on meta-variable expression `count` must be less than 4
+error: depth parameter of meta-variable expression `count` must be less than 4
   --> $DIR/out-of-bounds-arguments.rs:7:14
    |
-LL |             ${count(foo, 10)},
-   |              ^^^^^^^^^^^^^^^^
+LL |             ${count($foo, 10)},
+   |              ^^^^^^^^^^^^^^^^^
 
-error: depth parameter on meta-variable expression `index` must be less than 3
+error: depth parameter of 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
+error: depth parameter of meta-variable expression `length` must be less than 2
   --> $DIR/out-of-bounds-arguments.rs:32:18
    |
 LL |                 ${length(10)}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
index b4fef11f1e2..53d045700f9 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
@@ -1,6 +1,6 @@
 macro_rules! count {
     ( $( $e:stmt ),* ) => {
-        ${ count(e) }
+        ${ count($e) }
         //~^ ERROR meta-variable expressions are unstable
     };
 }
@@ -19,7 +19,7 @@ macro_rules! dollar_dollar {
 
 macro_rules! index {
     ( $( $e:stmt ),* ) => {
-        $( ${ignore(e)} ${index()} )*
+        $( ${ignore($e)} ${index()} )*
         //~^ ERROR meta-variable expressions are unstable
         //~| ERROR meta-variable expressions are unstable
     };
@@ -27,14 +27,14 @@ macro_rules! index {
 
 macro_rules! ignore {
     ( $( $i:stmt ),* ) => {{
-        0 $( + 1 ${ignore(i)} )*
+        0 $( + 1 ${ignore($i)} )*
         //~^ ERROR meta-variable expressions are unstable
     }};
 }
 
 macro_rules! length {
     ( $( $e:stmt ),* ) => {
-        $( ${ignore(e)} ${length()} )*
+        $( ${ignore($e)} ${length()} )*
         //~^ ERROR meta-variable expressions are unstable
         //~| ERROR meta-variable expressions are unstable
     };
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
index ecf598b104d..2c2cbb15b72 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
@@ -1,8 +1,8 @@
 error[E0658]: meta-variable expressions are unstable
   --> $DIR/required-feature.rs:3:10
    |
-LL |         ${ count(e) }
-   |          ^^^^^^^^^^^^
+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
@@ -46,17 +46,17 @@ LL |             ( $$( $$any:tt )* ) => { $$( $$any )* };
 error[E0658]: meta-variable expressions are unstable
   --> $DIR/required-feature.rs:22:13
    |
-LL |         $( ${ignore(e)} ${index()} )*
-   |             ^^^^^^^^^^^
+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
+  --> $DIR/required-feature.rs:22:27
    |
-LL |         $( ${ignore(e)} ${index()} )*
-   |                          ^^^^^^^^^
+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
@@ -64,8 +64,8 @@ LL |         $( ${ignore(e)} ${index()} )*
 error[E0658]: meta-variable expressions are unstable
   --> $DIR/required-feature.rs:30:19
    |
-LL |         0 $( + 1 ${ignore(i)} )*
-   |                   ^^^^^^^^^^^
+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
@@ -73,17 +73,17 @@ LL |         0 $( + 1 ${ignore(i)} )*
 error[E0658]: meta-variable expressions are unstable
   --> $DIR/required-feature.rs:37:13
    |
-LL |         $( ${ignore(e)} ${length()} )*
-   |             ^^^^^^^^^^^
+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
+  --> $DIR/required-feature.rs:37:27
    |
-LL |         $( ${ignore(e)} ${length()} )*
-   |                          ^^^^^^^^^^
+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
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
index fdf16442d2a..05c65fe8690 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
@@ -5,24 +5,17 @@
 // `round` = Left hand side round brackets
 
 macro_rules! curly__no_rhs_dollar__round {
-    ( $( $i:ident ),* ) => { ${ count(i) } };
+    ( $( $i:ident ),* ) => { ${ count($i) } };
 }
 
 macro_rules! curly__no_rhs_dollar__no_round {
-    ( $i:ident ) => { ${ count(i) } };
+    ( $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 `$`
+    //~^ ERROR `count` can not be placed inside the inner-most repetition
 }
 
 macro_rules! no_curly__no_rhs_dollar__round {
@@ -60,16 +53,16 @@ macro_rules! extra_garbage_after_metavar {
         ${count() a b c}
         //~^ ERROR unexpected token: a
         //~| ERROR expected expression, found `$`
-        ${count(i a b c)}
+        ${count($i a b c)}
         //~^ ERROR unexpected token: a
-        ${count(i, 1 a b c)}
+        ${count($i, 1 a b c)}
         //~^ ERROR unexpected token: a
-        ${count(i) a b c}
+        ${count($i) a b c}
         //~^ ERROR unexpected token: a
 
-        ${ignore(i) a b c}
+        ${ignore($i) a b c}
         //~^ ERROR unexpected token: a
-        ${ignore(i a b c)}
+        ${ignore($i a b c)}
         //~^ ERROR unexpected token: a
 
         ${index() a b c}
@@ -100,8 +93,8 @@ macro_rules! metavar_in_the_lhs {
 
 macro_rules! metavar_token_without_ident {
     ( $( $i:ident ),* ) => { ${ ignore() } };
-    //~^ ERROR expected identifier
-    //~| ERROR expected expression, found `$`
+    //~^ ERROR meta-variable expressions must be referenced using a dollar sign
+    //~| ERROR expected expression
 }
 
 macro_rules! metavar_with_literal_suffix {
@@ -125,14 +118,16 @@ macro_rules! open_brackets_without_tokens {
 macro_rules! unknown_count_ident {
     ( $( $i:ident )* ) => {
         ${count(foo)}
-        //~^ ERROR variable `foo` is not recognized in meta-variable expression
+        //~^ ERROR meta-variable expressions must be referenced using a dollar sign
+        //~| ERROR expected expression
     };
 }
 
 macro_rules! unknown_ignore_ident {
     ( $( $i:ident )* ) => {
         ${ignore(bar)}
-        //~^ ERROR variable `bar` is not recognized in meta-variable expression
+        //~^ ERROR meta-variable expressions must be referenced using a dollar sign
+        //~| ERROR expected expression
     };
 }
 
@@ -145,7 +140,6 @@ macro_rules! unknown_metavar {
 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);
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
index a6cff95fd91..0dda38290ab 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -1,197 +1,197 @@
-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
+  --> $DIR/syntax-errors.rs:46:8
    |
 LL |     ( $$ $a:ident ) => {
    |        ^
 
 note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
-  --> $DIR/syntax-errors.rs:53:8
+  --> $DIR/syntax-errors.rs:46:8
    |
 LL |     ( $$ $a:ident ) => {
    |        ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:60:19
+  --> $DIR/syntax-errors.rs:53:19
    |
 LL |         ${count() a b c}
    |                   ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:60:19
+  --> $DIR/syntax-errors.rs:53:19
    |
 LL |         ${count() a b c}
    |                   ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:63:19
+  --> $DIR/syntax-errors.rs:56:20
    |
-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}
+LL |         ${count($i a b c)}
    |                    ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:67:20
+  --> $DIR/syntax-errors.rs:56:20
    |
-LL |         ${count(i) a b c}
+LL |         ${count($i a b c)}
    |                    ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:70:21
+  --> $DIR/syntax-errors.rs:58:23
    |
-LL |         ${ignore(i) a b c}
+LL |         ${count($i, 1 a b c)}
+   |                       ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:58:23
+   |
+LL |         ${count($i, 1 a b c)}
+   |                       ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:60:21
+   |
+LL |         ${count($i) a b c}
    |                     ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:70:21
+  --> $DIR/syntax-errors.rs:60:21
    |
-LL |         ${ignore(i) a b c}
+LL |         ${count($i) a b c}
    |                     ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:72:20
+  --> $DIR/syntax-errors.rs:63:22
    |
-LL |         ${ignore(i a b c)}
-   |                    ^
+LL |         ${ignore($i) a b c}
+   |                      ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:72:20
+  --> $DIR/syntax-errors.rs:63:22
    |
-LL |         ${ignore(i a b c)}
-   |                    ^
+LL |         ${ignore($i) a b c}
+   |                      ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:65:21
+   |
+LL |         ${ignore($i a b c)}
+   |                     ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:65:21
+   |
+LL |         ${ignore($i a b c)}
+   |                     ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:68:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:68:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:70:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:70:19
+   |
+LL |         ${index(1 a b c)}
+   |                   ^
+
+error: unexpected token: a
+  --> $DIR/syntax-errors.rs:73:19
+   |
+LL |         ${index() a b c}
+   |                   ^
+   |
+note: meta-variable expression must not have trailing tokens
+  --> $DIR/syntax-errors.rs:73:19
+   |
+LL |         ${index() a b c}
+   |                   ^
 
 error: unexpected token: a
   --> $DIR/syntax-errors.rs:75:19
    |
-LL |         ${index() a b c}
+LL |         ${index(1 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
+  --> $DIR/syntax-errors.rs:82:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
    |                                 ^^^^^
 
 error: unexpected token: {
-  --> $DIR/syntax-errors.rs:95:8
+  --> $DIR/syntax-errors.rs:88:8
    |
 LL |     ( ${ length() } ) => {
    |        ^^^^^^^^^^^^
 
 note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
-  --> $DIR/syntax-errors.rs:95:8
+  --> $DIR/syntax-errors.rs:88:8
    |
 LL |     ( ${ length() } ) => {
    |        ^^^^^^^^^^^^
 
 error: expected one of: `*`, `+`, or `?`
-  --> $DIR/syntax-errors.rs:95:8
+  --> $DIR/syntax-errors.rs:88:8
    |
 LL |     ( ${ length() } ) => {
    |        ^^^^^^^^^^^^
 
-error: expected identifier
-  --> $DIR/syntax-errors.rs:102:33
+error: meta-variables within meta-variable expressions must be referenced using a dollar sign
+  --> $DIR/syntax-errors.rs:95:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
    |                                 ^^^^^^
 
 error: only unsuffixes integer literals are supported in meta-variable expressions
-  --> $DIR/syntax-errors.rs:108:33
+  --> $DIR/syntax-errors.rs:101:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
    |                                 ^^^^^
 
 error: meta-variable expression parameter must be wrapped in parentheses
-  --> $DIR/syntax-errors.rs:114:33
+  --> $DIR/syntax-errors.rs:107:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
    |                                 ^^^^^
 
 error: expected identifier
-  --> $DIR/syntax-errors.rs:120:31
+  --> $DIR/syntax-errors.rs:113:31
    |
 LL |     ( $( $i:ident ),* ) => { ${ {} } };
    |                               ^^^^^^
 
+error: meta-variables within meta-variable expressions must be referenced using a dollar sign
+  --> $DIR/syntax-errors.rs:120:11
+   |
+LL |         ${count(foo)}
+   |           ^^^^^
+
+error: meta-variables within meta-variable expressions must be referenced using a dollar sign
+  --> $DIR/syntax-errors.rs:128:11
+   |
+LL |         ${ignore(bar)}
+   |           ^^^^^^
+
 error: unrecognized meta-variable expression
-  --> $DIR/syntax-errors.rs:140:33
+  --> $DIR/syntax-errors.rs:135:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
    |                                 ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length
@@ -199,39 +199,23 @@ LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
 error: `count` can not be placed inside the inner-most repetition
   --> $DIR/syntax-errors.rs:12:24
    |
-LL |     ( $i:ident ) => { ${ count(i) } };
-   |                        ^^^^^^^^^^^^
+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
+error: `count` can not be placed inside the inner-most repetition
+  --> $DIR/syntax-errors.rs:17:24
    |
 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
+  --> $DIR/syntax-errors.rs:34:36
    |
 LL |     ( $( $i:ident ),* ) => { count($i) };
    |                                    ^^
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:60:9
+  --> $DIR/syntax-errors.rs:53:9
    |
 LL |         ${count() a b c}
    |         ^ expected expression
@@ -242,7 +226,7 @@ LL |     extra_garbage_after_metavar!(a);
    = 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
+  --> $DIR/syntax-errors.rs:82:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
    |                              ^ expected expression
@@ -253,7 +237,7 @@ LL |     metavar_depth_is_not_literal!(a);
    = 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
+  --> $DIR/syntax-errors.rs:95:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
    |                              ^ expected expression
@@ -264,7 +248,7 @@ LL |     metavar_token_without_ident!(a);
    = 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
+  --> $DIR/syntax-errors.rs:101:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
    |                              ^ expected expression
@@ -275,7 +259,7 @@ LL |     metavar_with_literal_suffix!(a);
    = 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
+  --> $DIR/syntax-errors.rs:107:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
    |                              ^ expected expression
@@ -286,7 +270,7 @@ LL |     metavar_without_parens!(a);
    = 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
+  --> $DIR/syntax-errors.rs:113:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ {} } };
    |                              ^ expected expression
@@ -296,20 +280,30 @@ LL |     open_brackets_without_tokens!(a);
    |
    = 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
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:120:9
    |
 LL |         ${count(foo)}
-   |                 ^^^
-
-error: variable `bar` is not recognized in meta-variable expression
-  --> $DIR/syntax-errors.rs:134:18
+   |         ^ expected expression
+...
+LL |     unknown_count_ident!(a);
+   |     ----------------------- in this macro invocation
    |
-LL |         ${ignore(bar)}
-   |                  ^^^
+   = note: this error originates in the macro `unknown_count_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:140:30
+  --> $DIR/syntax-errors.rs:128:9
+   |
+LL |         ${ignore(bar)}
+   |         ^ expected expression
+...
+LL |     unknown_ignore_ident!(a);
+   |     ------------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `unknown_ignore_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected expression, found `$`
+  --> $DIR/syntax-errors.rs:135:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
    |                              ^ expected expression
@@ -320,7 +314,7 @@ LL |     unknown_metavar!(a);
    = 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
+  --> $DIR/syntax-errors.rs:22:36
    |
 LL |     ( $( $i:ident ),* ) => { count(i) };
    |                                    ^ not found in this scope
@@ -331,7 +325,7 @@ LL |     no_curly__no_rhs_dollar__round!(a, b, c);
    = 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
+  --> $DIR/syntax-errors.rs:28:29
    |
 LL |     ( $i:ident ) => { count(i) };
    |                             ^ not found in this scope
@@ -342,13 +336,13 @@ LL |     no_curly__no_rhs_dollar__no_round!(a);
    = 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
+  --> $DIR/syntax-errors.rs:147: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
+  --> $DIR/syntax-errors.rs:22:30
    |
 LL |     ( $( $i:ident ),* ) => { count(i) };
    |                              ^^^^^ not found in this scope
@@ -359,7 +353,7 @@ LL |     no_curly__no_rhs_dollar__round!(a, b, c);
    = 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
+  --> $DIR/syntax-errors.rs:28:23
    |
 LL |     ( $i:ident ) => { count(i) };
    |                       ^^^^^ not found in this scope
@@ -370,7 +364,7 @@ LL |     no_curly__no_rhs_dollar__no_round!(a);
    = 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
+  --> $DIR/syntax-errors.rs:39:23
    |
 LL |     ( $i:ident ) => { count($i) };
    |                       ^^^^^ not found in this scope
@@ -380,6 +374,6 @@ LL |     no_curly__rhs_dollar__no_round!(a);
    |
    = 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
+error: aborting due to 39 previous errors
 
 For more information about this error, try `rustc --explain E0425`.