Skip to content

Commit 54116c8

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 e3f66b2 commit 54116c8

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
@@ -406,8 +408,13 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
406408

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

410-
for (_def_id, body) in def_and_mir_for_all_mono_fns {
411418
// Inspect every coverage statement in the function's MIR.
412419
for stmt in body
413420
.basic_blocks
@@ -418,11 +425,18 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
418425
if let Some(inlined) = stmt.source_info.scope.inlined_instance(&body.source_scopes) {
419426
// This coverage statement was inlined from another function.
420427
used_via_inlining.insert(inlined.def_id());
428+
} else {
429+
// Non-inlined coverage statements belong to the enclosing function.
430+
saw_own_coverage = true;
421431
}
422432
}
433+
434+
if !saw_own_coverage && body.function_coverage_info.is_some() {
435+
missing_own_coverage.insert(def_id);
436+
}
423437
}
424438

425-
UsageSets { all_mono_items, used_via_inlining }
439+
UsageSets { all_mono_items, used_via_inlining, missing_own_coverage }
426440
}
427441

428442
fn add_unused_function_coverage<'tcx>(

0 commit comments

Comments
 (0)