@@ -103,9 +103,12 @@ impl BranchInfoBuilder {
103103 false_marker : BlockMarkerId ,
104104 ) -> Option < ( u16 , ConditionInfo ) > {
105105 let mcdc_state = self . mcdc_state . as_mut ( ) ?;
106- let decision_depth = mcdc_state. decision_depth ;
106+ let decision_depth = mcdc_state. decision_depth ( ) ;
107107 let ( mut condition_info, decision_result) =
108108 mcdc_state. take_condition ( true_marker, false_marker) ;
109+ // take_condition() returns Some for decision_result when the decision stack
110+ // is empty, i.e. when all the conditions of the decision were instrumented,
111+ // and the decision is "complete".
109112 if let Some ( decision) = decision_result {
110113 match decision. conditions_num {
111114 0 => {
@@ -200,20 +203,28 @@ impl BranchInfoBuilder {
200203/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged.
201204const MAX_CONDITIONS_NUM_IN_DECISION : usize = 6 ;
202205
203- struct MCDCState {
206+ #[ derive( Default ) ]
207+ struct MCDCDecisionCtx {
204208 /// To construct condition evaluation tree.
205209 decision_stack : VecDeque < ConditionInfo > ,
206210 processing_decision : Option < MCDCDecisionSpan > ,
207- decision_depth : u16 ,
211+ }
212+
213+ struct MCDCState {
214+ decision_ctx_stack : Vec < MCDCDecisionCtx > ,
208215}
209216
210217impl MCDCState {
211218 fn new_if_enabled ( tcx : TyCtxt < ' _ > ) -> Option < Self > {
212- tcx. sess . instrument_coverage_mcdc ( ) . then ( || Self {
213- decision_stack : VecDeque :: new ( ) ,
214- processing_decision : None ,
215- decision_depth : 0 ,
216- } )
219+ tcx. sess
220+ . instrument_coverage_mcdc ( )
221+ . then ( || Self { decision_ctx_stack : vec ! [ MCDCDecisionCtx :: default ( ) ] } )
222+ }
223+
224+ #[ inline]
225+ fn decision_depth ( & self ) -> u16 {
226+ self . decision_ctx_stack . len ( ) . checked_sub ( 1 ) . expect ( "Unexpected empty decision stack" )
227+ as u16
217228 }
218229
219230 // At first we assign ConditionIds for each sub expression.
@@ -257,20 +268,23 @@ impl MCDCState {
257268 // - 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".
258269 // - 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".
259270 fn record_conditions ( & mut self , op : LogicalOp , span : Span ) {
260- let decision = match self . processing_decision . as_mut ( ) {
271+ let decision_depth = self . decision_depth ( ) ;
272+ let decision_ctx =
273+ self . decision_ctx_stack . last_mut ( ) . expect ( "Unexpected empty decision_ctx_stack" ) ;
274+ let decision = match decision_ctx. processing_decision . as_mut ( ) {
261275 Some ( decision) => {
262276 decision. span = decision. span . to ( span) ;
263277 decision
264278 }
265- None => self . processing_decision . insert ( MCDCDecisionSpan {
279+ None => decision_ctx . processing_decision . insert ( MCDCDecisionSpan {
266280 span,
267281 conditions_num : 0 ,
268282 end_markers : vec ! [ ] ,
269- decision_depth : 0 ,
283+ decision_depth : decision_depth ,
270284 } ) ,
271285 } ;
272286
273- let parent_condition = self . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
287+ let parent_condition = decision_ctx . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
274288 let lhs_id = if parent_condition. condition_id == ConditionId :: NONE {
275289 decision. conditions_num += 1 ;
276290 ConditionId :: from ( decision. conditions_num )
@@ -310,19 +324,21 @@ impl MCDCState {
310324 }
311325 } ;
312326 // We visit expressions tree in pre-order, so place the left-hand side on the top.
313- self . decision_stack . push_back ( rhs) ;
314- self . decision_stack . push_back ( lhs) ;
327+ decision_ctx . decision_stack . push_back ( rhs) ;
328+ decision_ctx . decision_stack . push_back ( lhs) ;
315329 }
316330
317331 fn take_condition (
318332 & mut self ,
319333 true_marker : BlockMarkerId ,
320334 false_marker : BlockMarkerId ,
321335 ) -> ( Option < ConditionInfo > , Option < MCDCDecisionSpan > ) {
322- let Some ( condition_info) = self . decision_stack . pop_back ( ) else {
336+ let decision_ctx =
337+ self . decision_ctx_stack . last_mut ( ) . expect ( "Unexpected empty decision_ctx_stack" ) ;
338+ let Some ( condition_info) = decision_ctx. decision_stack . pop_back ( ) else {
323339 return ( None , None ) ;
324340 } ;
325- let Some ( decision) = self . processing_decision . as_mut ( ) else {
341+ let Some ( decision) = decision_ctx . processing_decision . as_mut ( ) else {
326342 bug ! ( "Processing decision should have been created before any conditions are taken" ) ;
327343 } ;
328344 if condition_info. true_next_id == ConditionId :: NONE {
@@ -332,8 +348,8 @@ impl MCDCState {
332348 decision. end_markers . push ( false_marker) ;
333349 }
334350
335- if self . decision_stack . is_empty ( ) {
336- ( Some ( condition_info) , self . processing_decision . take ( ) )
351+ if decision_ctx . decision_stack . is_empty ( ) {
352+ ( Some ( condition_info) , decision_ctx . processing_decision . take ( ) )
337353 } else {
338354 ( Some ( condition_info) , None )
339355 }
@@ -399,15 +415,15 @@ impl Builder<'_, '_> {
399415 if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
400416 && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
401417 {
402- mcdc_state. decision_depth += 1 ;
418+ mcdc_state. decision_ctx_stack . push ( MCDCDecisionCtx :: default ( ) ) ;
403419 } ;
404420 }
405421
406422 pub ( crate ) fn mcdc_decrement_depth_if_enabled ( & mut self ) {
407423 if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
408424 && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
409425 {
410- mcdc_state. decision_depth -= 1 ;
426+ mcdc_state. decision_ctx_stack . pop ( ) . expect ( "Unexpected empty decision stack" ) ;
411427 } ;
412428 }
413429}
0 commit comments