Skip to content

Fix tracing::instrument async block coverage - #158276

Open
xd009642 wants to merge 1 commit into
rust-lang:mainfrom
xd009642:async_instr_coverage_fix
Open

Fix tracing::instrument async block coverage#158276
xd009642 wants to merge 1 commit into
rust-lang:mainfrom
xd009642:async_instr_coverage_fix

Conversation

@xd009642

@xd009642 xd009642 commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Fixes #131119 (or tries to...)

Using tracing::instrument code such as:

  #[tracing::instrument]
  pub async fn fetch(id: u64) -> Result<String, Error> {
      let row = db_get(id).await?;
      Ok(row.name)
  }

Often results in functions with no coverage counters.

Using the following MRE:

use tracing::instrument;

pub async fn plain_async_branch(value: u8) -> &'static str {
    if value.is_multiple_of(2) {
        "plain even"
    } else {
        "plain odd"
    }
}

#[tracing::instrument]
pub fn instrumented_sync_branch(value: u8) -> &'static str {
    if value.is_multiple_of(2) {
        "sync even"
    } else {
        "sync odd"
    }
}

#[tracing::instrument]
pub async fn instrumented_async_branch(value: u8) -> &'static str {
    if value.is_multiple_of(2) {
        "async even"
    } else {
        "async odd"
    }
}

mod tests {
    use super::*;

    #[tokio::test]
    async fn plain_async_branch_reports_coverage() {
        assert_eq!(plain_async_branch(2).await, "plain even");
        assert_eq!(plain_async_branch(3).await, "plain odd");
    }

    #[test]
    fn instrumented_sync_branch_reports_coverage() {
        assert_eq!(instrumented_sync_branch(2), "sync even");
        assert_eq!(instrumented_sync_branch(3), "sync odd");
    }

    #[tokio::test]
    async fn instrumented_async_branch_reports_coverage() {
        assert_eq!(instrumented_async_branch(2).await, "async even");
        assert_eq!(instrumented_async_branch(3).await, "async odd");
    }
}

That was all wrong, a new approach has been done! It seems it was caused by looking at the wrong place in the macro expansion tree

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 23, 2026
@xd009642
xd009642 marked this pull request as ready for review June 23, 2026 00:06
@rustbot

rustbot commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Some changes occurred in coverage instrumentation.

cc @Zalathar

Some changes occurred to MIR optimizations

cc @rust-lang/wg-mir-opt

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jun 23, 2026
@rustbot

rustbot commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

r? @nnethercote

rustbot has assigned @nnethercote.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: compiler, mir, mir-opt
  • compiler, mir, mir-opt expanded to 73 candidates
  • Random selection from 21 candidates

@rustbot

This comment has been minimized.

@xd009642
xd009642 force-pushed the async_instr_coverage_fix branch from 6ccf282 to e741c23 Compare June 23, 2026 00:08
@rust-log-analyzer

This comment has been minimized.

@nnethercote

Copy link
Copy Markdown
Contributor

This is a small and simple change and it seems reasonable. But I will defer to someone who knows a lot more about this code than I do.

r? @Zalathar

@rustbot

rustbot commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Zalathar is not on the review rotation at the moment.
They may take a while to respond.

Comment thread compiler/rustc_mir_transform/src/coverage/query.rs Outdated
@xd009642
xd009642 force-pushed the async_instr_coverage_fix branch from e741c23 to 8ad73df Compare August 20, 2026 23:08
@rustbot

This comment has been minimized.

@xd009642

Copy link
Copy Markdown
Contributor Author

Okay @Zalathar using codex to help with debugging I managed to narrow it down better than my own semi-blind println stumbling around! The actual issue is that the instrumented function contains dummy spans and is evaluated but the actual user code is somewhere else in the expansion tree. This solution should hopefully be better

Removed my old incorrect processing and rebased on latest version. No tests currently for it as I'm not sure what the testing requirements are for the coverage stuff

Attribute proc macros such as `#[tracing::instrument]` can wrap the body
of an async function in another async block. The generated block's body
span belongs to the attribute expansion context, while the interpolated
user code retains spans in the root syntax context.

Coverage refinement uses the generated body's expansion-tree node. When
that node contains only dummy or empty spans, no mappings are produced
for the user code, even though useful spans exist in the root node for
the same MIR body.

When an attribute proc macro produces this shape, use the root-context
node for coverage mapping. The expansion tree contains spans from only
one MIR body, so the fallback cannot select spans from another function.
@xd009642
xd009642 force-pushed the async_instr_coverage_fix branch from 8ad73df to 401941a Compare September 2, 2026 15:33
@rustbot

rustbot commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@Zalathar

Zalathar commented Sep 3, 2026

Copy link
Copy Markdown
Member

(Sorry for this taking so long. The code in question is delicate enough that I don’t want to add more heuristics without properly understanding them, and the interaction of async and proc-macros is a very tricky business.)

@xd009642

xd009642 commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Sure no problem, I could try to make a project using numerous proc macro crates and async and see how this pr impacts coverage accuracy and then compare against sync proc macro projects as well if that'll help

@Zalathar Zalathar added the A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) label Sep 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-code-coverage Area: Source-based code coverage (-Cinstrument-coverage) S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Coverage information is wrong when using tracing

6 participants