@@ -23,14 +23,13 @@ pub struct FunctionCoverage<'tcx> {
23
23
function_coverage_info : & ' tcx FunctionCoverageInfo ,
24
24
is_used : bool ,
25
25
26
- /// Tracks which counters have been seen, to avoid duplicate mappings
27
- /// that might be introduced by MIR inlining .
26
+ /// Tracks which counters have been seen, so that we can identify mappings
27
+ /// to counters that were optimized out, and set them to zero .
28
28
counters_seen : BitSet < CounterId > ,
29
29
expressions : IndexVec < ExpressionId , Option < Expression > > ,
30
30
/// Tracks which expressions are known to always have a value of zero.
31
31
/// Only updated during the finalize step.
32
32
zero_expressions : FxIndexSet < ExpressionId > ,
33
- mappings : Vec < Mapping > ,
34
33
}
35
34
36
35
impl < ' tcx > FunctionCoverage < ' tcx > {
@@ -67,7 +66,6 @@ impl<'tcx> FunctionCoverage<'tcx> {
67
66
counters_seen : BitSet :: new_empty ( num_counters) ,
68
67
expressions : IndexVec :: from_elem_n ( None , num_expressions) ,
69
68
zero_expressions : FxIndexSet :: default ( ) ,
70
- mappings : Vec :: new ( ) ,
71
69
}
72
70
}
73
71
@@ -76,28 +74,20 @@ impl<'tcx> FunctionCoverage<'tcx> {
76
74
self . is_used
77
75
}
78
76
79
- /// Adds code regions to be counted by an injected counter intrinsic .
77
+ /// Marks a counter ID as having been seen in a counter-increment statement .
80
78
#[ instrument( level = "debug" , skip( self ) ) ]
81
- pub ( crate ) fn add_counter ( & mut self , id : CounterId , code_regions : & [ CodeRegion ] ) {
82
- if self . counters_seen . insert ( id) {
83
- self . add_mappings ( CovTerm :: Counter ( id) , code_regions) ;
84
- }
79
+ pub ( crate ) fn add_counter ( & mut self , id : CounterId ) {
80
+ self . counters_seen . insert ( id) ;
85
81
}
86
82
87
- /// Adds information about a coverage expression, along with zero or more
88
- /// code regions mapped to that expression.
89
- ///
90
- /// Both counters and "counter expressions" (or simply, "expressions") can be operands in other
91
- /// expressions. These are tracked as separate variants of `CovTerm`, so there is no ambiguity
92
- /// between operands that are counter IDs and operands that are expression IDs.
83
+ /// Adds information about a coverage expression.
93
84
#[ instrument( level = "debug" , skip( self ) ) ]
94
85
pub ( crate ) fn add_counter_expression (
95
86
& mut self ,
96
87
expression_id : ExpressionId ,
97
88
lhs : CovTerm ,
98
89
op : Op ,
99
90
rhs : CovTerm ,
100
- code_regions : & [ CodeRegion ] ,
101
91
) {
102
92
debug_assert ! (
103
93
expression_id. as_usize( ) < self . expressions. len( ) ,
@@ -111,10 +101,7 @@ impl<'tcx> FunctionCoverage<'tcx> {
111
101
let expression = Expression { lhs, op, rhs } ;
112
102
let slot = & mut self . expressions [ expression_id] ;
113
103
match slot {
114
- None => {
115
- * slot = Some ( expression) ;
116
- self . add_mappings ( CovTerm :: Expression ( expression_id) , code_regions) ;
117
- }
104
+ None => * slot = Some ( expression) ,
118
105
// If this expression ID slot has already been filled, it should
119
106
// contain identical information.
120
107
Some ( ref previous_expression) => assert_eq ! (
@@ -124,25 +111,8 @@ impl<'tcx> FunctionCoverage<'tcx> {
124
111
}
125
112
}
126
113
127
- /// Adds regions that will be marked as "unreachable", with a constant "zero counter".
128
- #[ instrument( level = "debug" , skip( self ) ) ]
129
- pub ( crate ) fn add_unreachable_regions ( & mut self , code_regions : & [ CodeRegion ] ) {
130
- assert ! ( !code_regions. is_empty( ) , "unreachable regions always have code regions" ) ;
131
- self . add_mappings ( CovTerm :: Zero , code_regions) ;
132
- }
133
-
134
- #[ instrument( level = "debug" , skip( self ) ) ]
135
- fn add_mappings ( & mut self , term : CovTerm , code_regions : & [ CodeRegion ] ) {
136
- self . mappings
137
- . extend ( code_regions. iter ( ) . cloned ( ) . map ( |code_region| Mapping { term, code_region } ) ) ;
138
- }
139
-
140
114
pub ( crate ) fn finalize ( & mut self ) {
141
115
self . update_zero_expressions ( ) ;
142
-
143
- // Sort all of the collected mappings into a predictable order.
144
- // (Mappings have a total order, so an unstable sort should be fine.)
145
- self . mappings . sort_unstable ( ) ;
146
116
}
147
117
148
118
/// Identify expressions that will always have a value of zero, and note
@@ -249,8 +219,17 @@ impl<'tcx> FunctionCoverage<'tcx> {
249
219
/// Converts this function's coverage mappings into an intermediate form
250
220
/// that will be used by `mapgen` when preparing for FFI.
251
221
pub ( crate ) fn mappings_for_ffi ( & self ) -> impl Iterator < Item = ( Counter , & CodeRegion ) > {
252
- self . mappings . iter ( ) . map ( |& Mapping { term, ref code_region } | {
253
- let counter = Counter :: from_term ( term) ;
222
+ self . function_coverage_info . mappings . iter ( ) . map ( |& Mapping { term, ref code_region } | {
223
+ // Historically, mappings were stored directly in counter/expression
224
+ // statements in MIR, and MIR optimizations would sometimes remove them.
225
+ // That's mostly no longer true, so now we detect cases where that would
226
+ // have happened, and zero out the corresponding mappings here instead.
227
+ let force_to_zero = match term {
228
+ CovTerm :: Counter ( id) => !self . counters_seen . contains ( id) ,
229
+ CovTerm :: Expression ( id) => self . zero_expressions . contains ( & id) ,
230
+ CovTerm :: Zero => false ,
231
+ } ;
232
+ let counter = if force_to_zero { Counter :: ZERO } else { Counter :: from_term ( term) } ;
254
233
( counter, code_region)
255
234
} )
256
235
}
0 commit comments