Skip to content

Commit cf6dc7a

Browse files
committedDec 20, 2023
coverage: Check for async fn explicitly, without needing a heuristic
The old code used a heuristic to detect async functions and adjust their coverage spans to produce better output. But there's no need to resort to a heuristic when we can just check whether the current function is actually an `async fn`.
1 parent 2a0290a commit cf6dc7a

File tree

2 files changed

+11
-12
lines changed

2 files changed

+11
-12
lines changed
 

Diff for: ‎compiler/rustc_mir_transform/src/coverage/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
299299
#[derive(Debug)]
300300
struct ExtractedHirInfo {
301301
function_source_hash: u64,
302+
is_async_fn: bool,
302303
fn_sig_span: Span,
303304
body_span: Span,
304305
}
@@ -312,6 +313,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
312313
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
313314
let hir_body = tcx.hir().body(fn_body_id);
314315

316+
let is_async_fn = hir_node.fn_sig().is_some_and(|fn_sig| fn_sig.header.is_async());
315317
let body_span = get_body_span(tcx, hir_body, def_id);
316318

317319
// The actual signature span is only used if it has the same context and
@@ -333,7 +335,7 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
333335

334336
let function_source_hash = hash_mir_source(tcx, hir_body);
335337

336-
ExtractedHirInfo { function_source_hash, fn_sig_span, body_span }
338+
ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span }
337339
}
338340

339341
fn get_body_span<'tcx>(

Diff for: ‎compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,14 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
1414
hir_info: &ExtractedHirInfo,
1515
basic_coverage_blocks: &CoverageGraph,
1616
) -> Vec<CoverageSpan> {
17-
let &ExtractedHirInfo { fn_sig_span, body_span, .. } = hir_info;
17+
let &ExtractedHirInfo { is_async_fn, fn_sig_span, body_span, .. } = hir_info;
18+
if is_async_fn {
19+
// An async function desugars into a function that returns a future,
20+
// with the user code wrapped in a closure. Any spans in the desugared
21+
// outer function will be unhelpful, so just produce a single span
22+
// associating the function signature with its entry BCB.
23+
return vec![CoverageSpan::for_fn_sig(fn_sig_span)];
24+
}
1825

1926
let mut initial_spans = Vec::with_capacity(mir_body.basic_blocks.len() * 2);
2027
for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() {
@@ -46,16 +53,6 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
4653
.then_with(|| Ord::cmp(&a.is_closure, &b.is_closure).reverse())
4754
});
4855

49-
// The desugaring of an async function includes a closure containing the
50-
// original function body, and a terminator that returns the `impl Future`.
51-
// That terminator will cause a confusing coverage count for the function's
52-
// closing brace, so discard everything after the body closure span.
53-
if let Some(body_closure_index) =
54-
initial_spans.iter().rposition(|covspan| covspan.is_closure && covspan.span == body_span)
55-
{
56-
initial_spans.truncate(body_closure_index + 1);
57-
}
58-
5956
initial_spans
6057
}
6158

0 commit comments

Comments
 (0)