@@ -17,7 +17,6 @@ use tracing::debug;
1717
1818use crate :: common:: CodegenCx ;
1919use crate :: coverageinfo:: llvm_cov;
20- use crate :: coverageinfo:: map_data:: FunctionCoverage ;
2120use crate :: coverageinfo:: mapgen:: covfun:: prepare_covfun_record;
2221use crate :: llvm;
2322
@@ -48,38 +47,32 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
4847
4948 debug ! ( "Generating coverage map for CodegenUnit: `{}`" , cx. codegen_unit. name( ) ) ;
5049
51- // In order to show that unused functions have coverage counts of zero (0), LLVM requires the
52- // functions exist. Generate synthetic functions with a (required) single counter, and add the
53- // MIR `Coverage` code regions to the `function_coverage_map`, before calling
54- // `ctx.take_function_coverage_map()`.
55- if cx. codegen_unit . is_code_coverage_dead_code_cgu ( ) {
56- add_unused_functions ( cx) ;
57- }
58-
5950 // FIXME(#132395): Can this be none even when coverage is enabled?
60- let function_coverage_map = match cx. coverage_cx {
61- Some ( ref cx) => cx. take_function_coverage_map ( ) ,
51+ let instances_used = match cx. coverage_cx {
52+ Some ( ref cx) => cx. instances_used . borrow ( ) ,
6253 None => return ,
6354 } ;
64- if function_coverage_map. is_empty ( ) {
65- // This CGU has no functions with coverage instrumentation.
66- return ;
67- }
6855
6956 // The order of entries in this global file table is arbitrary, and depends
7057 // on the order in which this CGU visited functions and statements during
7158 // codegen. But that order should be deterministic, so the table order is
7259 // deterministic too.
7360 let mut global_file_table = GlobalFileTable :: new ( ) ;
7461
75- let covfun_records = function_coverage_map
76- . into_iter ( )
77- . filter_map ( |( instance, function_coverage) | {
78- let is_used = function_coverage. is_used ( ) ;
79- prepare_covfun_record ( tcx, & mut global_file_table, instance, is_used)
80- } )
62+ let mut covfun_records = instances_used
63+ . iter ( )
64+ . copied ( )
65+ . filter_map ( |instance| prepare_covfun_record ( tcx, & mut global_file_table, instance, true ) )
8166 . collect :: < Vec < _ > > ( ) ;
8267
68+ // In a single designated CGU, also prepare covfun records for functions
69+ // in this crate that were instrumented for coverage, but are unused.
70+ if cx. codegen_unit . is_code_coverage_dead_code_cgu ( ) {
71+ covfun_records. extend ( gather_unused_functions ( cx) . into_iter ( ) . filter_map ( |instance| {
72+ prepare_covfun_record ( tcx, & mut global_file_table, instance, false )
73+ } ) ) ;
74+ }
75+
8376 // If there are no covfun records for this CGU, don't generate a covmap record.
8477 // Emitting a covmap record without any covfun records causes `llvm-cov` to
8578 // fail when generating coverage reports, and if there are no covfun records
@@ -255,7 +248,7 @@ fn generate_covmap_record<'ll>(cx: &CodegenCx<'ll, '_>, version: u32, filenames_
255248/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them.
256249/// We also end up adding their symbol names to a special global array that LLVM will include in
257250/// its embedded coverage data.
258- fn add_unused_functions ( cx : & CodegenCx < ' _ , ' _ > ) {
251+ fn gather_unused_functions < ' tcx > ( cx : & CodegenCx < ' _ , ' tcx > ) -> Vec < ty :: Instance < ' tcx > > {
259252 assert ! ( cx. codegen_unit. is_code_coverage_dead_code_cgu( ) ) ;
260253
261254 let tcx = cx. tcx ;
@@ -273,20 +266,17 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
273266 && !usage. used_via_inlining . contains ( & d)
274267 } ;
275268
276- // Scan for unused functions that were instrumented for coverage.
277- for def_id in tcx. mir_keys ( ( ) ) . iter ( ) . copied ( ) . filter ( |& def_id| is_unused_fn ( def_id) ) {
278- // Get the coverage info from MIR, skipping functions that were never instrumented.
279- let body = tcx. optimized_mir ( def_id) ;
280- let Some ( function_coverage_info) = body. function_coverage_info . as_deref ( ) else { continue } ;
269+ // FIXME(#79651): Consider trying to filter out dummy instantiations of
270+ // unused generic functions from library crates, because they can produce
271+ // "unused instantiation" in coverage reports even when they are actually
272+ // used by some downstream crate in the same binary.
281273
282- // FIXME(79651): Consider trying to filter out dummy instantiations of
283- // unused generic functions from library crates, because they can produce
284- // "unused instantiation" in coverage reports even when they are actually
285- // used by some downstream crate in the same binary.
286-
287- debug ! ( "generating unused fn: {def_id:?}" ) ;
288- add_unused_function_coverage ( cx, def_id, function_coverage_info) ;
289- }
274+ tcx. mir_keys ( ( ) )
275+ . iter ( )
276+ . copied ( )
277+ . filter ( |& def_id| is_unused_fn ( def_id) )
278+ . map ( |def_id| make_dummy_instance ( tcx, def_id) )
279+ . collect :: < Vec < _ > > ( )
290280}
291281
292282struct UsageSets < ' tcx > {
@@ -351,16 +341,11 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
351341 UsageSets { all_mono_items, used_via_inlining, missing_own_coverage }
352342}
353343
354- fn add_unused_function_coverage < ' tcx > (
355- cx : & CodegenCx < ' _ , ' tcx > ,
356- def_id : LocalDefId ,
357- function_coverage_info : & ' tcx mir:: coverage:: FunctionCoverageInfo ,
358- ) {
359- let tcx = cx. tcx ;
360- let def_id = def_id. to_def_id ( ) ;
344+ fn make_dummy_instance < ' tcx > ( tcx : TyCtxt < ' tcx > , local_def_id : LocalDefId ) -> ty:: Instance < ' tcx > {
345+ let def_id = local_def_id. to_def_id ( ) ;
361346
362347 // Make a dummy instance that fills in all generics with placeholders.
363- let instance = ty:: Instance :: new (
348+ ty:: Instance :: new (
364349 def_id,
365350 ty:: GenericArgs :: for_item ( tcx, def_id, |param, _| {
366351 if let ty:: GenericParamDefKind :: Lifetime = param. kind {
@@ -369,9 +354,5 @@ fn add_unused_function_coverage<'tcx>(
369354 tcx. mk_param_from_def ( param)
370355 }
371356 } ) ,
372- ) ;
373-
374- // An unused function's mappings will all be rewritten to map to zero.
375- let function_coverage = FunctionCoverage :: new_unused ( function_coverage_info) ;
376- cx. coverage_cx ( ) . function_coverage_map . borrow_mut ( ) . insert ( instance, function_coverage) ;
357+ )
377358}
0 commit comments