@@ -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,38 +47,32 @@ 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
// The order of entries in this global file table is arbitrary, and depends
70
57
// on the order in which this CGU visited functions and statements during
71
58
// codegen. But that order should be deterministic, so the table order is
72
59
// deterministic too.
73
60
let mut global_file_table = GlobalFileTable :: new ( ) ;
74
61
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 ) )
81
66
. collect :: < Vec < _ > > ( ) ;
82
67
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
+
83
76
// If there are no covfun records for this CGU, don't generate a covmap record.
84
77
// Emitting a covmap record without any covfun records causes `llvm-cov` to
85
78
// 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_
255
248
/// coverage map (in a single designated CGU) so that we still emit coverage mappings for them.
256
249
/// We also end up adding their symbol names to a special global array that LLVM will include in
257
250
/// its embedded coverage data.
258
- fn add_unused_functions ( cx : & CodegenCx < ' _ , ' _ > ) {
251
+ fn gather_unused_functions < ' tcx > ( cx : & CodegenCx < ' _ , ' tcx > ) -> Vec < ty :: Instance < ' tcx > > {
259
252
assert ! ( cx. codegen_unit. is_code_coverage_dead_code_cgu( ) ) ;
260
253
261
254
let tcx = cx. tcx ;
@@ -273,20 +266,17 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) {
273
266
&& !usage. used_via_inlining . contains ( & d)
274
267
} ;
275
268
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.
281
273
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 < _ > > ( )
290
280
}
291
281
292
282
struct UsageSets < ' tcx > {
@@ -351,16 +341,11 @@ fn prepare_usage_sets<'tcx>(tcx: TyCtxt<'tcx>) -> UsageSets<'tcx> {
351
341
UsageSets { all_mono_items, used_via_inlining, missing_own_coverage }
352
342
}
353
343
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 ( ) ;
361
346
362
347
// Make a dummy instance that fills in all generics with placeholders.
363
- let instance = ty:: Instance :: new (
348
+ ty:: Instance :: new (
364
349
def_id,
365
350
ty:: GenericArgs :: for_item ( tcx, def_id, |param, _| {
366
351
if let ty:: GenericParamDefKind :: Lifetime = param. kind {
@@ -369,9 +354,5 @@ fn add_unused_function_coverage<'tcx>(
369
354
tcx. mk_param_from_def ( param)
370
355
}
371
356
} ) ,
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
+ )
377
358
}
0 commit comments