@@ -17,7 +17,6 @@ use tracing::debug;
17
17
18
18
use crate :: common:: CodegenCx ;
19
19
use crate :: coverageinfo:: llvm_cov;
20
- use crate :: coverageinfo:: map_data:: FunctionCoverage ;
21
20
use crate :: coverageinfo:: mapgen:: covfun:: prepare_covfun_record;
22
21
use crate :: llvm;
23
22
@@ -48,34 +47,28 @@ pub(crate) fn finalize(cx: &CodegenCx<'_, '_>) {
48
47
49
48
debug ! ( "Generating coverage map for CodegenUnit: `{}`" , cx. codegen_unit. name( ) ) ;
50
49
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
-
59
50
// 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 ( ) ,
62
53
None => return ,
63
54
} ;
64
- if function_coverage_map. is_empty ( ) {
65
- // This CGU has no functions with coverage instrumentation.
66
- return ;
67
- }
68
55
69
56
let mut global_file_table = GlobalFileTable :: new ( ) ;
70
57
71
- let covfun_records = function_coverage_map
72
- . into_iter ( )
73
- . filter_map ( |( instance, function_coverage) | {
74
- let is_used = function_coverage. is_used ( ) ;
75
- prepare_covfun_record ( tcx, & mut global_file_table, instance, is_used)
76
- } )
58
+ let mut covfun_records = instances_used
59
+ . iter ( )
60
+ . copied ( )
61
+ . filter_map ( |instance| prepare_covfun_record ( tcx, & mut global_file_table, instance, true ) )
77
62
. collect :: < Vec < _ > > ( ) ;
78
63
64
+ // In a single designated CGU, also prepare covfun records for functions
65
+ // in this crate that were instrumented for coverage, but are unused.
66
+ if cx. codegen_unit . is_code_coverage_dead_code_cgu ( ) {
67
+ covfun_records. extend ( gather_unused_functions ( cx) . into_iter ( ) . filter_map ( |instance| {
68
+ prepare_covfun_record ( tcx, & mut global_file_table, instance, false )
69
+ } ) ) ;
70
+ }
71
+
79
72
// If there are no covfun records for this CGU, don't generate a covmap record.
80
73
// Emitting a covmap record without any covfun records causes `llvm-cov` to
81
74
// fail when generating coverage reports, and if there are no covfun records
@@ -252,7 +245,7 @@ fn generate_covmap_record<'ll>(cx: &CodegenCx<'ll, '_>, version: u32, filenames_
252
245
/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them.
253
246
/// We also end up adding their symbol names to a special global array that LLVM will include in
254
247
/// its embedded coverage data.
255
- fn add_unused_functions ( cx : & CodegenCx < ' _ , ' _ > ) {
248
+ fn gather_unused_functions < ' tcx > ( cx : & CodegenCx < ' _ , ' tcx > ) -> Vec < ty :: Instance < ' tcx > > {
256
249
assert ! ( cx. codegen_unit. is_code_coverage_dead_code_cgu( ) ) ;
257
250
258
251
let tcx = cx. tcx ;
@@ -269,20 +262,17 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
269
262
&& !usage. used_via_inlining . contains ( & def_id. to_def_id ( ) )
270
263
} ;
271
264
272
- // Scan for unused functions that were instrumented for coverage.
273
- for def_id in tcx. mir_keys ( ( ) ) . iter ( ) . copied ( ) . filter ( |& def_id| is_unused_fn ( def_id) ) {
274
- // Get the coverage info from MIR, skipping functions that were never instrumented.
275
- let body = tcx. optimized_mir ( def_id) ;
276
- let Some ( function_coverage_info) = body. function_coverage_info . as_deref ( ) else { continue } ;
265
+ // FIXME(79651): Consider trying to filter out dummy instantiations of
266
+ // unused generic functions from library crates, because they can produce
267
+ // "unused instantiation" in coverage reports even when they are actually
268
+ // used by some downstream crate in the same binary.
277
269
278
- // FIXME(79651): Consider trying to filter out dummy instantiations of
279
- // unused generic functions from library crates, because they can produce
280
- // "unused instantiation" in coverage reports even when they are actually
281
- // used by some downstream crate in the same binary.
282
-
283
- debug ! ( "generating unused fn: {def_id:?}" ) ;
284
- add_unused_function_coverage ( cx, def_id, function_coverage_info) ;
285
- }
270
+ tcx. mir_keys ( ( ) )
271
+ . iter ( )
272
+ . copied ( )
273
+ . filter ( |& def_id| is_unused_fn ( def_id) )
274
+ . map ( |def_id| make_dummy_instance ( tcx, def_id) )
275
+ . collect :: < Vec < _ > > ( )
286
276
}
287
277
288
278
struct UsageSets < ' tcx > {
@@ -347,16 +337,11 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
347
337
UsageSets { all_mono_items, used_via_inlining, missing_own_coverage }
348
338
}
349
339
350
- fn add_unused_function_coverage < ' tcx > (
351
- cx : & CodegenCx < ' _ , ' tcx > ,
352
- def_id : LocalDefId ,
353
- function_coverage_info : & ' tcx mir:: coverage:: FunctionCoverageInfo ,
354
- ) {
355
- let tcx = cx. tcx ;
356
- let def_id = def_id. to_def_id ( ) ;
340
+ fn make_dummy_instance < ' tcx > ( tcx : TyCtxt < ' tcx > , local_def_id : LocalDefId ) -> ty:: Instance < ' tcx > {
341
+ let def_id = local_def_id. to_def_id ( ) ;
357
342
358
343
// Make a dummy instance that fills in all generics with placeholders.
359
- let instance = ty:: Instance :: new (
344
+ ty:: Instance :: new (
360
345
def_id,
361
346
ty:: GenericArgs :: for_item ( tcx, def_id, |param, _| {
362
347
if let ty:: GenericParamDefKind :: Lifetime = param. kind {
@@ -365,9 +350,5 @@ fn add_unused_function_coverage<'tcx>(
365
350
tcx. mk_param_from_def ( param)
366
351
}
367
352
} ) ,
368
- ) ;
369
-
370
- // An unused function's mappings will all be rewritten to map to zero.
371
- let function_coverage = FunctionCoverage :: new_unused ( function_coverage_info) ;
372
- cx. coverage_cx ( ) . function_coverage_map . borrow_mut ( ) . insert ( instance, function_coverage) ;
353
+ )
373
354
}
0 commit comments