coverage: Attribute macro-generated function bodies to their invocation site - #158833
coverage: Attribute macro-generated function bodies to their invocation site#158833alex wants to merge 2 commits into
Conversation
…on site Functions whose bodies are entirely proc-macro-generated (e.g. the impls from a `#[derive(...)]` macro) have every statement span pointing at the macro invocation site, because proc-macro output tokens get call-site spans. Before Rust 1.84, the empty invocation-site spans that survived span refinement were widened by one column, so the invocation line reported the generated code's execution count via the entry counter. PR rust-lang#132675 (1.84) restricted that widening to spans adjacent to '{' or '}', which as a side effect left such functions either completely uninstrumented, or with a single leftover sliver region wired to an arbitrary non-entry counter that reads 0 even when the function runs. Restore the pre-1.84 semantics deliberately: when a function body is entirely macro-expanded and its spans point back into the invocation site (distinguishing proc-macro output from `macro_rules!` definition-site tokens, which normal refinement still handles), emit a single code region over the visible invocation site - the derive-macro path, the attribute, or `name!` - wired to the function's entry counter. Never-called generated functions get the same region as an unused-function mapping (count 0); executed siblings from the same invocation share the span, so llvm-cov's aggregation covers the line. `#[automatically_derived]` impls remain uninstrumented, as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
r? @wesleywiser rustbot has assigned @wesleywiser. Use Why was this reviewer chosen?The reviewer was selected based on:
|
|
|
@rustbot reroll |
Review feedback: `extract_refined_covspans` already has an `ExpnTree` whose nodes cache each expansion's kind, call site, and parent context, so walk that tree instead of re-deriving the same data from `outer_expn_data()`. Also drops the explicit dummy-span check (the tree already stores dummy call sites as `None`) and unwraps `macro_kind`, since the loop cannot exit without seeing at least one macro expansion. No functional change intended; coverage test snapshots are unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
If I understand the Rust LLM contribution policy, does this need to be closed (it was developed by/in conjunction with Claude)? |
|
We're explicitly not retconning the rules. To avoid it landing in reroll-hell, maybe still check in the #llm-mentoring stream if there is a reviewer who knows about this area willing to review it |
|
It’s difficult to accept ad-hoc special cases in this area of code, even if they improve coverage output, because they impose steep costs on more fundamental improvements to how macro expansions are handled. |
|
@Zalathar That's a comment about the nature of the PR itself (special casing macro-generated code), not LLMs, is that right? Assuming I'm understanding correctly, it sounds like this is wontfix until the more fundamental improvements occur? If that's right, I guess the thing for me to do is close this, and turn it into an issue so this doesn't get lost -- is there a place to follow (or even help) with the blocking work? |
|
r? Zalathar |
|
|
Functions whose bodies are entirely proc-macro-generated (e.g. the impls from a
#[derive(...)]macro) have every statement span pointing at the macro invocation site, because proc-macro output tokens get call-site spans.Before Rust 1.84, the empty invocation-site spans that survived span refinement were widened by one column, so the invocation line reported the generated code's execution count via the entry counter. PR #132675 (1.84) restricted that widening to spans adjacent to '{' or '}', which as a side effect left such functions either completely uninstrumented, or with a single leftover sliver region wired to an arbitrary non-entry counter that reads 0 even when the function runs.
Restore the pre-1.84 semantics deliberately: when a function body is entirely macro-expanded and its spans point back into the invocation site (distinguishing proc-macro output from
macro_rules!definition-site tokens, which normal refinement still handles), emit a single code region over the visible invocation site - the derive-macro path, the attribute, orname!- wired to the function's entry counter.Never-called generated functions get the same region as an unused-function mapping (count 0); executed siblings from the same invocation share the span, so llvm-cov's aggregation covers the line.
#[automatically_derived]impls remain uninstrumented, as before.