11use  std:: assert_matches:: assert_matches; 
22use  std:: collections:: hash_map:: Entry ; 
3- use  std:: collections:: VecDeque ; 
3+ use  std:: collections:: { BTreeMap ,   VecDeque } ; 
44
55use  rustc_data_structures:: fx:: FxHashMap ; 
66use  rustc_middle:: mir:: coverage:: { 
77    BlockMarkerId ,  BranchSpan ,  ConditionId ,  ConditionInfo ,  CoverageKind ,  MCDCBranchSpan , 
8-     MCDCDecisionSpan , 
8+     MCDCDecisionSpan ,   MCDCMatchBranchSpan , 
99} ; 
10- use  rustc_middle:: mir:: { self ,  BasicBlock ,  SourceInfo ,  UnOp } ; 
10+ use  rustc_middle:: mir:: { self ,  BasicBlock ,  SourceInfo ,  StatementKind ,   UnOp } ; 
1111use  rustc_middle:: thir:: { ExprId ,  ExprKind ,  LogicalOp ,  Thir } ; 
1212use  rustc_middle:: ty:: TyCtxt ; 
1313use  rustc_span:: def_id:: LocalDefId ; 
@@ -22,7 +22,8 @@ pub(crate) struct BranchInfoBuilder {
2222
2323    num_block_markers :  usize , 
2424    branch_spans :  Vec < BranchSpan > , 
25- 
25+     pattern_match_branch_records :  BTreeMap < Span ,  MCDCMatchBranchSpan > , 
26+     markers_map :  BTreeMap < usize ,  BasicBlock > , 
2627    mcdc_branch_spans :  Vec < MCDCBranchSpan > , 
2728    mcdc_decision_spans :  Vec < MCDCDecisionSpan > , 
2829    mcdc_state :  Option < MCDCState > , 
@@ -47,6 +48,8 @@ impl BranchInfoBuilder {
4748                nots :  FxHashMap :: default ( ) , 
4849                num_block_markers :  0 , 
4950                branch_spans :  vec ! [ ] , 
51+                 pattern_match_branch_records :  BTreeMap :: new ( ) , 
52+                 markers_map :  Default :: default ( ) , 
5053                mcdc_branch_spans :  vec ! [ ] , 
5154                mcdc_decision_spans :  vec ! [ ] , 
5255                mcdc_state :  MCDCState :: new_if_enabled ( tcx) , 
@@ -175,6 +178,8 @@ impl BranchInfoBuilder {
175178            nots :  _, 
176179            num_block_markers, 
177180            branch_spans, 
181+             pattern_match_branch_records, 
182+             markers_map :  _, 
178183            mcdc_branch_spans, 
179184            mcdc_decision_spans, 
180185            mcdc_state :  _, 
@@ -184,11 +189,24 @@ impl BranchInfoBuilder {
184189            assert ! ( branch_spans. is_empty( ) ) ; 
185190            return  None ; 
186191        } 
192+         let  mut  mcdc_match_branch_spans =
193+             pattern_match_branch_records. into_values ( ) . collect :: < Vec < _ > > ( ) ; 
194+         mcdc_match_branch_spans. sort_by ( |a,  b| { 
195+             if  a. span . contains ( b. span )  {  std:: cmp:: Ordering :: Less  }  else  {  a. span . cmp ( & b. span )  } 
196+         } ) ; 
197+         for  idx in  0 ..( mcdc_match_branch_spans. len ( )  - 1 )  { 
198+             if  mcdc_match_branch_spans[ idx] . span . contains ( mcdc_match_branch_spans[ idx + 1 ] . span )  { 
199+                 let  refined_span =
200+                     mcdc_match_branch_spans[ idx] . span . until ( mcdc_match_branch_spans[ idx + 1 ] . span ) ; 
201+                 mcdc_match_branch_spans[ idx] . span  = refined_span; 
202+             } 
203+         } 
187204
188205        Some ( Box :: new ( mir:: coverage:: BranchInfo  { 
189206            num_block_markers, 
190207            branch_spans, 
191208            mcdc_branch_spans, 
209+             mcdc_match_branch_spans, 
192210            mcdc_decision_spans, 
193211        } ) ) 
194212    } 
@@ -385,4 +403,74 @@ impl Builder<'_, '_> {
385403            mcdc_state. record_conditions ( logical_op,  span) ; 
386404        } 
387405    } 
406+ 
407+     pub ( crate )  fn  visit_coverage_mcdc_match_arms ( 
408+         & mut  self , 
409+         test_block :  BasicBlock , 
410+         targets :  impl  Iterator < Item  = ( Span ,  BasicBlock ) > , 
411+     )  { 
412+         if  !self . tcx . sess . instrument_coverage_mcdc ( )  { 
413+             return ; 
414+         } 
415+         let  mut  markers_map = BTreeMap :: < usize ,  BasicBlock > :: new ( ) ; 
416+         let  mut  get_marker_id = |span,  block| { 
417+             self . cfg 
418+                 . block_data_mut ( block) 
419+                 . statements 
420+                 . iter ( ) 
421+                 . find_map ( |statement| match  statement. kind  { 
422+                     StatementKind :: Coverage ( CoverageKind :: BlockMarker  {  id } )  => Some ( id) , 
423+                     _ => None , 
424+                 } ) 
425+                 . unwrap_or_else ( || { 
426+                     let  source_info = self . source_info ( span) ; 
427+                     let  id = self 
428+                         . coverage_branch_info 
429+                         . as_mut ( ) 
430+                         . expect ( "Checked at entry of the function" ) 
431+                         . next_block_marker_id ( ) ; 
432+ 
433+                     let  marker_statement = mir:: Statement  { 
434+                         source_info, 
435+                         kind :  mir:: StatementKind :: Coverage ( CoverageKind :: BlockMarker  {  id } ) , 
436+                     } ; 
437+                     markers_map. insert ( id. as_usize ( ) ,  block) ; 
438+                     self . cfg . push ( block,  marker_statement) ; 
439+                     id
440+                 } ) 
441+         } ; 
442+         let  test_block_id = get_marker_id ( Span :: default ( ) ,  test_block) ; 
443+ 
444+         let  mut  targets = targets
445+             . map ( |( span,  block) | { 
446+                 let  marker_id = get_marker_id ( span,  block) ; 
447+                 ( span,  marker_id) 
448+             } ) 
449+             . collect :: < Vec < _ > > ( ) ; 
450+ 
451+         let  branch_records = self 
452+             . coverage_branch_info 
453+             . as_mut ( ) 
454+             . map ( |branch_info| { 
455+                 branch_info. markers_map . extend ( markers_map) ; 
456+                 & mut  branch_info. pattern_match_branch_records 
457+             } ) 
458+             . expect ( "Checked at entry of the function" ) ; 
459+ 
460+         while  let  Some ( ( span,  matched_block) )  = targets. pop ( )  { 
461+             // By here we do not know the span of the target yet, so just record the 
462+             // basic blocks and insert BlockMarkerId later. 
463+             let  record = branch_records. entry ( span) . or_insert_with ( || MCDCMatchBranchSpan  { 
464+                 span, 
465+                 condition_info :  None , 
466+                 test_markers :  vec ! [ ] , 
467+                 true_markers :  vec ! [ ] , 
468+                 substract_markers :  vec ! [ ] , 
469+             } ) ; 
470+             record. test_markers . push ( test_block_id) ; 
471+             record. true_markers . push ( matched_block) ; 
472+ 
473+             record. substract_markers . extend ( targets. iter ( ) . map ( |( _,  blk) | * blk) ) ; 
474+         } 
475+     } 
388476} 
0 commit comments