Matchers and fragment specifiers¶
Level: 301 · deep dive
One line: A rule's left side is a pattern over tokens — $name:expr, $name:ident, $name:tt and twelve other fragment specifiers — and rules are tried top to bottom, with the first one that matches doing the expansion.
Stub — an outline, not a lesson. There is no runnable example behind this page yet, so nothing on it has been through the check that backs every other claim in this library. The bullets below are the questions the finished page has to answer.
What it has to cover¶
- The fifteen fragment specifiers the Reference lists for 1.98.0 —
block,expr,expr_2021,ident,item,lifetime,literal,meta,pat,pat_param,path,stmt,tt,ty,vis— each with one call it accepts and one it refuses ttas the escape hatch: one token or one bracketed group. Once a fragment is forwarded to a second macro it is opaque, and onlyident,lifetimeandttcan still be matched there by literal tokens- Order decides: with
($i:ident)above($e:expr),kind!(x)takes theidentrule; swap the two rules andexprclaimsx. Nothing warns about the rule that can no longer fire —unused_macro_rulesis allow-by-default - A rule that starts parsing a fragment commits to it: against
($e:expr)then($a:tt +), the callm!(1 +)fails withexpected expression, found end of macro argumentsand the second rule is never tried - Follow-set restrictions:
exprandstmtmay be followed only by=>,,or;,tyandpathby a longer list — what does rustc say about a matcher like$a:expr $b:expr, and why is the rule there at all? - Edition 2024 widened
exprto match_andconst { … }: the same macro printsconst block/underscoreunder--edition 2021andexpr/exprunder 2024.expr_2021keeps the old meaning, and the allow-by-defaultedition_2024_expr_fragment_specifierlint (in therust-2024-compatibilitygroup) flags the matchers that change - The
ttmuncher: a rule that takes$head:tt $($tail:tt)*and recurses on the tail. Counting 150 tokens that way hitsrecursion limit reached while expandingwith a hint to add#![recursion_limit = "256"]— what does the limit cost to raise?
The trap it exists for¶
Putting the general rule first. ($e:expr) above ($i:ident) swallows every identifier, the ident rule is dead, and the default lints say nothing. A match over values would have warned about an unreachable arm; a list of macro rules does not.
Where this sits¶
Pattern matching is patterns over values, where exhaustiveness is checked and unreachable_patterns warns by default. This page is patterns over tokens, where neither check runs. Repetition owns $( … )*; this page covers a single fragment and the choice between rules.
See also¶
matchexpressions — first match wins there too, with checks this page does not get- Pattern matching — what a pattern is when the input is a value
- Repetition — matching a list of fragments
- Expanding a macro —
trace_macros!for watching which rule fired - Macros by example: metavariables ↗ — the Reference's specifier list and the follow-set rules below it
- Edition guide: macro fragment specifiers ↗ — the 2024 change to
expr - The Little Book of Rust Macros: incremental TT munchers ↗ — the recursion pattern in full
If you are coming from another language¶
- C. A function-like
#definehas exactly one pattern: a fixed list of parameter names, or..., each argument a comma-separated run of tokens. Rust adds typed fragments and several rules per macro, so a malformed argument is refused at the call —no rules expectedthe offending token — instead of expanding into broken code somewhere downstream. - Python. A
matchstatement'scaseclauses are tried top to bottom and the first match wins, as macro rules are. The difference is timing and input: Python matches values at run time, a macro matches source tokens at compile time.
Po polsku¶
Lewa strona reguły macro_rules! to wzorzec dopasowywany do tokenów, a nie wartości: $x:expr oznacza „tu ma stać wyrażenie”, $x:ident — identyfikator, $x:tt — dowolne drzewo tokenów (token tree). Reguły sprawdzane są od góry, wygrywa pierwsza pasująca, a kompilator — inaczej niż przy match — nie ostrzeże, że ogólna reguła postawiona wyżej zasłania szczegółową. Edycja 2024 poszerzyła expr o _ i const { … }; stare zachowanie daje expr_2021.
Szukaj po polsku: wzorce w makrach · specyfikatory fragmentów · rust macro fragment specifier list · rust tt muncher · expr_2021 edition 2024