@@ -88,21 +88,27 @@ struct Instrumentor<'a, 'tcx> {
88
88
pass_name : & ' a str ,
89
89
tcx : TyCtxt < ' tcx > ,
90
90
mir_body : & ' a mut mir:: Body < ' tcx > ,
91
+ fn_sig_span : Span ,
91
92
body_span : Span ,
92
93
basic_coverage_blocks : CoverageGraph ,
93
94
coverage_counters : CoverageCounters ,
94
95
}
95
96
96
97
impl < ' a , ' tcx > Instrumentor < ' a , ' tcx > {
97
98
fn new ( pass_name : & ' a str , tcx : TyCtxt < ' tcx > , mir_body : & ' a mut mir:: Body < ' tcx > ) -> Self {
98
- let hir_body = hir_body ( tcx, mir_body. source . def_id ( ) ) ;
99
+ let ( some_fn_sig , hir_body) = fn_sig_and_body ( tcx, mir_body. source . def_id ( ) ) ;
99
100
let body_span = hir_body. value . span ;
101
+ let fn_sig_span = match some_fn_sig {
102
+ Some ( fn_sig) => fn_sig. span . with_hi ( body_span. lo ( ) ) ,
103
+ None => body_span. shrink_to_lo ( ) ,
104
+ } ;
100
105
let function_source_hash = hash_mir_source ( tcx, hir_body) ;
101
106
let basic_coverage_blocks = CoverageGraph :: from_mir ( mir_body) ;
102
107
Self {
103
108
pass_name,
104
109
tcx,
105
110
mir_body,
111
+ fn_sig_span,
106
112
body_span,
107
113
basic_coverage_blocks,
108
114
coverage_counters : CoverageCounters :: new ( function_source_hash) ,
@@ -114,9 +120,15 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
114
120
let source_map = tcx. sess . source_map ( ) ;
115
121
let mir_source = self . mir_body . source ;
116
122
let def_id = mir_source. def_id ( ) ;
123
+ let fn_sig_span = self . fn_sig_span ;
117
124
let body_span = self . body_span ;
118
125
119
- debug ! ( "instrumenting {:?}, span: {}" , def_id, source_map. span_to_string( body_span) ) ;
126
+ debug ! (
127
+ "instrumenting {:?}, fn sig span: {}, body span: {}" ,
128
+ def_id,
129
+ source_map. span_to_string( fn_sig_span) ,
130
+ source_map. span_to_string( body_span)
131
+ ) ;
120
132
121
133
let mut graphviz_data = debug:: GraphvizData :: new ( ) ;
122
134
let mut debug_used_expressions = debug:: UsedExpressions :: new ( ) ;
@@ -138,6 +150,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
138
150
// Compute `CoverageSpan`s from the `CoverageGraph`.
139
151
let coverage_spans = CoverageSpans :: generate_coverage_spans (
140
152
& self . mir_body ,
153
+ fn_sig_span,
141
154
body_span,
142
155
& self . basic_coverage_blocks ,
143
156
) ;
@@ -260,26 +273,47 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
260
273
261
274
let mut bcb_counters = IndexVec :: from_elem_n ( None , self . basic_coverage_blocks . num_nodes ( ) ) ;
262
275
for covspan in coverage_spans {
263
- let bcb = covspan. bcb ;
264
276
let span = covspan. span ;
265
- let counter_kind = if let Some ( & counter_operand) = bcb_counters[ bcb] . as_ref ( ) {
266
- self . coverage_counters . make_identity_counter ( counter_operand)
267
- } else if let Some ( counter_kind) = self . bcb_data_mut ( bcb) . take_counter ( ) {
268
- bcb_counters[ bcb] = Some ( counter_kind. as_operand_id ( ) ) ;
269
- debug_used_expressions. add_expression_operands ( & counter_kind) ;
270
- counter_kind
271
- } else {
272
- bug ! ( "Every BasicCoverageBlock should have a Counter or Expression" ) ;
273
- } ;
274
- graphviz_data. add_bcb_coverage_span_with_counter ( bcb, & covspan, & counter_kind) ;
275
- // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special
276
- // cases?
277
- let some_code_region = if self . is_code_region_redundant ( bcb, span, body_span) {
278
- None
277
+ if let Some ( bcb) = covspan. bcb {
278
+ let counter_kind = if let Some ( & counter_operand) = bcb_counters[ bcb] . as_ref ( ) {
279
+ self . coverage_counters . make_identity_counter ( counter_operand)
280
+ } else if let Some ( counter_kind) = self . bcb_data_mut ( bcb) . take_counter ( ) {
281
+ bcb_counters[ bcb] = Some ( counter_kind. as_operand_id ( ) ) ;
282
+ debug_used_expressions. add_expression_operands ( & counter_kind) ;
283
+ counter_kind
284
+ } else {
285
+ bug ! ( "Every BasicCoverageBlock should have a Counter or Expression" ) ;
286
+ } ;
287
+ graphviz_data. add_bcb_coverage_span_with_counter ( bcb, & covspan, & counter_kind) ;
288
+ // FIXME(#78542): Can spans for `TerminatorKind::Goto` be improved to avoid special
289
+ // cases?
290
+ let some_code_region = if self . is_code_region_redundant ( bcb, span, body_span) {
291
+ None
292
+ } else {
293
+ Some ( make_code_region ( file_name, & source_file, span, body_span) )
294
+ } ;
295
+ inject_statement (
296
+ self . mir_body ,
297
+ counter_kind,
298
+ self . bcb_last_bb ( bcb) ,
299
+ some_code_region,
300
+ ) ;
279
301
} else {
280
- Some ( make_code_region ( file_name, & source_file, span, body_span) )
281
- } ;
282
- inject_statement ( self . mir_body , counter_kind, self . bcb_last_bb ( bcb) , some_code_region) ;
302
+ // A closure body has its own, separate MIR, but the code span for the closure body
303
+ // is known to the enclosing function's MIR. Since it is possible for a closure to
304
+ // be "unused", that closure's MIR would not get codegenned and would not have any
305
+ // known coverage. Adding an `Unreachable` code region for the closure ensures the
306
+ // closure's region is known to coverage and can be marked "uncovered" if needed.
307
+ // Note, the `Unreachable` region will generate a `Zero` counter, which is
308
+ // subsequently turned into a `gap_region` in the Coverage Map. The `gap_region`
309
+ // ensures code is only marked uncovered if there is no other defined coverage.
310
+ inject_statement (
311
+ self . mir_body ,
312
+ CoverageKind :: Unreachable ,
313
+ mir:: START_BLOCK ,
314
+ Some ( make_code_region ( file_name, & source_file, span, body_span) ) ,
315
+ ) ;
316
+ }
283
317
}
284
318
}
285
319
@@ -521,10 +555,13 @@ fn make_code_region(
521
555
}
522
556
}
523
557
524
- fn hir_body < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : DefId ) -> & ' tcx rustc_hir:: Body < ' tcx > {
558
+ fn fn_sig_and_body < ' tcx > (
559
+ tcx : TyCtxt < ' tcx > ,
560
+ def_id : DefId ,
561
+ ) -> ( Option < & ' tcx rustc_hir:: FnSig < ' tcx > > , & ' tcx rustc_hir:: Body < ' tcx > ) {
525
562
let hir_node = tcx. hir ( ) . get_if_local ( def_id) . expect ( "expected DefId is local" ) ;
526
563
let fn_body_id = hir:: map:: associated_body ( hir_node) . expect ( "HIR node is a function with body" ) ;
527
- tcx. hir ( ) . body ( fn_body_id)
564
+ ( hir :: map :: fn_sig ( hir_node ) , tcx. hir ( ) . body ( fn_body_id) )
528
565
}
529
566
530
567
fn hash_mir_source < ' tcx > ( tcx : TyCtxt < ' tcx > , hir_body : & ' tcx rustc_hir:: Body < ' tcx > ) -> u64 {
0 commit comments