@@ -8,7 +8,7 @@ mod spans;
88mod tests;
99
1010use rustc_middle:: mir:: coverage:: {
11- CodeRegion , CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind ,
11+ CodeRegion , CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind , Op ,
1212} ;
1313use rustc_middle:: mir:: {
1414 self , BasicBlock , BasicBlockData , SourceInfo , Statement , StatementKind , Terminator ,
@@ -21,7 +21,7 @@ use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
2121
2222use crate :: coverage:: counters:: { CounterIncrementSite , CoverageCounters } ;
2323use crate :: coverage:: graph:: { BasicCoverageBlock , CoverageGraph } ;
24- use crate :: coverage:: mappings:: ExtractedMappings ;
24+ use crate :: coverage:: mappings:: { BranchArm , ExtractedMappings } ;
2525use crate :: MirPass ;
2626
2727/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
@@ -91,10 +91,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
9191 }
9292
9393 let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings. contains ( bcb) ;
94- let coverage_counters =
94+ let mut coverage_counters =
9595 CoverageCounters :: make_bcb_counters ( & basic_coverage_blocks, bcb_has_counter_mappings) ;
9696
97- let mappings = create_mappings ( tcx, & hir_info, & extracted_mappings, & coverage_counters) ;
97+ let mappings = create_mappings ( tcx, & hir_info, & extracted_mappings, & mut coverage_counters) ;
9898 if mappings. is_empty ( ) {
9999 // No spans could be converted into valid mappings, so skip this function.
100100 debug ! ( "no spans could be converted into valid mappings; skipping" ) ;
@@ -136,7 +136,7 @@ fn create_mappings<'tcx>(
136136 tcx : TyCtxt < ' tcx > ,
137137 hir_info : & ExtractedHirInfo ,
138138 extracted_mappings : & ExtractedMappings ,
139- coverage_counters : & CoverageCounters ,
139+ coverage_counters : & mut CoverageCounters ,
140140) -> Vec < Mapping > {
141141 let source_map = tcx. sess . source_map ( ) ;
142142 let body_span = hir_info. body_span ;
@@ -148,24 +148,66 @@ fn create_mappings<'tcx>(
148148 & source_file. name . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO ) . to_string_lossy ( ) ,
149149 ) ;
150150
151- let term_for_bcb = |bcb| {
152- coverage_counters
153- . bcb_counter ( bcb)
154- . expect ( "all BCBs with spans were given counters" )
155- . as_term ( )
156- } ;
157151 let region_for_span = |span : Span | make_code_region ( source_map, file_name, span, body_span) ;
158152
159153 // Fully destructure the mappings struct to make sure we don't miss any kinds.
160154 let ExtractedMappings {
161155 code_mappings,
162- branch_pairs ,
156+ branch_arm_lists ,
163157 mcdc_bitmap_bytes : _,
164158 mcdc_branches,
165159 mcdc_decisions,
166160 } = extracted_mappings;
167161 let mut mappings = Vec :: new ( ) ;
168162
163+ // Process branch arms first, because they might need to mutate `coverage_counters`
164+ // to create new expressions.
165+ for arm_list in branch_arm_lists {
166+ let mut arms_rev = arm_list. iter ( ) . rev ( ) ;
167+
168+ let mut rest_counter = {
169+ // The last arm's span is ignored, because its BCB is only used as the
170+ // false branch of the second-last arm; it's not a branch of its own.
171+ let Some ( & BranchArm { span : _, pre_guard_bcb, arm_taken_bcb } ) = arms_rev. next ( ) else {
172+ continue ;
173+ } ;
174+ debug_assert_eq ! ( pre_guard_bcb, arm_taken_bcb, "last arm should not have a guard" ) ;
175+ coverage_counters. bcb_counter ( pre_guard_bcb) . expect ( "all relevant BCBs have counters" )
176+ } ;
177+
178+ // All relevant BCBs should have counters, so we can `.unwrap()` them.
179+ for & BranchArm { span, pre_guard_bcb, arm_taken_bcb } in arms_rev {
180+ // Number of times the pattern matched.
181+ let matched_counter = coverage_counters. bcb_counter ( pre_guard_bcb) . unwrap ( ) ;
182+ // Number of times the pattern matched and the guard succeeded.
183+ let arm_taken_counter = coverage_counters. bcb_counter ( arm_taken_bcb) . unwrap ( ) ;
184+ // Total number of times execution logically reached this pattern.
185+ let reached_counter =
186+ coverage_counters. make_expression ( rest_counter, Op :: Add , arm_taken_counter) ;
187+ // Number of times execution reached this pattern, but didn't match it.
188+ let unmatched_counter =
189+ coverage_counters. make_expression ( reached_counter, Op :: Subtract , matched_counter) ;
190+
191+ let kind = MappingKind :: Branch {
192+ true_term : matched_counter. as_term ( ) ,
193+ false_term : unmatched_counter. as_term ( ) ,
194+ } ;
195+
196+ if let Some ( code_region) = region_for_span ( span) {
197+ mappings. push ( Mapping { kind, code_region } ) ;
198+ }
199+
200+ rest_counter = reached_counter;
201+ }
202+ }
203+
204+ let term_for_bcb = |bcb| {
205+ coverage_counters
206+ . bcb_counter ( bcb)
207+ . expect ( "all BCBs with spans were given counters" )
208+ . as_term ( )
209+ } ;
210+
169211 mappings. extend ( code_mappings. iter ( ) . filter_map (
170212 // Ordinary code mappings are the simplest kind.
171213 |& mappings:: CodeMapping { span, bcb } | {
@@ -175,16 +217,6 @@ fn create_mappings<'tcx>(
175217 } ,
176218 ) ) ;
177219
178- mappings. extend ( branch_pairs. iter ( ) . filter_map (
179- |& mappings:: BranchPair { span, true_bcb, false_bcb } | {
180- let true_term = term_for_bcb ( true_bcb) ;
181- let false_term = term_for_bcb ( false_bcb) ;
182- let kind = MappingKind :: Branch { true_term, false_term } ;
183- let code_region = region_for_span ( span) ?;
184- Some ( Mapping { kind, code_region } )
185- } ,
186- ) ) ;
187-
188220 mappings. extend ( mcdc_branches. iter ( ) . filter_map (
189221 |& mappings:: MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth : _ } | {
190222 let code_region = region_for_span ( span) ?;
0 commit comments