@@ -28,6 +28,7 @@ pub struct Expression {
2828/// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count
2929/// for a gap area is only used as the line execution count if there are no other regions on a
3030/// line."
31+ #[ derive( Debug ) ]
3132pub struct FunctionCoverage < ' tcx > {
3233 instance : Instance < ' tcx > ,
3334 source_hash : u64 ,
@@ -40,30 +41,34 @@ pub struct FunctionCoverage<'tcx> {
4041impl < ' tcx > FunctionCoverage < ' tcx > {
4142 /// Creates a new set of coverage data for a used (called) function.
4243 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 {
5244 let coverageinfo = tcx. coverageinfo ( instance. def_id ( ) ) ;
5345 debug ! (
54- "FunctionCoverage::new(instance={:?}) has coverageinfo={:?}. is_used={} " ,
55- instance, coverageinfo, is_used
46+ "FunctionCoverage::new(instance={:?}) has coverageinfo={:?}" ,
47+ instance, coverageinfo
5648 ) ;
5749 Self {
5850 instance,
5951 source_hash : 0 , // will be set with the first `add_counter()`
60- is_used,
52+ is_used : true ,
6153 counters : IndexVec :: from_elem_n ( None , coverageinfo. num_counters as usize ) ,
6254 expressions : IndexVec :: from_elem_n ( None , coverageinfo. num_expressions as usize ) ,
6355 unreachable_regions : Vec :: new ( ) ,
6456 }
6557 }
6658
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+
6772 /// Returns true for a used (called) function, and false for an unused function.
6873 pub fn is_used ( & self ) -> bool {
6974 self . is_used
@@ -142,13 +147,33 @@ impl<'tcx> FunctionCoverage<'tcx> {
142147 /// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create
143148 /// `CounterMappingRegion`s.
144149 pub fn get_expressions_and_counter_regions < ' a > (
145- & ' a self ,
150+ & ' a mut self ,
146151 ) -> ( 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+ }
152177
153178 let counter_regions = self . counter_regions ( ) ;
154179 let ( counter_expressions, expression_regions) = self . expressions_with_regions ( ) ;
0 commit comments