@@ -111,6 +111,9 @@ impl BranchInfoBuilder {
111111 let decision_depth = mcdc_state. decision_depth ;
112112 let ( mut condition_info, decision_result) =
113113 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".
114117 if let Some ( decision) = decision_result {
115118 match decision. conditions_num {
116119 0 => {
@@ -180,22 +183,25 @@ impl BranchInfoBuilder {
180183/// This limit may be relaxed if the [upstream change](https://github.com/llvm/llvm-project/pull/82448) is merged.
181184const MAX_CONDITIONS_NUM_IN_DECISION : usize = 6 ;
182185
183- struct MCDCState {
186+ #[ derive( Default ) ]
187+ struct MCDCDecisionCtx {
184188 /// To construct condition evaluation tree.
185189 decision_stack : VecDeque < ConditionInfo > ,
186190 processing_decision : Option < MCDCDecisionSpan > ,
191+ }
192+
193+ struct MCDCState {
194+ decision_ctx_stack : Vec < MCDCDecisionCtx > ,
195+ /// To track the nesting level of boolean expressions.
187196 decision_depth : u16 ,
188197}
189198
190199impl MCDCState {
191200 fn new_if_enabled ( tcx : TyCtxt < ' _ > ) -> Option < Self > {
192- tcx. sess
193- . instrument_coverage_mcdc ( )
194- . then ( || Self {
195- decision_stack : VecDeque :: new ( ) ,
196- processing_decision : None ,
197- decision_depth : 0 ,
198- } )
201+ tcx. sess . instrument_coverage_mcdc ( ) . then ( || Self {
202+ decision_ctx_stack : vec ! [ MCDCDecisionCtx :: default ( ) ] ,
203+ decision_depth : 0 ,
204+ } )
199205 }
200206
201207 // At first we assign ConditionIds for each sub expression.
@@ -239,20 +245,21 @@ impl MCDCState {
239245 // - 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".
240246 // - 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".
241247 fn record_conditions ( & mut self , op : LogicalOp , span : Span ) {
242- let decision = match self . processing_decision . as_mut ( ) {
248+ let decision_ctx = & mut self . decision_ctx_stack [ self . decision_depth as usize ] ;
249+ let decision = match decision_ctx. processing_decision . as_mut ( ) {
243250 Some ( decision) => {
244251 decision. span = decision. span . to ( span) ;
245252 decision
246253 }
247- None => self . processing_decision . insert ( MCDCDecisionSpan {
254+ None => decision_ctx . processing_decision . insert ( MCDCDecisionSpan {
248255 span,
249256 conditions_num : 0 ,
250257 end_markers : vec ! [ ] ,
251- decision_depth : 0 ,
258+ decision_depth : self . decision_depth ,
252259 } ) ,
253260 } ;
254261
255- let parent_condition = self . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
262+ let parent_condition = decision_ctx . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
256263 let lhs_id = if parent_condition. condition_id == ConditionId :: NONE {
257264 decision. conditions_num += 1 ;
258265 ConditionId :: from ( decision. conditions_num )
@@ -292,19 +299,20 @@ impl MCDCState {
292299 }
293300 } ;
294301 // 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) ;
302+ decision_ctx . decision_stack . push_back ( rhs) ;
303+ decision_ctx . decision_stack . push_back ( lhs) ;
297304 }
298305
299306 fn take_condition (
300307 & mut self ,
301308 true_marker : BlockMarkerId ,
302309 false_marker : BlockMarkerId ,
303310 ) -> ( Option < ConditionInfo > , Option < MCDCDecisionSpan > ) {
304- let Some ( condition_info) = self . decision_stack . pop_back ( ) else {
311+ let decision_ctx = & mut self . decision_ctx_stack [ self . decision_depth as usize ] ;
312+ let Some ( condition_info) = decision_ctx. decision_stack . pop_back ( ) else {
305313 return ( None , None ) ;
306314 } ;
307- let Some ( decision) = self . processing_decision . as_mut ( ) else {
315+ let Some ( decision) = decision_ctx . processing_decision . as_mut ( ) else {
308316 bug ! ( "Processing decision should have been created before any conditions are taken" ) ;
309317 } ;
310318 if condition_info. true_next_id == ConditionId :: NONE {
@@ -314,8 +322,8 @@ impl MCDCState {
314322 decision. end_markers . push ( false_marker) ;
315323 }
316324
317- if self . decision_stack . is_empty ( ) {
318- ( Some ( condition_info) , self . processing_decision . take ( ) )
325+ if decision_ctx . decision_stack . is_empty ( ) {
326+ ( Some ( condition_info) , decision_ctx . processing_decision . take ( ) )
319327 } else {
320328 ( Some ( condition_info) , None )
321329 }
@@ -391,6 +399,7 @@ impl Builder<'_, '_> {
391399 if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
392400 && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
393401 {
402+ mcdc_state. decision_ctx_stack . push ( MCDCDecisionCtx :: default ( ) ) ;
394403 mcdc_state. decision_depth += 1 ;
395404 } ;
396405 }
@@ -399,6 +408,12 @@ impl Builder<'_, '_> {
399408 if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
400409 && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
401410 {
411+ #[ allow( unused) ]
412+ let Some ( MCDCDecisionCtx { decision_stack, processing_decision } ) =
413+ mcdc_state. decision_ctx_stack . pop ( )
414+ else {
415+ bug ! ( "Unexpected empty Decision stack" ) ;
416+ } ;
402417 mcdc_state. decision_depth -= 1 ;
403418 } ;
404419 }
0 commit comments