@@ -2,7 +2,7 @@ use std::assert_matches::assert_matches;
2
2
use std:: collections:: hash_map:: Entry ;
3
3
4
4
use rustc_data_structures:: fx:: FxHashMap ;
5
- use rustc_middle:: mir:: coverage:: { BlockMarkerId , BranchSpan , CoverageKind } ;
5
+ use rustc_middle:: mir:: coverage:: { BlockMarkerId , BranchSpan , CoverageInfoHi , CoverageKind } ;
6
6
use rustc_middle:: mir:: { self , BasicBlock , SourceInfo , UnOp } ;
7
7
use rustc_middle:: thir:: { ExprId , ExprKind , Pat , Thir } ;
8
8
use rustc_middle:: ty:: TyCtxt ;
@@ -13,16 +13,25 @@ use crate::build::{Builder, CFG};
13
13
14
14
mod mcdc;
15
15
16
- pub ( crate ) struct BranchInfoBuilder {
16
+ /// Collects coverage-related information during MIR building, to eventually be
17
+ /// turned into a function's [`CoverageInfoHi`] when MIR building is complete.
18
+ pub ( crate ) struct CoverageInfoBuilder {
17
19
/// Maps condition expressions to their enclosing `!`, for better instrumentation.
18
20
nots : FxHashMap < ExprId , NotInfo > ,
19
21
20
22
markers : BlockMarkerGen ,
21
- branch_spans : Vec < BranchSpan > ,
22
23
24
+ /// Present if branch coverage is enabled.
25
+ branch_info : Option < BranchInfo > ,
26
+ /// Present if MC/DC coverage is enabled.
23
27
mcdc_info : Option < MCDCInfoBuilder > ,
24
28
}
25
29
30
+ #[ derive( Default ) ]
31
+ struct BranchInfo {
32
+ branch_spans : Vec < BranchSpan > ,
33
+ }
34
+
26
35
#[ derive( Clone , Copy ) ]
27
36
struct NotInfo {
28
37
/// When visiting the associated expression as a branch condition, treat this
@@ -62,20 +71,20 @@ impl BlockMarkerGen {
62
71
}
63
72
}
64
73
65
- impl BranchInfoBuilder {
66
- /// Creates a new branch info builder, but only if branch coverage instrumentation
74
+ impl CoverageInfoBuilder {
75
+ /// Creates a new coverage info builder, but only if coverage instrumentation
67
76
/// is enabled and `def_id` represents a function that is eligible for coverage.
68
77
pub ( crate ) fn new_if_enabled ( tcx : TyCtxt < ' _ > , def_id : LocalDefId ) -> Option < Self > {
69
- if tcx. sess . instrument_coverage_branch ( ) && tcx. is_eligible_for_coverage ( def_id) {
70
- Some ( Self {
71
- nots : FxHashMap :: default ( ) ,
72
- markers : BlockMarkerGen :: default ( ) ,
73
- branch_spans : vec ! [ ] ,
74
- mcdc_info : tcx. sess . instrument_coverage_mcdc ( ) . then ( MCDCInfoBuilder :: new) ,
75
- } )
76
- } else {
77
- None
78
+ if !tcx. sess . instrument_coverage ( ) || !tcx. is_eligible_for_coverage ( def_id) {
79
+ return None ;
78
80
}
81
+
82
+ Some ( Self {
83
+ nots : FxHashMap :: default ( ) ,
84
+ markers : BlockMarkerGen :: default ( ) ,
85
+ branch_info : tcx. sess . instrument_coverage_branch ( ) . then ( BranchInfo :: default) ,
86
+ mcdc_info : tcx. sess . instrument_coverage_mcdc ( ) . then ( MCDCInfoBuilder :: new) ,
87
+ } )
79
88
}
80
89
81
90
/// Unary `!` expressions inside an `if` condition are lowered by lowering
@@ -88,6 +97,12 @@ impl BranchInfoBuilder {
88
97
pub ( crate ) fn visit_unary_not ( & mut self , thir : & Thir < ' _ > , unary_not : ExprId ) {
89
98
assert_matches ! ( thir[ unary_not] . kind, ExprKind :: Unary { op: UnOp :: Not , .. } ) ;
90
99
100
+ // The information collected by this visitor is only needed when branch
101
+ // coverage or higher is enabled.
102
+ if self . branch_info . is_none ( ) {
103
+ return ;
104
+ }
105
+
91
106
self . visit_with_not_info (
92
107
thir,
93
108
unary_not,
@@ -137,40 +152,40 @@ impl BranchInfoBuilder {
137
152
false_block,
138
153
inject_block_marker,
139
154
) ;
140
- } else {
141
- let true_marker = self . markers . inject_block_marker ( cfg, source_info, true_block) ;
142
- let false_marker = self . markers . inject_block_marker ( cfg, source_info, false_block) ;
143
-
144
- self . branch_spans . push ( BranchSpan {
145
- span : source_info. span ,
146
- true_marker,
147
- false_marker,
148
- } ) ;
155
+ return ;
149
156
}
157
+
158
+ // Bail out if branch coverage is not enabled.
159
+ let Some ( branch_info) = self . branch_info . as_mut ( ) else { return } ;
160
+
161
+ let true_marker = self . markers . inject_block_marker ( cfg, source_info, true_block) ;
162
+ let false_marker = self . markers . inject_block_marker ( cfg, source_info, false_block) ;
163
+
164
+ branch_info. branch_spans . push ( BranchSpan {
165
+ span : source_info. span ,
166
+ true_marker,
167
+ false_marker,
168
+ } ) ;
150
169
}
151
170
152
- pub ( crate ) fn into_done ( self ) -> Option < Box < mir:: coverage:: BranchInfo > > {
153
- let Self {
154
- nots : _,
155
- markers : BlockMarkerGen { num_block_markers } ,
156
- branch_spans,
157
- mcdc_info,
158
- } = self ;
171
+ pub ( crate ) fn into_done ( self ) -> Box < CoverageInfoHi > {
172
+ let Self { nots : _, markers : BlockMarkerGen { num_block_markers } , branch_info, mcdc_info } =
173
+ self ;
159
174
160
- if num_block_markers == 0 {
161
- assert ! ( branch_spans. is_empty( ) ) ;
162
- return None ;
163
- }
175
+ let branch_spans =
176
+ branch_info. map ( |branch_info| branch_info. branch_spans ) . unwrap_or_default ( ) ;
164
177
165
178
let ( mcdc_decision_spans, mcdc_branch_spans) =
166
179
mcdc_info. map ( MCDCInfoBuilder :: into_done) . unwrap_or_default ( ) ;
167
180
168
- Some ( Box :: new ( mir:: coverage:: BranchInfo {
181
+ // For simplicity, always return an info struct (without Option), even
182
+ // if there's nothing interesting in it.
183
+ Box :: new ( CoverageInfoHi {
169
184
num_block_markers,
170
185
branch_spans,
171
186
mcdc_branch_spans,
172
187
mcdc_decision_spans,
173
- } ) )
188
+ } )
174
189
}
175
190
}
176
191
@@ -184,7 +199,7 @@ impl<'tcx> Builder<'_, 'tcx> {
184
199
block : & mut BasicBlock ,
185
200
) {
186
201
// Bail out if condition coverage is not enabled for this function.
187
- let Some ( branch_info ) = self . coverage_branch_info . as_mut ( ) else { return } ;
202
+ let Some ( coverage_info ) = self . coverage_info . as_mut ( ) else { return } ;
188
203
if !self . tcx . sess . instrument_coverage_condition ( ) {
189
204
return ;
190
205
} ;
@@ -224,7 +239,7 @@ impl<'tcx> Builder<'_, 'tcx> {
224
239
) ;
225
240
226
241
// Separate path for handling branches when MC/DC is enabled.
227
- branch_info . register_two_way_branch (
242
+ coverage_info . register_two_way_branch (
228
243
self . tcx ,
229
244
& mut self . cfg ,
230
245
source_info,
@@ -247,12 +262,12 @@ impl<'tcx> Builder<'_, 'tcx> {
247
262
mut then_block : BasicBlock ,
248
263
mut else_block : BasicBlock ,
249
264
) {
250
- // Bail out if branch coverage is not enabled for this function.
251
- let Some ( branch_info ) = self . coverage_branch_info . as_mut ( ) else { return } ;
265
+ // Bail out if coverage is not enabled for this function.
266
+ let Some ( coverage_info ) = self . coverage_info . as_mut ( ) else { return } ;
252
267
253
268
// If this condition expression is nested within one or more `!` expressions,
254
269
// replace it with the enclosing `!` collected by `visit_unary_not`.
255
- if let Some ( & NotInfo { enclosing_not, is_flipped } ) = branch_info . nots . get ( & expr_id) {
270
+ if let Some ( & NotInfo { enclosing_not, is_flipped } ) = coverage_info . nots . get ( & expr_id) {
256
271
expr_id = enclosing_not;
257
272
if is_flipped {
258
273
std:: mem:: swap ( & mut then_block, & mut else_block) ;
@@ -261,7 +276,7 @@ impl<'tcx> Builder<'_, 'tcx> {
261
276
262
277
let source_info = SourceInfo { span : self . thir [ expr_id] . span , scope : self . source_scope } ;
263
278
264
- branch_info . register_two_way_branch (
279
+ coverage_info . register_two_way_branch (
265
280
self . tcx ,
266
281
& mut self . cfg ,
267
282
source_info,
@@ -280,13 +295,11 @@ impl<'tcx> Builder<'_, 'tcx> {
280
295
true_block : BasicBlock ,
281
296
false_block : BasicBlock ,
282
297
) {
283
- // Bail out if branch coverage is not enabled for this function.
284
- let Some ( branch_info) = self . coverage_branch_info . as_mut ( ) else { return } ;
285
-
286
- // FIXME(#124144) This may need special handling when MC/DC is enabled.
298
+ // Bail out if coverage is not enabled for this function.
299
+ let Some ( coverage_info) = self . coverage_info . as_mut ( ) else { return } ;
287
300
288
301
let source_info = SourceInfo { span : pattern. span , scope : self . source_scope } ;
289
- branch_info . register_two_way_branch (
302
+ coverage_info . register_two_way_branch (
290
303
self . tcx ,
291
304
& mut self . cfg ,
292
305
source_info,
0 commit comments