Macros Code Review
Review Workflow
- Check
Cargo.toml -- Note Rust edition (2024 reserves gen keyword, affecting macro output), proc-macro crate dependencies (syn, quote, proc-macro2), and feature flags (e.g., syn with minimal features)
- Check macro type -- Determine if reviewing declarative (
macro_rules!), function-like proc macro, attribute macro, or derive macro
- Check if a macro is needed -- If the transformation is type-based, generics are better. Macros are for structural/repetitive code generation that generics cannot express
- Scan macro definitions -- Read full macro bodies including all match arms, not just the invocation site
- Check each category -- Work through the checklist below, loading references as needed
- Gates -- Complete Gates below before reporting; do not substitute informal “I verified.”
Gates (before reporting findings)
Complete in order. Do not emit findings until Gate 4 passes for each issue.
Gate 1 — Crate context (on disk)
PASS when: You opened the reviewed crate’s Cargo.toml (workspace member path if applicable) and recorded Rust edition, whether the crate is proc-macro = true, and relevant proc-macro dependencies or syn / quote feature flags.
Blocks rationalization: Edition 2024 findings (gen, unsafe extern, generated unsafe bodies) and syn “full” vs minimal flags require this — do not flag edition-specific macro output without matching edition from the file.
Gate 2 — Macro definitions read
PASS when: For every macro you critique, you read the full definition (all macro_rules! arms, or the proc-macro entry plus helpers you rely on), not only call sites or partial expansions.
Artifact: At least one path per macro to the defining .rs file(s) you used.
Gate 3 — Per-finding evidence
PASS when: Each planned issue has [FILE:LINE] from the current tree for the macro definition, attribute/derive site, or generated code location you are discussing (not from memory, docs-only, or another branch).
Gate 4 — Pre-report protocol
PASS when: You loaded and applied beagle-rust:review-verification-protocol, including Macro-Specific Verification for hygiene, fragment type, and proc-macro performance claims. Then add findings.
Output Format
Report findings as:
[FILE:LINE] ISSUE_TITLE
Severity: Critical | Major | Minor | Informational
Description of the issue and why it matters.
Quick Reference
Review Checklist
Declarative Macros (macro_rules!)
Procedural Macros
Derive Macros
Attribute Macros
Edition 2024 Awareness
Generics vs Macros
Flag a macro when the same result is achievable with generics or trait bounds. Macros are appropriate when:
- The generated code varies structurally (not just by type)
- Repetitive trait impls for many concrete types
- Test batteries with configuration variants
- Compile-time computation that
const fn cannot express
Severity Calibration
Critical (Block Merge)
- Macro generates unsound
unsafe code
- Hygiene violation in macro that outputs
unsafe blocks (caller's variables leak into unsafe context)
- Proc macro panics instead of returning
compile_error! (crashes the compiler)
- Derive macro generates incorrect trait implementation (violates trait contract)
Major (Should Fix)
- Exported macro uses
crate:: or self:: instead of $crate:: (breaks for downstream users)
- Exported macro uses
::std:: instead of ::core::/::alloc:: (breaks no_std users)
- Wrong fragment type causing unexpected parsing (
:expr where :tt needed, or vice versa)
- Proc macro enables
syn full features unnecessarily (compile time cost)
- Missing span propagation (errors point to macro definition, not invocation)
- No error handling in proc macro (panics on bad input instead of
compile_error!)
Minor (Consider Fixing)
- Missing trailing comma/semicolon tolerance in repetition patterns
- Matcher arms not ordered most-specific-first
- Macro used where generics would be clearer and equally expressive
- Missing
compile_error! fallback arm for invalid patterns
- Helper attributes undocumented
Informational (Note Only)
- Suggestions to split complex
macro_rules! into a proc macro
- Suggestions to reduce generated code volume
- TT munching or push-down accumulation patterns that could be simplified
Valid Patterns (Do NOT Flag)
macro_rules! for test batteries -- Generating repetitive test modules from a list of types/configs
macro_rules! for trait impls -- Implementing a trait for many concrete types with identical bodies
- TT munching -- Valid advanced pattern for recursive token processing
- Push-down accumulation -- Valid pattern for building output incrementally across recursive calls
#[macro_export] with $crate -- Correct way to make macros usable outside the defining crate
Span::call_site() for generated functions -- Intentionally making generated items visible to callers
syn::Error::to_compile_error() -- Correct error reporting pattern in proc macros
trybuild tests for proc macros -- Standard compile-fail testing approach
- Attribute macros on test functions -- Common pattern for test setup/teardown
compile_error! in impossible match arms -- Good practice for catching invalid macro input