1
+ use rustc_data_structures:: captures:: Captures ;
1
2
use rustc_data_structures:: graph:: dominators:: { self , Dominators } ;
2
3
use rustc_data_structures:: graph:: { self , GraphSuccessors , WithNumNodes , WithStartNode } ;
3
4
use rustc_index:: bit_set:: BitSet ;
4
5
use rustc_index:: { IndexSlice , IndexVec } ;
5
- use rustc_middle:: mir:: { self , BasicBlock , BasicBlockData , Terminator , TerminatorKind } ;
6
+ use rustc_middle:: mir:: { self , BasicBlock , TerminatorKind } ;
6
7
7
8
use std:: cmp:: Ordering ;
8
9
use std:: ops:: { Index , IndexMut } ;
@@ -36,9 +37,8 @@ impl CoverageGraph {
36
37
}
37
38
let bcb_data = & bcbs[ bcb] ;
38
39
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] )
42
42
{
43
43
if !seen[ successor] {
44
44
seen[ successor] = true ;
@@ -80,10 +80,9 @@ impl CoverageGraph {
80
80
// intentionally omits unwind paths.
81
81
// FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
82
82
// `catch_unwind()` handlers.
83
- let mir_cfg_without_unwind = ShortCircuitPreorder :: new ( & mir_body, bcb_filtered_successors) ;
84
83
85
84
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 ) {
87
86
if let Some ( last) = basic_blocks. last ( ) {
88
87
let predecessors = & mir_body. basic_blocks . predecessors ( ) [ bb] ;
89
88
if predecessors. len ( ) > 1 || !predecessors. contains ( last) {
@@ -109,7 +108,7 @@ impl CoverageGraph {
109
108
}
110
109
basic_blocks. push ( bb) ;
111
110
112
- let term = data . terminator ( ) ;
111
+ let term = mir_body [ bb ] . terminator ( ) ;
113
112
114
113
match term. kind {
115
114
TerminatorKind :: Return { .. }
@@ -316,11 +315,6 @@ impl BasicCoverageBlockData {
316
315
pub fn last_bb ( & self ) -> BasicBlock {
317
316
* self . basic_blocks . last ( ) . unwrap ( )
318
317
}
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
- }
324
318
}
325
319
326
320
/// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`)
@@ -362,26 +356,28 @@ impl std::fmt::Debug for BcbBranch {
362
356
}
363
357
}
364
358
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.
366
361
// FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
367
362
// `catch_unwind()` handlers.
368
363
fn bcb_filtered_successors < ' a , ' tcx > (
369
364
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 )
385
381
}
386
382
387
383
/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
@@ -553,66 +549,28 @@ pub(super) fn find_loop_backedges(
553
549
backedges
554
550
}
555
551
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 > (
561
553
body : & ' a mir:: Body < ' tcx > ,
562
- visited : BitSet < BasicBlock > ,
563
- worklist : Vec < BasicBlock > ,
564
554
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 > ,
572
559
{
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 ] ;
595
562
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 ) {
599
566
continue ;
600
567
}
601
568
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) ) ;
607
570
608
- return Some ( ( idx , data ) ) ;
571
+ return Some ( bb ) ;
609
572
}
610
573
611
574
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
+ } )
618
576
}
0 commit comments