@@ -91,74 +91,41 @@ impl CoverageGraph {
9191 // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
9292 // `catch_unwind()` handlers.
9393
94+ // Accumulates a chain of blocks that will be combined into one BCB.
9495 let mut basic_blocks = Vec :: new ( ) ;
96+
9597 let filtered_successors = |bb| bcb_filtered_successors ( mir_body[ bb] . terminator ( ) ) ;
9698 for bb in short_circuit_preorder ( mir_body, filtered_successors)
9799 . filter ( |& bb| mir_body[ bb] . terminator ( ) . kind != TerminatorKind :: Unreachable )
98100 {
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+ ) ;
121121 }
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- }
144122
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) ;
156124 }
157125
158126 if !basic_blocks. is_empty ( ) {
159- // process any remaining basic_blocks into a final `BasicCoverageBlockData`
127+ debug ! ( "flushing accumulated blocks into one last BCB" ) ;
160128 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" ) ;
162129 }
163130
164131 ( bcbs, bb_to_bcb)
@@ -350,6 +317,15 @@ enum CoverageSuccessors<'a> {
350317 NotChainable ( & ' a [ BasicBlock ] ) ,
351318}
352319
320+ impl CoverageSuccessors < ' _ > {
321+ fn is_chainable ( & self ) -> bool {
322+ match self {
323+ Self :: Chainable ( _) => true ,
324+ Self :: NotChainable ( _) => false ,
325+ }
326+ }
327+ }
328+
353329impl IntoIterator for CoverageSuccessors < ' _ > {
354330 type Item = BasicBlock ;
355331 type IntoIter = impl DoubleEndedIterator < Item = Self :: Item > ;
0 commit comments