@@ -456,21 +456,41 @@ impl<'a,'tcx> Builder<'a,'tcx> {
456
456
/// See module comment for more details. None indicates there’s no
457
457
/// cleanup to do at this point.
458
458
pub fn diverge_cleanup ( & mut self ) -> Option < BasicBlock > {
459
- if self . scopes . is_empty ( ) {
459
+ if self . scopes . iter ( ) . all ( |scope| scope . drops . is_empty ( ) && scope . free . is_none ( ) ) {
460
460
return None ;
461
461
}
462
+ assert ! ( !self . scopes. is_empty( ) ) ; // or `all` above would be true
463
+
462
464
let unit_temp = self . get_unit_temp ( ) ;
463
- let Builder { ref mut hir, ref mut cfg, ref mut scopes, .. } = * self ;
464
-
465
- // Given an array of scopes, we generate these from the outermost scope to the innermost
466
- // one. Thus for array [S0, S1, S2] with corresponding cleanup blocks [B0, B1, B2], we will
467
- // generate B0 <- B1 <- B2 in left-to-right order. Control flow of the generated blocks
468
- // always ends up at a block with the Resume terminator.
469
- if scopes. iter ( ) . any ( |scope| !scope. drops . is_empty ( ) || scope. free . is_some ( ) ) {
470
- Some ( build_diverge_scope ( hir. tcx ( ) , self . fn_span , cfg, & unit_temp, scopes) )
465
+ let Builder { ref mut hir, ref mut cfg, ref mut scopes,
466
+ ref mut cached_resume_block, .. } = * self ;
467
+
468
+ // Build up the drops in **reverse** order. The end result will
469
+ // look like:
470
+ //
471
+ // scopes[n] -> scopes[n-1] -> ... -> scopes[0]
472
+ //
473
+ // However, we build this in **reverse order**. That is, we
474
+ // process scopes[0], then scopes[1], etc, pointing each one at
475
+ // the result generates from the one before. Along the way, we
476
+ // store caches. If everything is cached, we'll just walk right
477
+ // to left reading the cached results but never created anything.
478
+
479
+ // To start, create the resume terminator.
480
+ let mut target = if let Some ( target) = * cached_resume_block {
481
+ target
471
482
} else {
472
- None
483
+ let resumeblk = cfg. start_new_cleanup_block ( ) ;
484
+ cfg. terminate ( resumeblk, scopes[ 0 ] . id , self . fn_span , TerminatorKind :: Resume ) ;
485
+ * cached_resume_block = Some ( resumeblk) ;
486
+ resumeblk
487
+ } ;
488
+
489
+ for scope in scopes {
490
+ target = build_diverge_scope ( hir. tcx ( ) , cfg, & unit_temp, scope, target) ;
473
491
}
492
+
493
+ Some ( target)
474
494
}
475
495
476
496
/// Utility function for *non*-scope code to build their own drops
@@ -640,43 +660,25 @@ fn build_scope_drops<'tcx>(cfg: &mut CFG<'tcx>,
640
660
}
641
661
642
662
fn build_diverge_scope < ' tcx > ( tcx : & TyCtxt < ' tcx > ,
643
- fn_span : Span ,
644
663
cfg : & mut CFG < ' tcx > ,
645
664
unit_temp : & Lvalue < ' tcx > ,
646
- scopes : & mut [ Scope < ' tcx > ] )
665
+ scope : & mut Scope < ' tcx > ,
666
+ mut target : BasicBlock )
647
667
-> BasicBlock
648
668
{
649
- assert ! ( scopes. len( ) >= 1 ) ;
650
-
651
669
// Build up the drops in **reverse** order. The end result will
652
670
// look like:
653
671
//
654
- // [drops[n]] -...-> [drops[0]] -> [Free] -> [scopes[..n-1] ]
672
+ // [drops[n]] -...-> [drops[0]] -> [Free] -> [target ]
655
673
// | |
656
674
// +------------------------------------+
657
- // code for scopes[n]
675
+ // code for scope
658
676
//
659
677
// The code in this function reads from right to left. At each
660
678
// point, we check for cached blocks representing the
661
679
// remainder. If everything is cached, we'll just walk right to
662
680
// left reading the cached results but never created anything.
663
681
664
- // To start, translate scopes[1..].
665
- let ( scope, earlier_scopes) = scopes. split_last_mut ( ) . unwrap ( ) ;
666
- let mut target = if let Some ( cached_block) = scope. cached_block {
667
- cached_block
668
- } else if earlier_scopes. is_empty ( ) {
669
- // Diverging from the root scope creates a RESUME terminator.
670
- // FIXME what span to use here?
671
- let resumeblk = cfg. start_new_cleanup_block ( ) ;
672
- cfg. terminate ( resumeblk, scope. id , fn_span, TerminatorKind :: Resume ) ;
673
- resumeblk
674
- } else {
675
- // Diverging from any other scope chains up to the previous scope.
676
- build_diverge_scope ( tcx, fn_span, cfg, unit_temp, earlier_scopes)
677
- } ;
678
- scope. cached_block = Some ( target) ;
679
-
680
682
// Next, build up any free.
681
683
if let Some ( ref mut free_data) = scope. free {
682
684
target = if let Some ( cached_block) = free_data. cached_block {
0 commit comments