@@ -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)
@@ -997,10 +999,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
997999 /// Returns the [DropIdx] for the innermost drop if the function unwound at
9981000 /// this point. The `DropIdx` will be created if it doesn't already exist.
9991001 fn diverge_cleanup ( & mut self ) -> DropIdx {
1000- let is_generator = self . generator_kind . is_some ( ) ;
1001- let ( uncached_scope, mut cached_drop) = self
1002- . scopes
1003- . scopes
1002+ // It is okay to use dummy span because the getting scope index on the topmost scope
1003+ // must always succeed.
1004+ self . diverge_cleanup_target ( self . scopes . topmost ( ) , DUMMY_SP )
1005+ }
1006+
1007+ /// This is similar to [diverge_cleanup](Self::diverge_cleanup) except its target is set to
1008+ /// some ancestor scope instead of the current scope.
1009+ /// It is possible to unwind to some ancestor scope if some drop panics as
1010+ /// the program breaks out of a if-then scope.
1011+ fn diverge_cleanup_target ( & mut self , target_scope : region:: Scope , span : Span ) -> DropIdx {
1012+ let target = self . scopes . scope_index ( target_scope, span) ;
1013+ let ( uncached_scope, mut cached_drop) = self . scopes . scopes [ ..=target]
10041014 . iter ( )
10051015 . enumerate ( )
10061016 . rev ( )
@@ -1009,7 +1019,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
10091019 } )
10101020 . unwrap_or ( ( 0 , ROOT_NODE ) ) ;
10111021
1012- for scope in & mut self . scopes . scopes [ uncached_scope..] {
1022+ if uncached_scope > target {
1023+ return cached_drop;
1024+ }
1025+
1026+ let is_generator = self . generator_kind . is_some ( ) ;
1027+ for scope in & mut self . scopes . scopes [ uncached_scope..=target] {
10131028 for drop in & scope. drops {
10141029 if is_generator || drop. kind == DropKind :: Value {
10151030 cached_drop = self . scopes . unwind_drops . add_drop ( * drop, cached_drop) ;
@@ -1222,21 +1237,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
12221237 fn build_exit_tree (
12231238 & mut self ,
12241239 mut drops : DropTree ,
1240+ else_scope : region:: Scope ,
1241+ span : Span ,
12251242 continue_block : Option < BasicBlock > ,
12261243 ) -> Option < BlockAnd < ( ) > > {
12271244 let mut blocks = IndexVec :: from_elem ( None , & drops. drops ) ;
12281245 blocks[ ROOT_NODE ] = continue_block;
12291246
12301247 drops. build_mir :: < ExitScopes > ( & mut self . cfg , & mut blocks) ;
1248+ let is_generator = self . generator_kind . is_some ( ) ;
12311249
12321250 // Link the exit drop tree to unwind drop tree.
12331251 if drops. drops . iter ( ) . any ( |( drop, _) | drop. kind == DropKind :: Value ) {
1234- let unwind_target = self . diverge_cleanup ( ) ;
1252+ let unwind_target = self . diverge_cleanup_target ( else_scope , span ) ;
12351253 let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, 1 ) ;
12361254 for ( drop_idx, drop_data) in drops. drops . iter_enumerated ( ) . skip ( 1 ) {
12371255 match drop_data. 0 . kind {
12381256 DropKind :: Storage => {
1239- if self . generator_kind . is_some ( ) {
1257+ if is_generator {
12401258 let unwind_drop = self
12411259 . scopes
12421260 . unwind_drops
0 commit comments