From 4d467a52202889ba0690a0ff3f9b6eb8eb50b7a2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Fri, 22 Mar 2024 13:23:04 +1100 Subject: [PATCH] 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. --- .../src/coverageinfo/mapgen.rs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index 1d734b19f86af..ec2540d2b1a05 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -353,10 +353,11 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { // To be eligible for "unused function" mappings, a definition must: // - Be function-like - // - Not participate directly in codegen + // - Not participate directly in codegen (or have lost all its coverage statements) // - Not have any coverage statements inlined into codegenned functions tcx.def_kind(def_id).is_fn_like() - && !usage.all_mono_items.contains(&def_id) + && (!usage.all_mono_items.contains(&def_id) + || usage.missing_own_coverage.contains(&def_id)) && !usage.used_via_inlining.contains(&def_id) }; @@ -379,6 +380,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { struct UsageSets<'tcx> { all_mono_items: &'tcx DefIdSet, used_via_inlining: FxHashSet, + missing_own_coverage: FxHashSet, } /// 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> { // Functions whose coverage statments were found inlined into other functions. let mut used_via_inlining = FxHashSet::default(); + // Functions that were instrumented, but had all of their coverage statements + // removed by later MIR transforms (e.g. UnreachablePropagation). + let mut missing_own_coverage = FxHashSet::default(); + + for (def_id, body) in def_and_mir_for_all_mono_fns { + let mut saw_own_coverage = false; - for (_def_id, body) in def_and_mir_for_all_mono_fns { // Inspect every coverage statement in the function's MIR. for stmt in body .basic_blocks @@ -420,11 +427,18 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> { if let Some(inlined) = stmt.source_info.scope.inlined_instance(&body.source_scopes) { // This coverage statement was inlined from another function. used_via_inlining.insert(inlined.def_id()); + } else { + // Non-inlined coverage statements belong to the enclosing function. + saw_own_coverage = true; } } + + if !saw_own_coverage && body.function_coverage_info.is_some() { + missing_own_coverage.insert(def_id); + } } - UsageSets { all_mono_items, used_via_inlining } + UsageSets { all_mono_items, used_via_inlining, missing_own_coverage } } fn add_unused_function_coverage<'tcx>(