@@ -13,7 +13,7 @@ use rustc_hir::intravisit::{Visitor, walk_expr};
1313use rustc_middle:: hir:: map:: Map ;
1414use rustc_middle:: hir:: nested_filter;
1515use rustc_middle:: mir:: coverage:: {
16- CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind , SourceRegion ,
16+ CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind , Op , SourceRegion ,
1717} ;
1818use rustc_middle:: mir:: {
1919 self , BasicBlock , BasicBlockData , SourceInfo , Statement , StatementKind , Terminator ,
@@ -27,7 +27,7 @@ use tracing::{debug, debug_span, instrument, trace};
2727
2828use crate :: coverage:: counters:: { CounterIncrementSite , CoverageCounters } ;
2929use crate :: coverage:: graph:: CoverageGraph ;
30- use crate :: coverage:: mappings:: ExtractedMappings ;
30+ use crate :: coverage:: mappings:: { BranchArm , ExtractedMappings } ;
3131
3232/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
3333/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
@@ -95,10 +95,10 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
9595 }
9696
9797 let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings. contains ( bcb) ;
98- let coverage_counters =
98+ let mut coverage_counters =
9999 CoverageCounters :: make_bcb_counters ( & basic_coverage_blocks, bcb_has_counter_mappings) ;
100100
101- let mappings = create_mappings ( tcx, & hir_info, & extracted_mappings, & coverage_counters) ;
101+ let mappings = create_mappings ( tcx, & hir_info, & extracted_mappings, & mut coverage_counters) ;
102102 if mappings. is_empty ( ) {
103103 // No spans could be converted into valid mappings, so skip this function.
104104 debug ! ( "no spans could be converted into valid mappings; skipping" ) ;
@@ -140,7 +140,7 @@ fn create_mappings<'tcx>(
140140 tcx : TyCtxt < ' tcx > ,
141141 hir_info : & ExtractedHirInfo ,
142142 extracted_mappings : & ExtractedMappings ,
143- coverage_counters : & CoverageCounters ,
143+ coverage_counters : & mut CoverageCounters ,
144144) -> Vec < Mapping > {
145145 let source_map = tcx. sess . source_map ( ) ;
146146 let body_span = hir_info. body_span ;
@@ -153,25 +153,67 @@ fn create_mappings<'tcx>(
153153 & source_file. name . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO ) . to_string_lossy ( ) ,
154154 ) ;
155155
156- let term_for_bcb = |bcb| {
157- coverage_counters
158- . bcb_counter ( bcb)
159- . expect ( "all BCBs with spans were given counters" )
160- . as_term ( )
161- } ;
162156 let region_for_span = |span : Span | make_source_region ( source_map, file_name, span, body_span) ;
163157
164158 // Fully destructure the mappings struct to make sure we don't miss any kinds.
165159 let ExtractedMappings {
166160 num_bcbs : _,
167161 code_mappings,
168- branch_pairs ,
162+ branch_arm_lists ,
169163 mcdc_bitmap_bytes : _,
170164 mcdc_branches,
171165 mcdc_decisions,
172166 } = extracted_mappings;
173167 let mut mappings = Vec :: new ( ) ;
174168
169+ // Process branch arms first, because they might need to mutate `coverage_counters`
170+ // to create new expressions.
171+ for arm_list in branch_arm_lists {
172+ let mut arms_rev = arm_list. iter ( ) . rev ( ) ;
173+
174+ let mut rest_counter = {
175+ // The last arm's span is ignored, because its BCB is only used as the
176+ // false branch of the second-last arm; it's not a branch of its own.
177+ let Some ( & BranchArm { span : _, pre_guard_bcb, arm_taken_bcb } ) = arms_rev. next ( ) else {
178+ continue ;
179+ } ;
180+ debug_assert_eq ! ( pre_guard_bcb, arm_taken_bcb, "last arm should not have a guard" ) ;
181+ coverage_counters. bcb_counter ( pre_guard_bcb) . expect ( "all relevant BCBs have counters" )
182+ } ;
183+
184+ // All relevant BCBs should have counters, so we can `.unwrap()` them.
185+ for & BranchArm { span, pre_guard_bcb, arm_taken_bcb } in arms_rev {
186+ // Number of times the pattern matched.
187+ let matched_counter = coverage_counters. bcb_counter ( pre_guard_bcb) . unwrap ( ) ;
188+ // Number of times the pattern matched and the guard succeeded.
189+ let arm_taken_counter = coverage_counters. bcb_counter ( arm_taken_bcb) . unwrap ( ) ;
190+ // Total number of times execution logically reached this pattern.
191+ let reached_counter =
192+ coverage_counters. make_expression ( rest_counter, Op :: Add , arm_taken_counter) ;
193+ // Number of times execution reached this pattern, but didn't match it.
194+ let unmatched_counter =
195+ coverage_counters. make_expression ( reached_counter, Op :: Subtract , matched_counter) ;
196+
197+ let kind = MappingKind :: Branch {
198+ true_term : matched_counter. as_term ( ) ,
199+ false_term : unmatched_counter. as_term ( ) ,
200+ } ;
201+
202+ if let Some ( source_region) = region_for_span ( span) {
203+ mappings. push ( Mapping { kind, source_region } ) ;
204+ }
205+
206+ rest_counter = reached_counter;
207+ }
208+ }
209+
210+ let term_for_bcb = |bcb| {
211+ coverage_counters
212+ . bcb_counter ( bcb)
213+ . expect ( "all BCBs with spans were given counters" )
214+ . as_term ( )
215+ } ;
216+
175217 mappings. extend ( code_mappings. iter ( ) . filter_map (
176218 // Ordinary code mappings are the simplest kind.
177219 |& mappings:: CodeMapping { span, bcb } | {
@@ -181,16 +223,6 @@ fn create_mappings<'tcx>(
181223 } ,
182224 ) ) ;
183225
184- mappings. extend ( branch_pairs. iter ( ) . filter_map (
185- |& mappings:: BranchPair { span, true_bcb, false_bcb } | {
186- let true_term = term_for_bcb ( true_bcb) ;
187- let false_term = term_for_bcb ( false_bcb) ;
188- let kind = MappingKind :: Branch { true_term, false_term } ;
189- let source_region = region_for_span ( span) ?;
190- Some ( Mapping { kind, source_region } )
191- } ,
192- ) ) ;
193-
194226 mappings. extend ( mcdc_branches. iter ( ) . filter_map (
195227 |& mappings:: MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth : _ } | {
196228 let source_region = region_for_span ( span) ?;
0 commit comments