@@ -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,32 @@ 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+ /// Decision depth is given as a u16 to reduce the size of the `CoverageKind`,
225+ /// as it is very unlikely that the depth ever reaches 2^16.
226+ #[ inline]
227+ fn decision_depth ( & self ) -> u16 {
228+ u16:: try_from (
229+ self . decision_ctx_stack . len ( ) . checked_sub ( 1 ) . expect ( "Unexpected empty decision stack" ) ,
230+ )
231+ . expect ( "decision depth did not fit in u16, this is likely to be an instrumentation error" )
213232 }
214233
215234 // At first we assign ConditionIds for each sub expression.
@@ -253,20 +272,23 @@ impl MCDCState {
253272 // - 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".
254273 // - 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".
255274 fn record_conditions ( & mut self , op : LogicalOp , span : Span ) {
256- let decision = match self . processing_decision . as_mut ( ) {
275+ let decision_depth = self . decision_depth ( ) ;
276+ let decision_ctx =
277+ self . decision_ctx_stack . last_mut ( ) . expect ( "Unexpected empty decision_ctx_stack" ) ;
278+ let decision = match decision_ctx. processing_decision . as_mut ( ) {
257279 Some ( decision) => {
258280 decision. span = decision. span . to ( span) ;
259281 decision
260282 }
261- None => self . processing_decision . insert ( MCDCDecisionSpan {
283+ None => decision_ctx . processing_decision . insert ( MCDCDecisionSpan {
262284 span,
263285 conditions_num : 0 ,
264286 end_markers : vec ! [ ] ,
265- decision_depth : 0 ,
287+ decision_depth,
266288 } ) ,
267289 } ;
268290
269- let parent_condition = self . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
291+ let parent_condition = decision_ctx . decision_stack . pop_back ( ) . unwrap_or_default ( ) ;
270292 let lhs_id = if parent_condition. condition_id == ConditionId :: NONE {
271293 decision. conditions_num += 1 ;
272294 ConditionId :: from ( decision. conditions_num )
@@ -306,19 +328,21 @@ impl MCDCState {
306328 }
307329 } ;
308330 // 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) ;
331+ decision_ctx . decision_stack . push_back ( rhs) ;
332+ decision_ctx . decision_stack . push_back ( lhs) ;
311333 }
312334
313335 fn take_condition (
314336 & mut self ,
315337 true_marker : BlockMarkerId ,
316338 false_marker : BlockMarkerId ,
317339 ) -> ( Option < ConditionInfo > , Option < MCDCDecisionSpan > ) {
318- let Some ( condition_info) = self . decision_stack . pop_back ( ) else {
340+ let decision_ctx =
341+ self . decision_ctx_stack . last_mut ( ) . expect ( "Unexpected empty decision_ctx_stack" ) ;
342+ let Some ( condition_info) = decision_ctx. decision_stack . pop_back ( ) else {
319343 return ( None , None ) ;
320344 } ;
321- let Some ( decision) = self . processing_decision . as_mut ( ) else {
345+ let Some ( decision) = decision_ctx . processing_decision . as_mut ( ) else {
322346 bug ! ( "Processing decision should have been created before any conditions are taken" ) ;
323347 } ;
324348 if condition_info. true_next_id == ConditionId :: NONE {
@@ -328,8 +352,8 @@ impl MCDCState {
328352 decision. end_markers . push ( false_marker) ;
329353 }
330354
331- if self . decision_stack . is_empty ( ) {
332- ( Some ( condition_info) , self . processing_decision . take ( ) )
355+ if decision_ctx . decision_stack . is_empty ( ) {
356+ ( Some ( condition_info) , decision_ctx . processing_decision . take ( ) )
333357 } else {
334358 ( Some ( condition_info) , None )
335359 }
@@ -365,14 +389,17 @@ impl Builder<'_, '_> {
365389 |block| branch_info. inject_block_marker ( & mut self . cfg , source_info, block) ;
366390 let true_marker = inject_block_marker ( then_block) ;
367391 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) ;
392+ let ( decision_depth, condition_info) = branch_info
393+ . fetch_mcdc_condition_info ( self . tcx , true_marker, false_marker)
394+ . map_or ( ( 0 , None ) , |( decision_depth, condition_info) | {
395+ ( decision_depth, Some ( condition_info) )
396+ } ) ;
370397 branch_info. mcdc_branch_spans . push ( MCDCBranchSpan {
371398 span : source_info. span ,
372399 condition_info,
373400 true_marker,
374401 false_marker,
375- decision_depth : 0 ,
402+ decision_depth,
376403 } ) ;
377404 return ;
378405 }
@@ -387,4 +414,20 @@ impl Builder<'_, '_> {
387414 mcdc_state. record_conditions ( logical_op, span) ;
388415 }
389416 }
417+
418+ pub ( crate ) fn mcdc_increment_depth_if_enabled ( & mut self ) {
419+ if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
420+ && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
421+ {
422+ mcdc_state. decision_ctx_stack . push ( MCDCDecisionCtx :: default ( ) ) ;
423+ } ;
424+ }
425+
426+ pub ( crate ) fn mcdc_decrement_depth_if_enabled ( & mut self ) {
427+ if let Some ( branch_info) = self . coverage_branch_info . as_mut ( )
428+ && let Some ( mcdc_state) = branch_info. mcdc_state . as_mut ( )
429+ {
430+ mcdc_state. decision_ctx_stack . pop ( ) . expect ( "Unexpected empty decision stack" ) ;
431+ } ;
432+ }
390433}
0 commit comments