@@ -28,6 +28,7 @@ pub struct Expression {
28
28
/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
29
29
/// for a gap area is only used as the line execution count if there are no other regions on a
30
30
/// line."
31
+ #[ derive( Debug ) ]
31
32
pub struct FunctionCoverage < ' tcx > {
32
33
instance : Instance < ' tcx > ,
33
34
source_hash : u64 ,
@@ -40,30 +41,34 @@ pub struct FunctionCoverage<'tcx> {
40
41
impl < ' tcx > FunctionCoverage < ' tcx > {
41
42
/// Creates a new set of coverage data for a used (called) function.
42
43
pub fn new ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> Self {
43
- Self :: create ( tcx, instance, true )
44
- }
45
-
46
- /// Creates a new set of coverage data for an unused (never called) function.
47
- pub fn unused ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > ) -> Self {
48
- Self :: create ( tcx, instance, false )
49
- }
50
-
51
- fn create ( tcx : TyCtxt < ' tcx > , instance : Instance < ' tcx > , is_used : bool ) -> Self {
52
44
let coverageinfo = tcx. coverageinfo ( instance. def_id ( ) ) ;
53
45
debug ! (
54
- "FunctionCoverage::new(instance={:?}) has coverageinfo={:?}. is_used={} " ,
55
- instance, coverageinfo, is_used
46
+ "FunctionCoverage::new(instance={:?}) has coverageinfo={:?}" ,
47
+ instance, coverageinfo
56
48
) ;
57
49
Self {
58
50
instance,
59
51
source_hash : 0 , // will be set with the first `add_counter()`
60
- is_used,
52
+ is_used : true ,
61
53
counters : IndexVec :: from_elem_n ( None , coverageinfo. num_counters as usize ) ,
62
54
expressions : IndexVec :: from_elem_n ( None , coverageinfo. num_expressions as usize ) ,
63
55
unreachable_regions : Vec :: new ( ) ,
64
56
}
65
57
}
66
58
59
+ /// Creates a new set of coverage data for an unused (never called) function.
60
+ pub fn unused ( instance : Instance < ' tcx > ) -> Self {
61
+ debug ! ( "FunctionCoverage::unused(instance={:?})" , instance) ;
62
+ Self {
63
+ instance,
64
+ source_hash : 0 , // will be set with the first `add_counter()`
65
+ is_used : false ,
66
+ counters : IndexVec :: from_elem_n ( None , CounterValueReference :: START . as_usize ( ) ) ,
67
+ expressions : IndexVec :: new ( ) ,
68
+ unreachable_regions : Vec :: new ( ) ,
69
+ }
70
+ }
71
+
67
72
/// Returns true for a used (called) function, and false for an unused function.
68
73
pub fn is_used ( & self ) -> bool {
69
74
self . is_used
@@ -142,13 +147,33 @@ impl<'tcx> FunctionCoverage<'tcx> {
142
147
/// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
143
148
/// `CounterMappingRegion`s.
144
149
pub fn get_expressions_and_counter_regions < ' a > (
145
- & ' a self ,
150
+ & ' a mut self ,
146
151
) -> ( Vec < CounterExpression > , impl Iterator < Item = ( Counter , & ' a CodeRegion ) > ) {
147
- assert ! (
148
- self . source_hash != 0 || !self . is_used,
149
- "No counters provided the source_hash for used function: {:?}" ,
150
- self . instance
151
- ) ;
152
+ if self . source_hash == 0 {
153
+ // Either this `FunctionCoverage` is _not_ used (created via
154
+ // `unused()`, or the function had all statements removed, including
155
+ // all `Counter`s.
156
+ //
157
+ // Dead blocks (removed during MIR transform, typically because
158
+ // const evaluation can determine that the block will never be
159
+ // called) are removed before codegen, but any coverage statements
160
+ // are replaced by `Coverage::unreachable` statements at the top of
161
+ // the MIR CFG.
162
+ debug ! ( "No counters provided the source_hash for used function:\n {:?}" , self ) ;
163
+ assert_eq ! (
164
+ self . expressions. len( ) ,
165
+ 0 ,
166
+ "Expressions (from MIR) without counters: {:?}" ,
167
+ self . instance
168
+ ) ;
169
+ // If there are `Unreachable` code regions, but no `Counter`s, we
170
+ // need to add at least one Counter, because LLVM seems to require
171
+ // it.
172
+ if let Some ( unreachable_code_region) = self . unreachable_regions . pop ( ) {
173
+ // Replace any one of the `Unreachable`s with a counter.
174
+ self . counters . push ( Some ( unreachable_code_region) ) ;
175
+ }
176
+ }
152
177
153
178
let counter_regions = self . counter_regions ( ) ;
154
179
let ( counter_expressions, expression_regions) = self . expressions_with_regions ( ) ;
0 commit comments