@@ -101,10 +101,14 @@ impl BranchInfoBuilder {
101101 tcx : TyCtxt < ' _ > ,
102102 true_marker : BlockMarkerId ,
103103 false_marker : BlockMarkerId ,
104- ) -> Option < ConditionInfo > {
104+ ) -> Option < ( u16 , ConditionInfo ) > {
105105 let mcdc_state = self . mcdc_state . as_mut ( ) ?;
106+ let decision_depth = mcdc_state. decision_depth ( ) ;
106107 let ( mut condition_info, decision_result) =
107108 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".
108112 if let Some ( decision) = decision_result {
109113 match decision. conditions_num {
110114 0 => {
@@ -131,7 +135,7 @@ impl BranchInfoBuilder {
131135 }
132136 }
133137 }
134- condition_info
138+ condition_info. map ( |cond_info| ( decision_depth , cond_info ) )
135139 }
136140
137141 fn add_two_way_branch < ' tcx > (
@@ -199,17 +203,28 @@ impl BranchInfoBuilder {
199203/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged.
200204const MAX_CONDITIONS_NUM_IN_DECISION : usize = 6 ;
201205
202- struct MCDCState {
206+ #[ derive( Default ) ]
207+ struct MCDCDecisionCtx {
203208 /// To construct condition evaluation tree.
204209 decision_stack : VecDeque < ConditionInfo > ,
205210 processing_decision : Option < MCDCDecisionSpan > ,
206211}
207212
213+ struct MCDCState {
214+ decision_ctx_stack : Vec < MCDCDecisionCtx > ,
215+ }
216+
208217impl MCDCState {
209218 fn new_if_enabled ( tcx : TyCtxt < ' _ > ) -> Option < Self > {
210219 tcx. sess
211220 . instrument_coverage_mcdc ( )
212- . then ( || Self { decision_stack : VecDeque :: new ( ) , processing_decision : None } )
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
213228 }
214229
215230 // At first we assign ConditionIds for each sub expression.
@@ -253,20 +268,23 @@ impl MCDCState {
253268 // - 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".
254269 // - 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".
255270 fn record_conditions ( & mut self , op : LogicalOp , span : Span ) {
256- 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 ( ) {
257275 Some ( decision) => {
258276 decision. span = decision. span . to ( span) ;
259277 decision
260278 }
261- None => self . processing_decision . insert ( MCDCDecisionSpan {
279+ None => decision_ctx . processing_decision . insert ( MCDCDecisionSpan {
262280 span,
263281 conditions_num : 0 ,
264282 end_markers : vec ! [ ] ,
265- decision_depth : 0 ,
283+ decision_depth : decision_depth ,
266284 } ) ,
267285 } ;
268286
269- let parent_condition = self . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
287+ let parent_condition = decision_ctx . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
270288 let lhs_id = if parent_condition. condition_id == ConditionId :: NONE {
271289 decision. conditions_num += 1 ;
272290 ConditionId :: from ( decision. conditions_num )
@@ -306,19 +324,21 @@ impl MCDCState {
306324 }
307325 } ;
308326 // We visit expressions tree in pre-order, so place the left-hand side on the top.
309- self . decision_stack . push_back ( rhs) ;
310- self . decision_stack . push_back ( lhs) ;
327+ decision_ctx . decision_stack . push_back ( rhs) ;
328+ decision_ctx . decision_stack . push_back ( lhs) ;
311329 }
312330
313331 fn take_condition (
314332 & mut self ,
315333 true_marker : BlockMarkerId ,
316334 false_marker : BlockMarkerId ,
317335 ) -> ( Option < ConditionInfo > , Option < MCDCDecisionSpan > ) {
318- 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 {
319339 return ( None , None ) ;
320340 } ;
321- let Some ( decision) = self . processing_decision . as_mut ( ) else {
341+ let Some ( decision) = decision_ctx . processing_decision . as_mut ( ) else {
322342 bug ! ( "Processing decision should have been created before any conditions are taken" ) ;
323343 } ;
324344 if condition_info. true_next_id == ConditionId :: NONE {
@@ -328,8 +348,8 @@ impl MCDCState {
328348 decision. end_markers . push ( false_marker) ;
329349 }
330350
331- if self . decision_stack . is_empty ( ) {
332- ( Some ( condition_info) , self . processing_decision . take ( ) )
351+ if decision_ctx . decision_stack . is_empty ( ) {
352+ ( Some ( condition_info) , decision_ctx . processing_decision . take ( ) )
333353 } else {
334354 ( Some ( condition_info) , None )
335355 }
@@ -365,14 +385,17 @@ impl Builder<'_, '_> {
365385 |block| branch_info. inject_block_marker ( & mut self . cfg , source_info, block) ;
366386 let true_marker = inject_block_marker ( then_block) ;
367387 let false_marker = inject_block_marker ( else_block) ;
368- let condition_info =
369- branch_info. fetch_mcdc_condition_info ( self . tcx , true_marker, false_marker) ;
388+ let ( decision_depth, condition_info) = branch_info
389+ . fetch_mcdc_condition_info ( self . tcx , true_marker, false_marker)
390+ . map_or ( ( 0 , None ) , |( decision_depth, condition_info) | {
391+ ( decision_depth, Some ( condition_info) )
392+ } ) ;
370393 branch_info. mcdc_branch_spans . push ( MCDCBranchSpan {
371394 span : source_info. span ,
372395 condition_info,
373396 true_marker,
374397 false_marker,
375- decision_depth : 0 ,
398+ decision_depth,
376399 } ) ;
377400 return ;
378401 }
@@ -387,4 +410,20 @@ impl Builder<'_, '_> {
387410 mcdc_state. record_conditions ( logical_op, span) ;
388411 }
389412 }
413+
414+ pub ( crate ) fn mcdc_increment_depth_if_enabled ( & mut self ) {
415+ if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
416+ && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
417+ {
418+ mcdc_state. decision_ctx_stack . push ( MCDCDecisionCtx :: default ( ) ) ;
419+ } ;
420+ }
421+
422+ pub ( crate ) fn mcdc_decrement_depth_if_enabled ( & mut self ) {
423+ if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
424+ && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
425+ {
426+ mcdc_state. decision_ctx_stack . pop ( ) . expect ( "Unexpected empty decision stack" ) ;
427+ } ;
428+ }
390429}
0 commit comments