Function rustc_mir_transform::simplify::save_unreachable_coverage
source · fn save_unreachable_coverage(
basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'_>>,
source_scopes: &IndexSlice<SourceScope, SourceScopeData<'_>>,
reachable: &BitSet<BasicBlock>
)
Expand description
Some MIR transforms can determine at compile time that a sequences of
statements will never be executed, so they can be dropped from the MIR.
For example, an if
or else
block that is guaranteed to never be executed
because its condition can be evaluated at compile time, such as by const
evaluation: if false { ... }
.
Those statements are bypassed by redirecting paths in the CFG around the
dead blocks
; but with -C instrument-coverage
, the dead blocks usually
include Coverage
statements representing the Rust source code regions to
be counted at runtime. Without these Coverage
statements, the regions are
lost, and the Rust source code will show no coverage information.
What we want to show in a coverage report is the dead code with coverage
counts of 0
. To do this, we need to save the code regions, by injecting
Unreachable
coverage statements. These are non-executable statements whose
code regions are still recorded in the coverage map, representing regions
with 0
executions.
If there are no live Counter
Coverage
statements remaining, we remove
Coverage
statements along with the dead blocks. Since at least one
counter per function is required by LLVM (and necessary, to add the
function_hash
to the counter’s call to the LLVM intrinsic
instrprof.increment()
).
The generator::StateTransform
MIR pass and MIR inlining can create
atypical conditions, where all live Counter
s are dropped from the MIR.
With MIR inlining we can have coverage counters belonging to different instances in a single body, so the strategy described above is applied to coverage counters from each instance individually.