@@ -323,7 +323,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
323
323
let parent_hir_id =
324
324
tcx. hir . definitions ( ) . node_to_hir_id (
325
325
self . source_scope_local_data [ source_scope] . lint_root
326
- ) ;
326
+ ) ;
327
327
let current_hir_id =
328
328
tcx. hir . definitions ( ) . node_to_hir_id ( node_id) ;
329
329
sets. lint_level_set ( parent_hir_id) ==
@@ -333,7 +333,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
333
333
if !same_lint_scopes {
334
334
self . source_scope =
335
335
self . new_source_scope ( region_scope. 1 . span , lint_level,
336
- None ) ;
336
+ None ) ;
337
337
}
338
338
}
339
339
self . push_scope ( region_scope) ;
@@ -455,35 +455,58 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
455
455
if may_panic {
456
456
self . diverge_cleanup ( ) ;
457
457
}
458
- let mut target_blocks = ( target, self . resume_block ( ) ) ;
459
458
460
- for scope in & mut self . scopes [ ( len - scope_count) ..] {
459
+ let resume_block = self . resume_block ( ) ;
460
+
461
+ // Start from the last cached block
462
+ let ( mut target_blocks, first_uncached) = self . scopes [ ( len - scope_count) ..] . iter ( )
463
+ . enumerate ( )
464
+ . rev ( )
465
+ . find_map ( |( idx, scope) | {
466
+ scope. cached_exits . get ( & ( target, region_scope. 0 ) ) . map ( |cached_target| {
467
+ (
468
+ (
469
+ * cached_target,
470
+ scope. cached_unwind . get ( true ) . unwrap_or_else ( || {
471
+ debug_assert ! ( !may_panic, "cached block not present?" ) ;
472
+ resume_block
473
+ } ) ,
474
+ ) ,
475
+ idx + 1 ,
476
+ )
477
+ } )
478
+ } )
479
+ . unwrap_or_else ( || {
480
+ let unwind_block = self . scopes [ len - scope_count - 1 ] . cached_unwind
481
+ . get ( true )
482
+ . unwrap_or_else ( || {
483
+ debug_assert ! ( !may_panic, "cached block not present?" ) ;
484
+ resume_block
485
+ } ) ;
486
+ ( ( target, unwind_block) , 0 )
487
+ } ) ;
488
+
489
+ for scope in & mut self . scopes [ ( len - scope_count + first_uncached) ..] {
461
490
if scope. drops . is_empty ( ) {
462
491
continue ;
463
492
}
464
- if let Some ( & cached) = scope. cached_exits . get ( & ( target, region_scope. 0 ) ) {
465
- target_blocks = ( cached, scope. cached_unwind . get ( false ) . unwrap_or_else ( || {
466
- debug_assert ! ( !may_panic, "cached block not present?" ) ;
467
- target_blocks. 1
468
- } ) ) ;
469
- } else {
470
- let current_target = self . cfg . start_new_block ( ) ;
471
- self . cfg . terminate (
472
- current_target,
473
- scope. source_info ( span) ,
474
- TerminatorKind :: Goto { target : target_blocks. 0 } ,
475
- ) ;
476
- target_blocks = build_scope_drops (
477
- & mut self . cfg ,
478
- current_target,
479
- target_blocks. 1 ,
480
- & scope. drops ,
481
- scope,
482
- self . arg_count ,
483
- false ,
484
- ) ;
485
- scope. cached_exits . insert ( ( target, region_scope. 0 ) , target_blocks. 0 ) ;
486
- } ;
493
+
494
+ let current_target = self . cfg . start_new_block ( ) ;
495
+ self . cfg . terminate (
496
+ current_target,
497
+ scope. source_info ( span) ,
498
+ TerminatorKind :: Goto { target : target_blocks. 0 } ,
499
+ ) ;
500
+ target_blocks = build_scope_drops (
501
+ & mut self . cfg ,
502
+ current_target,
503
+ target_blocks. 1 ,
504
+ & scope. drops ,
505
+ scope,
506
+ self . arg_count ,
507
+ false ,
508
+ ) ;
509
+ scope. cached_exits . insert ( ( target, region_scope. 0 ) , target_blocks. 0 ) ;
487
510
}
488
511
self . cfg . terminate (
489
512
block,
@@ -497,56 +520,66 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
497
520
/// This path terminates in GeneratorDrop. Returns the start of the path.
498
521
/// None indicates there’s no cleanup to do at this point.
499
522
pub fn generator_drop_cleanup ( & mut self ) -> Option < BasicBlock > {
500
- // Fill in the cache
523
+ // Fill in the cache for unwinds
501
524
self . diverge_cleanup_gen ( true ) ;
502
525
503
526
let src_info = self . scopes [ 0 ] . source_info ( self . fn_span ) ;
504
- let mut target_blocks = None ;
505
- let resume_block = self . resume_block ( ) ;
506
527
507
- for scope in & mut self . scopes {
528
+ // Start from the last cached block
529
+ let ( mut target_blocks, first_uncached) = self . scopes . iter ( )
530
+ . enumerate ( )
531
+ . rev ( )
532
+ . find_map ( |( idx, scope) | {
533
+ scope. cached_generator_drop . map ( |cached_target| {
534
+ (
535
+ (
536
+ cached_target,
537
+ scope. cached_unwind . get ( true ) . unwrap_or_else ( || {
538
+ span_bug ! ( src_info. span, "cached block not present?" )
539
+ } ) ,
540
+ ) ,
541
+ idx + 1 ,
542
+ )
543
+ } )
544
+ } )
545
+ . unwrap_or_else ( || {
546
+ let generator_drop_block = self . cfg . start_new_block ( ) ;
547
+ self . cfg . terminate ( generator_drop_block, src_info, TerminatorKind :: GeneratorDrop ) ;
548
+ ( ( generator_drop_block, self . resume_block ( ) ) , 0 )
549
+ } ) ;
550
+
551
+ for scope in & mut self . scopes [ first_uncached..] {
508
552
if !scope. needs_cleanup {
509
553
continue ;
510
554
}
511
- if let Some ( cached) = scope. cached_generator_drop {
512
- target_blocks = Some ( ( cached, scope. cached_unwind . get ( true ) . unwrap_or_else ( || {
513
- span_bug ! ( src_info. span, "cached block not present?" )
514
- } ) ) ) ;
515
- } else {
516
- let current_target = self . cfg . start_new_block ( ) ;
517
- let unwind_target = if let Some ( ( target, unwind_target) ) = target_blocks {
518
- self . cfg . terminate (
519
- current_target,
520
- src_info,
521
- TerminatorKind :: Goto { target } ,
522
- ) ;
523
- unwind_target
524
- } else {
525
- self . cfg . terminate ( current_target, src_info, TerminatorKind :: GeneratorDrop ) ;
526
- resume_block
527
- } ;
528
- let next_target_blocks = build_scope_drops (
529
- & mut self . cfg ,
530
- current_target,
531
- unwind_target,
532
- & scope. drops ,
533
- scope,
534
- self . arg_count ,
535
- true ,
536
- ) ;
537
- scope. cached_generator_drop = Some ( next_target_blocks. 0 ) ;
538
- target_blocks = Some ( next_target_blocks) ;
539
- } ;
555
+
556
+ let current_target = self . cfg . start_new_block ( ) ;
557
+ self . cfg . terminate (
558
+ current_target,
559
+ src_info,
560
+ TerminatorKind :: Goto { target : target_blocks. 0 } ,
561
+ ) ;
562
+
563
+ target_blocks = build_scope_drops (
564
+ & mut self . cfg ,
565
+ current_target,
566
+ target_blocks. 1 ,
567
+ & scope. drops ,
568
+ scope,
569
+ self . arg_count ,
570
+ true ,
571
+ ) ;
572
+ scope. cached_generator_drop = Some ( target_blocks. 0 ) ;
540
573
}
541
574
542
- target_blocks. map ( | ( target , _ ) | target )
575
+ Some ( target_blocks. 0 )
543
576
}
544
577
545
578
/// Creates a new source scope, nested in the current one.
546
579
pub fn new_source_scope ( & mut self ,
547
- span : Span ,
548
- lint_level : LintLevel ,
549
- safety : Option < Safety > ) -> SourceScope {
580
+ span : Span ,
581
+ lint_level : LintLevel ,
582
+ safety : Option < Safety > ) -> SourceScope {
550
583
let parent = self . source_scope ;
551
584
debug ! ( "new_source_scope({:?}, {:?}, {:?}) - parent({:?})={:?}" ,
552
585
span, lint_level, safety,
@@ -805,11 +838,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
805
838
}
806
839
807
840
fn diverge_cleanup_gen ( & mut self , generator_drop : bool ) -> BasicBlock {
808
- // To start, create the resume terminator.
809
- let mut target = self . resume_block ( ) ;
810
-
811
- let Builder { ref mut cfg, ref mut scopes, .. } = * self ;
812
-
813
841
// Build up the drops in **reverse** order. The end result will
814
842
// look like:
815
843
//
@@ -821,8 +849,16 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
821
849
// store caches. If everything is cached, we'll just walk right
822
850
// to left reading the cached results but never created anything.
823
851
824
- for scope in scopes. iter_mut ( ) {
825
- target = build_diverge_scope ( cfg, scope. region_scope_span ,
852
+ // Find the last cached block
853
+ let ( mut target, first_uncached) = if let Some ( cached_index) = self . scopes . iter ( )
854
+ . rposition ( |scope| scope. cached_unwind . get ( generator_drop) . is_some ( ) ) {
855
+ ( self . scopes [ cached_index] . cached_unwind . get ( generator_drop) . unwrap ( ) , cached_index + 1 )
856
+ } else {
857
+ ( self . resume_block ( ) , 0 )
858
+ } ;
859
+
860
+ for scope in self . scopes [ first_uncached..] . iter_mut ( ) {
861
+ target = build_diverge_scope ( & mut self . cfg , scope. region_scope_span ,
826
862
scope, target, generator_drop) ;
827
863
}
828
864
@@ -999,11 +1035,11 @@ fn push_storage_deads<'tcx>(
999
1035
}
1000
1036
1001
1037
fn build_diverge_scope < ' tcx > ( cfg : & mut CFG < ' tcx > ,
1002
- span : Span ,
1003
- scope : & mut Scope < ' tcx > ,
1004
- mut target : BasicBlock ,
1005
- generator_drop : bool )
1006
- -> BasicBlock
1038
+ span : Span ,
1039
+ scope : & mut Scope < ' tcx > ,
1040
+ mut target : BasicBlock ,
1041
+ generator_drop : bool )
1042
+ -> BasicBlock
1007
1043
{
1008
1044
// Build up the drops in **reverse** order. The end result will
1009
1045
// look like:
@@ -1015,11 +1051,6 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
1015
1051
// remainder. If everything is cached, we'll just walk right to
1016
1052
// left reading the cached results but never create anything.
1017
1053
1018
- let scope_cached_block = scope. cached_unwind . ref_mut ( generator_drop) ;
1019
- if let Some ( scope_cached_block) = * scope_cached_block {
1020
- return scope_cached_block;
1021
- }
1022
-
1023
1054
let source_scope = scope. source_scope ;
1024
1055
let source_info = |span| SourceInfo {
1025
1056
span,
@@ -1058,7 +1089,7 @@ fn build_diverge_scope<'tcx>(cfg: &mut CFG<'tcx>,
1058
1089
} ;
1059
1090
}
1060
1091
1061
- * scope_cached_block = Some ( target) ;
1092
+ * scope . cached_unwind . ref_mut ( generator_drop ) = Some ( target) ;
1062
1093
1063
1094
debug ! ( "build_diverge_scope({:?}, {:?}) = {:?}" , scope, span, target) ;
1064
1095
0 commit comments