Skip to content

Commit a246b6b

Browse files
committed
coverage: Make fn_sig_span optional, and note its quirks
1 parent fde1702 commit a246b6b

File tree

3 files changed

+17
-11
lines changed

3 files changed

+17
-11
lines changed

compiler/rustc_mir_transform/src/coverage/mod.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,9 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
394394
struct ExtractedHirInfo {
395395
function_source_hash: u64,
396396
is_async_fn: bool,
397-
fn_sig_span: Span,
397+
/// The span of the function's signature, extended to the start of `body_span`.
398+
/// Must have the same context and filename as the body span.
399+
fn_sig_span_extended: Option<Span>,
398400
body_span: Span,
399401
}
400402

@@ -407,7 +409,8 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
407409
hir::map::associated_body(hir_node).expect("HIR node is a function with body");
408410
let hir_body = tcx.hir().body(fn_body_id);
409411

410-
let is_async_fn = hir_node.fn_sig().is_some_and(|fn_sig| fn_sig.header.is_async());
412+
let maybe_fn_sig = hir_node.fn_sig();
413+
let is_async_fn = maybe_fn_sig.is_some_and(|fn_sig| fn_sig.header.is_async());
411414

412415
let mut body_span = hir_body.value.span;
413416

@@ -423,8 +426,8 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
423426

424427
// The actual signature span is only used if it has the same context and
425428
// filename as the body, and precedes the body.
426-
let maybe_fn_sig_span = hir_node.fn_sig().map(|fn_sig| fn_sig.span);
427-
let fn_sig_span = maybe_fn_sig_span
429+
let fn_sig_span_extended = maybe_fn_sig
430+
.map(|fn_sig| fn_sig.span)
428431
.filter(|&fn_sig_span| {
429432
let source_map = tcx.sess.source_map();
430433
let file_idx = |span: Span| source_map.lookup_source_file_idx(span.lo());
@@ -434,13 +437,11 @@ fn extract_hir_info<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ExtractedHir
434437
&& file_idx(fn_sig_span) == file_idx(body_span)
435438
})
436439
// If so, extend it to the start of the body span.
437-
.map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()))
438-
// Otherwise, create a dummy signature span at the start of the body.
439-
.unwrap_or_else(|| body_span.shrink_to_lo());
440+
.map(|fn_sig_span| fn_sig_span.with_hi(body_span.lo()));
440441

441442
let function_source_hash = hash_mir_source(tcx, hir_body);
442443

443-
ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span, body_span }
444+
ExtractedHirInfo { function_source_hash, is_async_fn, fn_sig_span_extended, body_span }
444445
}
445446

446447
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {

compiler/rustc_mir_transform/src/coverage/spans.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ pub(super) fn generate_coverage_spans(
5151
// with the user code wrapped in a closure. Any spans in the desugared
5252
// outer function will be unhelpful, so just keep the signature span
5353
// and ignore all of the spans in the MIR body.
54-
let span = hir_info.fn_sig_span;
55-
mappings.push(BcbMapping { kind: BcbMappingKind::Code(START_BCB), span });
54+
if let Some(span) = hir_info.fn_sig_span_extended {
55+
mappings.push(BcbMapping { kind: BcbMappingKind::Code(START_BCB), span });
56+
}
5657
} else {
5758
let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans(
5859
mir_body,

compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
2323
hir_info: &ExtractedHirInfo,
2424
basic_coverage_blocks: &CoverageGraph,
2525
) -> Vec<CoverageSpan> {
26-
let &ExtractedHirInfo { fn_sig_span, body_span, .. } = hir_info;
26+
let &ExtractedHirInfo { body_span, .. } = hir_info;
2727

2828
let mut initial_spans = vec![];
2929

@@ -33,6 +33,10 @@ pub(super) fn mir_to_initial_sorted_coverage_spans(
3333

3434
// Only add the signature span if we found at least one span in the body.
3535
if !initial_spans.is_empty() {
36+
// If there is no usable signature span, add a fake one (before refinement)
37+
// to avoid an ugly gap between the body start and the first real span.
38+
// FIXME: Find a more principled way to solve this problem.
39+
let fn_sig_span = hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo());
3640
initial_spans.push(SpanFromMir::for_fn_sig(fn_sig_span));
3741
}
3842

0 commit comments

Comments
 (0)