@@ -466,9 +466,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
466466 let normal_exit_block = f ( self ) ;
467467 let breakable_scope = self . scopes . breakable_scopes . pop ( ) . unwrap ( ) ;
468468 assert ! ( breakable_scope. region_scope == region_scope) ;
469- let break_block = self . build_exit_tree ( breakable_scope. break_drops , None ) ;
469+ let break_block =
470+ self . build_exit_tree ( breakable_scope. break_drops , region_scope, span, None ) ;
470471 if let Some ( drops) = breakable_scope. continue_drops {
471- self . build_exit_tree ( drops, loop_block) ;
472+ self . build_exit_tree ( drops, region_scope , span , loop_block) ;
472473 }
473474 match ( normal_exit_block, break_block) {
474475 ( Some ( block) , None ) | ( None , Some ( block) ) => block,
@@ -510,6 +511,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
510511 pub ( crate ) fn in_if_then_scope < F > (
511512 & mut self ,
512513 region_scope : region:: Scope ,
514+ span : Span ,
513515 f : F ,
514516 ) -> ( BasicBlock , BasicBlock )
515517 where
@@ -524,7 +526,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
524526 assert ! ( if_then_scope. region_scope == region_scope) ;
525527
526528 let else_block = self
527- . build_exit_tree ( if_then_scope. else_drops , None )
529+ . build_exit_tree ( if_then_scope. else_drops , region_scope , span , None )
528530 . map_or_else ( || self . cfg . start_new_block ( ) , |else_block_and| unpack ! ( else_block_and) ) ;
529531
530532 ( then_block, else_block)
@@ -1021,6 +1023,38 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10211023 cached_drop
10221024 }
10231025
1026+ /// This is similar to [diverge_cleanup_target] except its target is set to
1027+ /// some ancestor scope instead of the current scope.
1028+ /// It is possible to unwind to some ancestor scope if some drop panics as
1029+ /// the program breaks out of a if-then scope.
1030+ fn diverge_cleanup_target ( & mut self , target_scope : region:: Scope , span : Span ) -> DropIdx {
1031+ let target = self . scopes . scope_index ( target_scope, span) ;
1032+ let ( uncached_scope, mut cached_drop) = self . scopes . scopes [ ..=target]
1033+ . iter ( )
1034+ . enumerate ( )
1035+ . rev ( )
1036+ . find_map ( |( scope_idx, scope) | {
1037+ scope. cached_unwind_block . map ( |cached_block| ( scope_idx + 1 , cached_block) )
1038+ } )
1039+ . unwrap_or ( ( 0 , ROOT_NODE ) ) ;
1040+
1041+ if uncached_scope > target {
1042+ return cached_drop;
1043+ }
1044+
1045+ let is_generator = self . generator_kind . is_some ( ) ;
1046+ for scope in & mut self . scopes . scopes [ uncached_scope..=target] {
1047+ for drop in & scope. drops {
1048+ if is_generator || drop. kind == DropKind :: Value {
1049+ cached_drop = self . scopes . unwind_drops . add_drop ( * drop, cached_drop) ;
1050+ }
1051+ }
1052+ scope. cached_unwind_block = Some ( cached_drop) ;
1053+ }
1054+
1055+ cached_drop
1056+ }
1057+
10241058 /// Prepares to create a path that performs all required cleanup for a
10251059 /// terminator that can unwind at the given basic block.
10261060 ///
@@ -1222,21 +1256,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
12221256 fn build_exit_tree (
12231257 & mut self ,
12241258 mut drops : DropTree ,
1259+ else_scope : region:: Scope ,
1260+ span : Span ,
12251261 continue_block : Option < BasicBlock > ,
12261262 ) -> Option < BlockAnd < ( ) > > {
12271263 let mut blocks = IndexVec :: from_elem ( None , & drops. drops ) ;
12281264 blocks[ ROOT_NODE ] = continue_block;
12291265
12301266 drops. build_mir :: < ExitScopes > ( & mut self . cfg , & mut blocks) ;
1267+ let is_generator = self . generator_kind . is_some ( ) ;
12311268
12321269 // Link the exit drop tree to unwind drop tree.
12331270 if drops. drops . iter ( ) . any ( |( drop, _) | drop. kind == DropKind :: Value ) {
1234- let unwind_target = self . diverge_cleanup ( ) ;
1271+ let unwind_target = self . diverge_cleanup_target ( else_scope , span ) ;
12351272 let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, 1 ) ;
12361273 for ( drop_idx, drop_data) in drops. drops . iter_enumerated ( ) . skip ( 1 ) {
12371274 match drop_data. 0 . kind {
12381275 DropKind :: Storage => {
1239- if self . generator_kind . is_some ( ) {
1276+ if is_generator {
12401277 let unwind_drop = self
12411278 . scopes
12421279 . unwind_drops
0 commit comments