1+ use rustc_data_structures:: captures:: Captures ;
12use rustc_data_structures:: graph:: dominators:: { self , Dominators } ;
23use rustc_data_structures:: graph:: { self , GraphSuccessors , WithNumNodes , WithStartNode } ;
34use rustc_index:: bit_set:: BitSet ;
45use rustc_index:: { IndexSlice , IndexVec } ;
5- use rustc_middle:: mir:: { self , BasicBlock , BasicBlockData , Terminator , TerminatorKind } ;
6+ use rustc_middle:: mir:: { self , BasicBlock , TerminatorKind } ;
67
78use std:: cmp:: Ordering ;
89use std:: ops:: { Index , IndexMut } ;
@@ -36,9 +37,8 @@ impl CoverageGraph {
3637 }
3738 let bcb_data = & bcbs[ bcb] ;
3839 let mut bcb_successors = Vec :: new ( ) ;
39- for successor in
40- bcb_filtered_successors ( & mir_body, & bcb_data. terminator ( mir_body) . kind )
41- . filter_map ( |successor_bb| bb_to_bcb[ successor_bb] )
40+ for successor in bcb_filtered_successors ( & mir_body, bcb_data. last_bb ( ) )
41+ . filter_map ( |successor_bb| bb_to_bcb[ successor_bb] )
4242 {
4343 if !seen[ successor] {
4444 seen[ successor] = true ;
@@ -80,10 +80,9 @@ impl CoverageGraph {
8080 // intentionally omits unwind paths.
8181 // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
8282 // `catch_unwind()` handlers.
83- let mir_cfg_without_unwind = ShortCircuitPreorder :: new ( & mir_body, bcb_filtered_successors) ;
8483
8584 let mut basic_blocks = Vec :: new ( ) ;
86- for ( bb , data ) in mir_cfg_without_unwind {
85+ for bb in short_circuit_preorder ( mir_body , bcb_filtered_successors ) {
8786 if let Some ( last) = basic_blocks. last ( ) {
8887 let predecessors = & mir_body. basic_blocks . predecessors ( ) [ bb] ;
8988 if predecessors. len ( ) > 1 || !predecessors. contains ( last) {
@@ -109,7 +108,7 @@ impl CoverageGraph {
109108 }
110109 basic_blocks. push ( bb) ;
111110
112- let term = data . terminator ( ) ;
111+ let term = mir_body [ bb ] . terminator ( ) ;
113112
114113 match term. kind {
115114 TerminatorKind :: Return { .. }
@@ -316,11 +315,6 @@ impl BasicCoverageBlockData {
316315 pub fn last_bb ( & self ) -> BasicBlock {
317316 * self . basic_blocks . last ( ) . unwrap ( )
318317 }
319-
320- #[ inline( always) ]
321- pub fn terminator < ' a , ' tcx > ( & self , mir_body : & ' a mir:: Body < ' tcx > ) -> & ' a Terminator < ' tcx > {
322- & mir_body[ self . last_bb ( ) ] . terminator ( )
323- }
324318}
325319
326320/// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`)
@@ -362,26 +356,28 @@ impl std::fmt::Debug for BcbBranch {
362356 }
363357}
364358
365- // Returns the `Terminator`s non-unwind successors.
359+ // Returns the subset of a block's successors that are relevant to the coverage
360+ // graph, i.e. those that do not represent unwinds or unreachable branches.
366361// FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
367362// `catch_unwind()` handlers.
368363fn bcb_filtered_successors < ' a , ' tcx > (
369364 body : & ' a mir:: Body < ' tcx > ,
370- term_kind : & ' a TerminatorKind < ' tcx > ,
371- ) -> Box < dyn Iterator < Item = BasicBlock > + ' a > {
372- Box :: new (
373- match & term_kind {
374- // SwitchInt successors are never unwind, and all of them should be traversed.
375- TerminatorKind :: SwitchInt { ref targets, .. } => {
376- None . into_iter ( ) . chain ( targets. all_targets ( ) . into_iter ( ) . copied ( ) )
377- }
378- // For all other kinds, return only the first successor, if any, and ignore unwinds.
379- // NOTE: `chain(&[])` is required to coerce the `option::iter` (from
380- // `next().into_iter()`) into the `mir::Successors` aliased type.
381- _ => term_kind. successors ( ) . next ( ) . into_iter ( ) . chain ( ( & [ ] ) . into_iter ( ) . copied ( ) ) ,
382- }
383- . filter ( move |& successor| body[ successor] . terminator ( ) . kind != TerminatorKind :: Unreachable ) ,
384- )
365+ bb : BasicBlock ,
366+ ) -> impl Iterator < Item = BasicBlock > + Captures < ' a > + Captures < ' tcx > {
367+ let terminator = body[ bb] . terminator ( ) ;
368+
369+ let take_n_successors = match terminator. kind {
370+ // SwitchInt successors are never unwinds, so all of them should be traversed.
371+ TerminatorKind :: SwitchInt { .. } => usize:: MAX ,
372+ // For all other kinds, return only the first successor (if any), ignoring any
373+ // unwind successors.
374+ _ => 1 ,
375+ } ;
376+
377+ terminator
378+ . successors ( )
379+ . take ( take_n_successors)
380+ . filter ( move |& successor| body[ successor] . terminator ( ) . kind != TerminatorKind :: Unreachable )
385381}
386382
387383/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
@@ -553,66 +549,28 @@ pub(super) fn find_loop_backedges(
553549 backedges
554550}
555551
556- pub struct ShortCircuitPreorder <
557- ' a ,
558- ' tcx ,
559- F : Fn ( & ' a mir:: Body < ' tcx > , & ' a TerminatorKind < ' tcx > ) -> Box < dyn Iterator < Item = BasicBlock > + ' a > ,
560- > {
552+ fn short_circuit_preorder < ' a , ' tcx , F , Iter > (
561553 body : & ' a mir:: Body < ' tcx > ,
562- visited : BitSet < BasicBlock > ,
563- worklist : Vec < BasicBlock > ,
564554 filtered_successors : F ,
565- }
566-
567- impl <
568- ' a ,
569- ' tcx ,
570- F : Fn ( & ' a mir:: Body < ' tcx > , & ' a TerminatorKind < ' tcx > ) -> Box < dyn Iterator < Item = BasicBlock > + ' a > ,
571- > ShortCircuitPreorder < ' a , ' tcx , F >
555+ ) -> impl Iterator < Item = BasicBlock > + Captures < ' a > + Captures < ' tcx >
556+ where
557+ F : Fn ( & ' a mir:: Body < ' tcx > , BasicBlock ) -> Iter ,
558+ Iter : Iterator < Item = BasicBlock > ,
572559{
573- pub fn new (
574- body : & ' a mir:: Body < ' tcx > ,
575- filtered_successors : F ,
576- ) -> ShortCircuitPreorder < ' a , ' tcx , F > {
577- let worklist = vec ! [ mir:: START_BLOCK ] ;
578-
579- ShortCircuitPreorder {
580- body,
581- visited : BitSet :: new_empty ( body. basic_blocks . len ( ) ) ,
582- worklist,
583- filtered_successors,
584- }
585- }
586- }
587-
588- impl <
589- ' a ,
590- ' tcx ,
591- F : Fn ( & ' a mir:: Body < ' tcx > , & ' a TerminatorKind < ' tcx > ) -> Box < dyn Iterator < Item = BasicBlock > + ' a > ,
592- > Iterator for ShortCircuitPreorder < ' a , ' tcx , F >
593- {
594- type Item = ( BasicBlock , & ' a BasicBlockData < ' tcx > ) ;
560+ let mut visited = BitSet :: new_empty ( body. basic_blocks . len ( ) ) ;
561+ let mut worklist = vec ! [ mir:: START_BLOCK ] ;
595562
596- fn next ( & mut self ) -> Option < ( BasicBlock , & ' a BasicBlockData < ' tcx > ) > {
597- while let Some ( idx ) = self . worklist . pop ( ) {
598- if !self . visited . insert ( idx ) {
563+ std :: iter :: from_fn ( move || {
564+ while let Some ( bb ) = worklist. pop ( ) {
565+ if !visited. insert ( bb ) {
599566 continue ;
600567 }
601568
602- let data = & self . body [ idx] ;
603-
604- if let Some ( ref term) = data. terminator {
605- self . worklist . extend ( ( self . filtered_successors ) ( & self . body , & term. kind ) ) ;
606- }
569+ worklist. extend ( filtered_successors ( body, bb) ) ;
607570
608- return Some ( ( idx , data ) ) ;
571+ return Some ( bb ) ;
609572 }
610573
611574 None
612- }
613-
614- fn size_hint ( & self ) -> ( usize , Option < usize > ) {
615- let size = self . body . basic_blocks . len ( ) - self . visited . count ( ) ;
616- ( size, Some ( size) )
617- }
575+ } )
618576}
0 commit comments