@@ -91,74 +91,41 @@ impl CoverageGraph {
91
91
// FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
92
92
// `catch_unwind()` handlers.
93
93
94
+ // Accumulates a chain of blocks that will be combined into one BCB.
94
95
let mut basic_blocks = Vec :: new ( ) ;
96
+
95
97
let filtered_successors = |bb| bcb_filtered_successors ( mir_body[ bb] . terminator ( ) ) ;
96
98
for bb in short_circuit_preorder ( mir_body, filtered_successors)
97
99
. filter ( |& bb| mir_body[ bb] . terminator ( ) . kind != TerminatorKind :: Unreachable )
98
100
{
99
- if let Some ( last) = basic_blocks. last ( ) {
100
- let predecessors = & mir_body. basic_blocks . predecessors ( ) [ bb] ;
101
- if predecessors. len ( ) > 1 || !predecessors. contains ( last) {
102
- // The `bb` has more than one _incoming_ edge, and should start its own
103
- // `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet
104
- // include `bb`; it contains a sequence of one or more sequential basic_blocks
105
- // with no intermediate branches in or out. Save these as a new
106
- // `BasicCoverageBlockData` before starting the new one.)
107
- Self :: add_basic_coverage_block (
108
- & mut bcbs,
109
- & mut bb_to_bcb,
110
- basic_blocks. split_off ( 0 ) ,
111
- ) ;
112
- debug ! (
113
- " because {}" ,
114
- if predecessors. len( ) > 1 {
115
- "predecessors.len() > 1" . to_owned( )
116
- } else {
117
- format!( "bb {} is not in predecessors: {:?}" , bb. index( ) , predecessors)
118
- }
119
- ) ;
120
- }
101
+ // If the previous block can't be chained into `bb`, flush the accumulated
102
+ // blocks into a new BCB, then start building the next chain.
103
+ if let Some ( & prev) = basic_blocks. last ( )
104
+ && ( !filtered_successors ( prev) . is_chainable ( ) || {
105
+ // If `bb` has multiple predecessor blocks, or `prev` isn't
106
+ // one of its predecessors, we can't chain and must flush.
107
+ let predecessors = & mir_body. basic_blocks . predecessors ( ) [ bb] ;
108
+ predecessors. len ( ) > 1 || !predecessors. contains ( & prev)
109
+ } )
110
+ {
111
+ debug ! (
112
+ terminator_kind = ?mir_body[ prev] . terminator( ) . kind,
113
+ predecessors = ?& mir_body. basic_blocks. predecessors( ) [ bb] ,
114
+ "can't chain from {prev:?} to {bb:?}"
115
+ ) ;
116
+ Self :: add_basic_coverage_block (
117
+ & mut bcbs,
118
+ & mut bb_to_bcb,
119
+ basic_blocks. split_off ( 0 ) ,
120
+ ) ;
121
121
}
122
- basic_blocks. push ( bb) ;
123
-
124
- let term = mir_body[ bb] . terminator ( ) ;
125
-
126
- match bcb_filtered_successors ( term) {
127
- CoverageSuccessors :: NotChainable ( _) => {
128
- // The `bb` has more than one _outgoing_ edge, or exits the function. Save the
129
- // current sequence of `basic_blocks` gathered to this point, as a new
130
- // `BasicCoverageBlockData`.
131
- Self :: add_basic_coverage_block (
132
- & mut bcbs,
133
- & mut bb_to_bcb,
134
- basic_blocks. split_off ( 0 ) ,
135
- ) ;
136
- debug ! ( " because term.kind = {:?}" , term. kind) ;
137
- // Note that this condition is based on `TerminatorKind`, even though it
138
- // theoretically boils down to `successors().len() != 1`; that is, either zero
139
- // (e.g., `Return`, `Terminate`) or multiple successors (e.g., `SwitchInt`), but
140
- // since the BCB CFG ignores things like unwind branches (which exist in the
141
- // `Terminator`s `successors()` list) checking the number of successors won't
142
- // work.
143
- }
144
122
145
- // The following `TerminatorKind`s are either not expected outside an unwind branch,
146
- // or they should not (under normal circumstances) branch. Coverage graphs are
147
- // simplified by assuring coverage results are accurate for program executions that
148
- // don't panic.
149
- //
150
- // Programs that panic and unwind may record slightly inaccurate coverage results
151
- // for a coverage region containing the `Terminator` that began the panic. This
152
- // is as intended. (See Issue #78544 for a possible future option to support
153
- // coverage in test programs that panic.)
154
- CoverageSuccessors :: Chainable ( _) => { }
155
- }
123
+ basic_blocks. push ( bb) ;
156
124
}
157
125
158
126
if !basic_blocks. is_empty ( ) {
159
- // process any remaining basic_blocks into a final `BasicCoverageBlockData`
127
+ debug ! ( "flushing accumulated blocks into one last BCB" ) ;
160
128
Self :: add_basic_coverage_block ( & mut bcbs, & mut bb_to_bcb, basic_blocks. split_off ( 0 ) ) ;
161
- debug ! ( " because the end of the MIR CFG was reached while traversing" ) ;
162
129
}
163
130
164
131
( bcbs, bb_to_bcb)
@@ -350,6 +317,15 @@ enum CoverageSuccessors<'a> {
350
317
NotChainable ( & ' a [ BasicBlock ] ) ,
351
318
}
352
319
320
+ impl CoverageSuccessors < ' _ > {
321
+ fn is_chainable ( & self ) -> bool {
322
+ match self {
323
+ Self :: Chainable ( _) => true ,
324
+ Self :: NotChainable ( _) => false ,
325
+ }
326
+ }
327
+ }
328
+
353
329
impl IntoIterator for CoverageSuccessors < ' _ > {
354
330
type Item = BasicBlock ;
355
331
type IntoIter = impl DoubleEndedIterator < Item = Self :: Item > ;
0 commit comments