@@ -8,7 +8,7 @@ mod spans;
8
8
mod tests;
9
9
10
10
use rustc_middle:: mir:: coverage:: {
11
- CodeRegion , CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind ,
11
+ CodeRegion , CoverageKind , DecisionInfo , FunctionCoverageInfo , Mapping , MappingKind , Op ,
12
12
} ;
13
13
use rustc_middle:: mir:: {
14
14
self , BasicBlock , BasicBlockData , SourceInfo , Statement , StatementKind , Terminator ,
@@ -21,7 +21,7 @@ use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
21
21
22
22
use crate :: coverage:: counters:: { CounterIncrementSite , CoverageCounters } ;
23
23
use crate :: coverage:: graph:: { BasicCoverageBlock , CoverageGraph } ;
24
- use crate :: coverage:: mappings:: ExtractedMappings ;
24
+ use crate :: coverage:: mappings:: { BranchArm , ExtractedMappings } ;
25
25
use crate :: MirPass ;
26
26
27
27
/// 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:
91
91
}
92
92
93
93
let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings. contains ( bcb) ;
94
- let coverage_counters =
94
+ let mut coverage_counters =
95
95
CoverageCounters :: make_bcb_counters ( & basic_coverage_blocks, bcb_has_counter_mappings) ;
96
96
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) ;
98
98
if mappings. is_empty ( ) {
99
99
// No spans could be converted into valid mappings, so skip this function.
100
100
debug ! ( "no spans could be converted into valid mappings; skipping" ) ;
@@ -136,7 +136,7 @@ fn create_mappings<'tcx>(
136
136
tcx : TyCtxt < ' tcx > ,
137
137
hir_info : & ExtractedHirInfo ,
138
138
extracted_mappings : & ExtractedMappings ,
139
- coverage_counters : & CoverageCounters ,
139
+ coverage_counters : & mut CoverageCounters ,
140
140
) -> Vec < Mapping > {
141
141
let source_map = tcx. sess . source_map ( ) ;
142
142
let body_span = hir_info. body_span ;
@@ -148,24 +148,66 @@ fn create_mappings<'tcx>(
148
148
& source_file. name . for_scope ( tcx. sess , RemapPathScopeComponents :: MACRO ) . to_string_lossy ( ) ,
149
149
) ;
150
150
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
- } ;
157
151
let region_for_span = |span : Span | make_code_region ( source_map, file_name, span, body_span) ;
158
152
159
153
// Fully destructure the mappings struct to make sure we don't miss any kinds.
160
154
let ExtractedMappings {
161
155
code_mappings,
162
- branch_pairs ,
156
+ branch_arm_lists ,
163
157
mcdc_bitmap_bytes : _,
164
158
mcdc_branches,
165
159
mcdc_decisions,
166
160
} = extracted_mappings;
167
161
let mut mappings = Vec :: new ( ) ;
168
162
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
+
169
211
mappings. extend ( code_mappings. iter ( ) . filter_map (
170
212
// Ordinary code mappings are the simplest kind.
171
213
|& mappings:: CodeMapping { span, bcb } | {
@@ -175,16 +217,6 @@ fn create_mappings<'tcx>(
175
217
} ,
176
218
) ) ;
177
219
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
-
188
220
mappings. extend ( mcdc_branches. iter ( ) . filter_map (
189
221
|& mappings:: MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth : _ } | {
190
222
let code_region = region_for_span ( span) ?;
0 commit comments