Skip to content

Commit 4d467a5

Browse files
committed
coverage: Detect functions that have lost all their coverage statements
If a function was instrumented for coverage, but all of its coverage statements have been removed by later MIR transforms, it should be treated as "unused" even if the compiler generates an unreachable stub for it.
1 parent 73a54f4 commit 4d467a5

File tree

1 file changed

+18
-4
lines changed
  • compiler/rustc_codegen_llvm/src/coverageinfo

1 file changed

+18
-4
lines changed

compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,11 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
353353

354354
// To be eligible for "unused function" mappings, a definition must:
355355
// - Be function-like
356-
// - Not participate directly in codegen
356+
// - Not participate directly in codegen (or have lost all its coverage statements)
357357
// - Not have any coverage statements inlined into codegenned functions
358358
tcx.def_kind(def_id).is_fn_like()
359-
&& !usage.all_mono_items.contains(&def_id)
359+
&& (!usage.all_mono_items.contains(&def_id)
360+
|| usage.missing_own_coverage.contains(&def_id))
360361
&& !usage.used_via_inlining.contains(&def_id)
361362
};
362363

@@ -379,6 +380,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
379380
struct UsageSets<'tcx> {
380381
all_mono_items: &'tcx DefIdSet,
381382
used_via_inlining: FxHashSet<DefId>,
383+
missing_own_coverage: FxHashSet<DefId>,
382384
}
383385

384386
/// Prepare sets of definitions that are relevant to deciding whether something
@@ -408,8 +410,13 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
408410

409411
// Functions whose coverage statments were found inlined into other functions.
410412
let mut used_via_inlining = FxHashSet::default();
413+
// Functions that were instrumented, but had all of their coverage statements
414+
// removed by later MIR transforms (e.g. UnreachablePropagation).
415+
let mut missing_own_coverage = FxHashSet::default();
416+
417+
for (def_id, body) in def_and_mir_for_all_mono_fns {
418+
let mut saw_own_coverage = false;
411419

412-
for (_def_id, body) in def_and_mir_for_all_mono_fns {
413420
// Inspect every coverage statement in the function's MIR.
414421
for stmt in body
415422
.basic_blocks
@@ -420,11 +427,18 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
420427
if let Some(inlined) = stmt.source_info.scope.inlined_instance(&body.source_scopes) {
421428
// This coverage statement was inlined from another function.
422429
used_via_inlining.insert(inlined.def_id());
430+
} else {
431+
// Non-inlined coverage statements belong to the enclosing function.
432+
saw_own_coverage = true;
423433
}
424434
}
435+
436+
if !saw_own_coverage && body.function_coverage_info.is_some() {
437+
missing_own_coverage.insert(def_id);
438+
}
425439
}
426440

427-
UsageSets { all_mono_items, used_via_inlining }
441+
UsageSets { all_mono_items, used_via_inlining, missing_own_coverage }
428442
}
429443

430444
fn add_unused_function_coverage<'tcx>(

0 commit comments

Comments
 (0)