Problem
The inline codegen in meta_graph.rs uses several "magic" identifiers that are internal to the generated code: __dfir_work_done, __dfir_metrics, and potentially others. These are referenced across multiple quote! and quote_spanned! blocks throughout the codegen.
When these identifiers appear inside quote_spanned! {some_user_span=> ...}, they inherit the user-provided span. This causes macro hygiene failures when dfir_syntax! is invoked indirectly through a declarative macro (e.g. dfir_expect_warnings!), because the user tokens have a different hygiene context and the generated identifiers can't resolve to the variables defined in the outer quote! scope.
We hit this in #2779 — dfir_expect_warnings! passes user code as a tt to dfir_syntax_noemit!, which changes the hygiene context. The fix was to create __dfir_work_done and __dfir_metrics with explicit Span::call_site() at the one call site that used quote_spanned!.
Proposed improvement
Define all internal codegen identifiers once at the top of the codegen function using Ident::new("...", Span::call_site()), then substitute them as #ident everywhere:
let work_done_ident = Ident::new("__dfir_work_done", Span::call_site());
let metrics_ident = Ident::new("__dfir_metrics", Span::call_site());
let wake_state_ident = Ident::new("__dfir_wake_state", Span::call_site());
// ... etc
Then use #work_done_ident and #metrics_ident in all quote!/quote_spanned! blocks instead of bare __dfir_work_done/__dfir_metrics.
This ensures:
- Hygiene correctness by construction — every reference to an internal identifier gets
Span::call_site(), so it always resolves in the proc macro's output context regardless of how the input tokens arrive.
- Single source of truth — if an identifier name needs to change, it's updated in one place.
- No future regressions — new
quote_spanned! blocks can't accidentally introduce bare identifiers that inherit user spans.
Context
Problem
The inline codegen in
meta_graph.rsuses several "magic" identifiers that are internal to the generated code:__dfir_work_done,__dfir_metrics, and potentially others. These are referenced across multiplequote!andquote_spanned!blocks throughout the codegen.When these identifiers appear inside
quote_spanned! {some_user_span=> ...}, they inherit the user-provided span. This causes macro hygiene failures whendfir_syntax!is invoked indirectly through a declarative macro (e.g.dfir_expect_warnings!), because the user tokens have a different hygiene context and the generated identifiers can't resolve to the variables defined in the outerquote!scope.We hit this in #2779 —
dfir_expect_warnings!passes user code as atttodfir_syntax_noemit!, which changes the hygiene context. The fix was to create__dfir_work_doneand__dfir_metricswith explicitSpan::call_site()at the one call site that usedquote_spanned!.Proposed improvement
Define all internal codegen identifiers once at the top of the codegen function using
Ident::new("...", Span::call_site()), then substitute them as#identeverywhere:Then use
#work_done_identand#metrics_identin allquote!/quote_spanned!blocks instead of bare__dfir_work_done/__dfir_metrics.This ensures:
Span::call_site(), so it always resolves in the proc macro's output context regardless of how the input tokens arrive.quote_spanned!blocks can't accidentally introduce bare identifiers that inherit user spans.Context
dfir_syntax!to inline codegen, begin removing scheduled DFIR [ci-bench] #2779dfir_lang/src/graph/meta_graph.rs(theas_code_inlinecodegen path)