1
1
use std:: cmp:: Ordering ;
2
2
use std:: collections:: VecDeque ;
3
- use std:: iter;
4
3
use std:: ops:: { Index , IndexMut } ;
4
+ use std:: { iter, slice} ;
5
5
6
6
use rustc_data_structures:: captures:: Captures ;
7
7
use rustc_data_structures:: fx:: FxHashSet ;
@@ -389,34 +389,26 @@ impl BasicCoverageBlockData {
389
389
/// indicates whether that block can potentially be combined into the same BCB
390
390
/// as its sole successor.
391
391
#[ derive( Clone , Copy , Debug ) ]
392
- enum CoverageSuccessors < ' a > {
393
- /// The terminator has exactly one straight-line successor, so its block can
394
- /// potentially be combined into the same BCB as that successor.
395
- Chainable ( BasicBlock ) ,
396
- /// The block cannot be combined into the same BCB as its successor(s).
397
- NotChainable ( & ' a [ BasicBlock ] ) ,
398
- /// Yield terminators are not chainable, and their execution count can also
399
- /// differ from the execution count of their out-edge.
400
- Yield ( BasicBlock ) ,
392
+ struct CoverageSuccessors < ' a > {
393
+ /// Coverage-relevant successors of the corresponding terminator.
394
+ /// There might be 0, 1, or multiple targets.
395
+ targets : & ' a [ BasicBlock ] ,
396
+ /// `Yield` terminators are not chainable, because their sole out-edge is
397
+ /// only followed if/when the generator is resumed after the yield.
398
+ is_yield : bool ,
401
399
}
402
400
403
401
impl CoverageSuccessors < ' _ > {
404
402
fn is_chainable ( & self ) -> bool {
405
- match self {
406
- Self :: Chainable ( _) => true ,
407
- Self :: NotChainable ( _) => false ,
408
- Self :: Yield ( _) => false ,
409
- }
403
+ // If a terminator is out-summable and has exactly one out-edge, then
404
+ // it is eligible to be chained into its successor block.
405
+ self . is_out_summable ( ) && self . targets . len ( ) == 1
410
406
}
411
407
412
408
/// Returns true if the terminator itself is assumed to have the same
413
409
/// execution count as the sum of its out-edges (assuming no panics).
414
410
fn is_out_summable ( & self ) -> bool {
415
- match self {
416
- Self :: Chainable ( _) => true ,
417
- Self :: NotChainable ( _) => true ,
418
- Self :: Yield ( _) => false ,
419
- }
411
+ !self . is_yield && !self . targets . is_empty ( )
420
412
}
421
413
}
422
414
@@ -425,12 +417,7 @@ impl IntoIterator for CoverageSuccessors<'_> {
425
417
type IntoIter = impl DoubleEndedIterator < Item = Self :: Item > ;
426
418
427
419
fn into_iter ( self ) -> Self :: IntoIter {
428
- match self {
429
- Self :: Chainable ( bb) | Self :: Yield ( bb) => {
430
- Some ( bb) . into_iter ( ) . chain ( ( & [ ] ) . iter ( ) . copied ( ) )
431
- }
432
- Self :: NotChainable ( bbs) => None . into_iter ( ) . chain ( bbs. iter ( ) . copied ( ) ) ,
433
- }
420
+ self . targets . iter ( ) . copied ( )
434
421
}
435
422
}
436
423
@@ -440,48 +427,44 @@ impl IntoIterator for CoverageSuccessors<'_> {
440
427
// `catch_unwind()` handlers.
441
428
fn bcb_filtered_successors < ' a , ' tcx > ( terminator : & ' a Terminator < ' tcx > ) -> CoverageSuccessors < ' a > {
442
429
use TerminatorKind :: * ;
443
- match terminator. kind {
430
+ let mut is_yield = false ;
431
+ let targets = match & terminator. kind {
444
432
// A switch terminator can have many coverage-relevant successors.
445
- // (If there is exactly one successor, we still treat it as not chainable.)
446
- SwitchInt { ref targets, .. } => CoverageSuccessors :: NotChainable ( targets. all_targets ( ) ) ,
433
+ SwitchInt { targets, .. } => targets. all_targets ( ) ,
447
434
448
435
// A yield terminator has exactly 1 successor, but should not be chained,
449
436
// because its resume edge has a different execution count.
450
- Yield { resume, .. } => CoverageSuccessors :: Yield ( resume) ,
437
+ Yield { resume, .. } => {
438
+ is_yield = true ;
439
+ slice:: from_ref ( resume)
440
+ }
451
441
452
442
// These terminators have exactly one coverage-relevant successor,
453
443
// and can be chained into it.
454
444
Assert { target, .. }
455
445
| Drop { target, .. }
456
446
| FalseEdge { real_target : target, .. }
457
447
| FalseUnwind { real_target : target, .. }
458
- | Goto { target } => CoverageSuccessors :: Chainable ( target) ,
448
+ | Goto { target } => slice :: from_ref ( target) ,
459
449
460
450
// A call terminator can normally be chained, except when it has no
461
451
// successor because it is known to diverge.
462
- Call { target : maybe_target, .. } => match maybe_target {
463
- Some ( target) => CoverageSuccessors :: Chainable ( target) ,
464
- None => CoverageSuccessors :: NotChainable ( & [ ] ) ,
465
- } ,
452
+ Call { target : maybe_target, .. } => maybe_target. as_slice ( ) ,
466
453
467
454
// An inline asm terminator can normally be chained, except when it
468
455
// diverges or uses asm goto.
469
- InlineAsm { ref targets, .. } => {
470
- if let [ target] = targets[ ..] {
471
- CoverageSuccessors :: Chainable ( target)
472
- } else {
473
- CoverageSuccessors :: NotChainable ( targets)
474
- }
475
- }
456
+ InlineAsm { targets, .. } => & targets,
476
457
477
458
// These terminators have no coverage-relevant successors.
478
459
CoroutineDrop
479
460
| Return
480
461
| TailCall { .. }
481
462
| Unreachable
482
463
| UnwindResume
483
- | UnwindTerminate ( _) => CoverageSuccessors :: NotChainable ( & [ ] ) ,
484
- }
464
+ | UnwindTerminate ( _) => & [ ] ,
465
+ } ;
466
+
467
+ CoverageSuccessors { targets, is_yield }
485
468
}
486
469
487
470
/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
0 commit comments