@@ -108,9 +108,12 @@ impl BranchInfoBuilder {
108
108
false_marker : BlockMarkerId ,
109
109
) -> Option < ( u16 , ConditionInfo ) > {
110
110
let mcdc_state = self . mcdc_state . as_mut ( ) ?;
111
- let decision_depth = mcdc_state. decision_depth ;
111
+ let decision_depth = mcdc_state. decision_depth ( ) ;
112
112
let ( mut condition_info, decision_result) =
113
113
mcdc_state. take_condition ( true_marker, false_marker) ;
114
+ // take_condition() returns Some for decision_result when the decision stack
115
+ // is empty, i.e. when all the conditions of the decision were instrumented,
116
+ // and the decision is "complete".
114
117
if let Some ( decision) = decision_result {
115
118
match decision. conditions_num {
116
119
0 => {
@@ -180,22 +183,27 @@ impl BranchInfoBuilder {
180
183
/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged.
181
184
const MAX_CONDITIONS_NUM_IN_DECISION : usize = 6 ;
182
185
183
- struct MCDCState {
186
+ #[ derive( Default ) ]
187
+ struct MCDCDecisionCtx {
184
188
/// To construct condition evaluation tree.
185
189
decision_stack : VecDeque < ConditionInfo > ,
186
190
processing_decision : Option < MCDCDecisionSpan > ,
187
- decision_depth : u16 ,
191
+ }
192
+
193
+ struct MCDCState {
194
+ decision_ctx_stack : Vec < MCDCDecisionCtx > ,
188
195
}
189
196
190
197
impl MCDCState {
191
198
fn new_if_enabled ( tcx : TyCtxt < ' _ > ) -> Option < Self > {
192
199
tcx. sess
193
200
. instrument_coverage_mcdc ( )
194
- . then ( || Self {
195
- decision_stack : VecDeque :: new ( ) ,
196
- processing_decision : None ,
197
- decision_depth : 0 ,
198
- } )
201
+ . then ( || Self { decision_ctx_stack : vec ! [ MCDCDecisionCtx :: default ( ) ] } )
202
+ }
203
+
204
+ #[ inline]
205
+ fn decision_depth ( & self ) -> u16 {
206
+ ( self . decision_ctx_stack . len ( ) - 1 ) as u16
199
207
}
200
208
201
209
// At first we assign ConditionIds for each sub expression.
@@ -239,20 +247,23 @@ impl MCDCState {
239
247
// - If the op is AND, the "false_next" of LHS and RHS should be the parent's "false_next". While "true_next" of the LHS is the RHS, the "true next" of RHS is the parent's "true_next".
240
248
// - If the op is OR, the "true_next" of LHS and RHS should be the parent's "true_next". While "false_next" of the LHS is the RHS, the "false next" of RHS is the parent's "false_next".
241
249
fn record_conditions ( & mut self , op : LogicalOp , span : Span ) {
242
- let decision = match self . processing_decision . as_mut ( ) {
250
+ let decision_depth = self . decision_depth ( ) ;
251
+ let decision_ctx =
252
+ self . decision_ctx_stack . last_mut ( ) . expect ( "Unexpected empty decision_ctx_stack" ) ;
253
+ let decision = match decision_ctx. processing_decision . as_mut ( ) {
243
254
Some ( decision) => {
244
255
decision. span = decision. span . to ( span) ;
245
256
decision
246
257
}
247
- None => self . processing_decision . insert ( MCDCDecisionSpan {
258
+ None => decision_ctx . processing_decision . insert ( MCDCDecisionSpan {
248
259
span,
249
260
conditions_num : 0 ,
250
261
end_markers : vec ! [ ] ,
251
- decision_depth : 0 ,
262
+ decision_depth : decision_depth ,
252
263
} ) ,
253
264
} ;
254
265
255
- let parent_condition = self . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
266
+ let parent_condition = decision_ctx . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
256
267
let lhs_id = if parent_condition. condition_id == ConditionId :: NONE {
257
268
decision. conditions_num += 1 ;
258
269
ConditionId :: from ( decision. conditions_num )
@@ -292,19 +303,21 @@ impl MCDCState {
292
303
}
293
304
} ;
294
305
// We visit expressions tree in pre-order, so place the left-hand side on the top.
295
- self . decision_stack . push_back ( rhs) ;
296
- self . decision_stack . push_back ( lhs) ;
306
+ decision_ctx . decision_stack . push_back ( rhs) ;
307
+ decision_ctx . decision_stack . push_back ( lhs) ;
297
308
}
298
309
299
310
fn take_condition (
300
311
& mut self ,
301
312
true_marker : BlockMarkerId ,
302
313
false_marker : BlockMarkerId ,
303
314
) -> ( Option < ConditionInfo > , Option < MCDCDecisionSpan > ) {
304
- let Some ( condition_info) = self . decision_stack . pop_back ( ) else {
315
+ let decision_ctx =
316
+ self . decision_ctx_stack . last_mut ( ) . expect ( "Unexpected empty decision_ctx_stack" ) ;
317
+ let Some ( condition_info) = decision_ctx. decision_stack . pop_back ( ) else {
305
318
return ( None , None ) ;
306
319
} ;
307
- let Some ( decision) = self . processing_decision . as_mut ( ) else {
320
+ let Some ( decision) = decision_ctx . processing_decision . as_mut ( ) else {
308
321
bug ! ( "Processing decision should have been created before any conditions are taken" ) ;
309
322
} ;
310
323
if condition_info. true_next_id == ConditionId :: NONE {
@@ -314,8 +327,8 @@ impl MCDCState {
314
327
decision. end_markers . push ( false_marker) ;
315
328
}
316
329
317
- if self . decision_stack . is_empty ( ) {
318
- ( Some ( condition_info) , self . processing_decision . take ( ) )
330
+ if decision_ctx . decision_stack . is_empty ( ) {
331
+ ( Some ( condition_info) , decision_ctx . processing_decision . take ( ) )
319
332
} else {
320
333
( Some ( condition_info) , None )
321
334
}
@@ -391,15 +404,20 @@ impl Builder<'_, '_> {
391
404
if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
392
405
&& let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
393
406
{
394
- mcdc_state. decision_depth += 1 ;
407
+ mcdc_state. decision_ctx_stack . push ( MCDCDecisionCtx :: default ( ) ) ;
395
408
} ;
396
409
}
397
410
398
411
pub ( crate ) fn mcdc_decrement_depth_if_enabled ( & mut self ) {
399
412
if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
400
413
&& let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
401
414
{
402
- mcdc_state. decision_depth -= 1 ;
415
+ #[ allow( unused) ]
416
+ let Some ( MCDCDecisionCtx { decision_stack, processing_decision } ) =
417
+ mcdc_state. decision_ctx_stack . pop ( )
418
+ else {
419
+ bug ! ( "Unexpected empty Decision stack" ) ;
420
+ } ;
403
421
} ;
404
422
}
405
423
}
0 commit comments