Macros

Fragment Specifiers

A fragment specifier (also called a designator) is the type tag after the colon in a macro_rules! metavariable ($name:specifier) that tells the Rust parser which grammatical construct to match and capture.

Complete Reference of macro_rules! Fragment Specifiers

Specifier What It Matches Example Input Tokens
expr Any valid Rust expression (Edition 2024 includes const { ... } and _) 2 + 2, foo(x), if c { 1 } else { 2 }
expr_2021 Expression using pre-2024 rules (excludes standalone const / _ expressions) 2 + 2, vec.len()
ident An identifier or keyword foo, Point, self, r#type
ty A type expression i32, Vec<String>, &'a [u8], impl Send
pat Any pattern (including top-level | or-patterns in 2021/2024) Some(x), 1 | 2 | 3, (a, _)
pat_param A single pattern excluding top-level | (allows | as a delimiter after it) Some(x), (a, b)
stmt A single statement without its trailing semicolon (except item statements) let x = 5, x += 1
block A brace-delimited block expression { let a = 1; a + 2 }
item A module-level or associated item fn f() {}, struct S;, use std::io;
meta The contents inside an attribute #[...] derive(Debug), allow(dead_code)
path A Type::Style path std::collections::HashMap, crate::util::run
literal Any literal expression (including negative numbers like -42) "hello", 42, -3.14, 'a', true
lifetime A lifetime token 'a, 'static, '_
vis An optional visibility qualifier (matches empty tokens if omitted!) pub, pub(crate), pub(super), (empty)
tt A single Token Tree: one identifier, literal, punctuation, or balanced (...) / [...] / {...} group +, foo, (a + b * c)

Using vis, ident, ty, and expr Together

Notice that $v:vis is always optional—it matches pub, pub(crate), or nothing at all (0 tokens) when the caller omits visibility:

macro_rules! make_getter {
    ($v:vis $field:ident : $t:ty = $default:expr) => {
        struct Config {
            $field: $t,
        }

        impl Config {
            $v fn $field(&self) -> &$t {
                &self.$field
            }
        }
    };
}

make_getter!(pub max_connections: usize = 128);

fn main() {
    let cfg = Config {
        max_connections: 256,
    };
    println!("max_connections = {}", cfg.max_connections());
}
max_connections = 256

Opaque AST Capture Rule (Cannot Re-Match a Non-tt Fragment)

Once tokens are captured as a structured AST fragment like $e:expr, $t:ty, or $p:pat, they are sealed into an opaque AST node. If you forward $e to another macro rule, that second rule can only match $e as $other:expr or $other:tt—it cannot destructure $e back into individual tokens ($a:ident + $b:ident). If a helper macro needs to inspect raw tokens recursively, capture them as $t:tt first.