@@ -466,9 +466,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
466
466
let normal_exit_block = f ( self ) ;
467
467
let breakable_scope = self . scopes . breakable_scopes . pop ( ) . unwrap ( ) ;
468
468
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 ) ;
470
471
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) ;
472
473
}
473
474
match ( normal_exit_block, break_block) {
474
475
( Some ( block) , None ) | ( None , Some ( block) ) => block,
@@ -510,6 +511,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
510
511
pub ( crate ) fn in_if_then_scope < F > (
511
512
& mut self ,
512
513
region_scope : region:: Scope ,
514
+ span : Span ,
513
515
f : F ,
514
516
) -> ( BasicBlock , BasicBlock )
515
517
where
@@ -524,7 +526,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
524
526
assert ! ( if_then_scope. region_scope == region_scope) ;
525
527
526
528
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 )
528
530
. map_or_else ( || self . cfg . start_new_block ( ) , |else_block_and| unpack ! ( else_block_and) ) ;
529
531
530
532
( then_block, else_block)
@@ -997,10 +999,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
997
999
/// Returns the [DropIdx] for the innermost drop if the function unwound at
998
1000
/// this point. The `DropIdx` will be created if it doesn't already exist.
999
1001
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]
1004
1014
. iter ( )
1005
1015
. enumerate ( )
1006
1016
. rev ( )
@@ -1009,7 +1019,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
1009
1019
} )
1010
1020
. unwrap_or ( ( 0 , ROOT_NODE ) ) ;
1011
1021
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] {
1013
1028
for drop in & scope. drops {
1014
1029
if is_generator || drop. kind == DropKind :: Value {
1015
1030
cached_drop = self . scopes . unwind_drops . add_drop ( * drop, cached_drop) ;
@@ -1222,21 +1237,24 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
1222
1237
fn build_exit_tree (
1223
1238
& mut self ,
1224
1239
mut drops : DropTree ,
1240
+ else_scope : region:: Scope ,
1241
+ span : Span ,
1225
1242
continue_block : Option < BasicBlock > ,
1226
1243
) -> Option < BlockAnd < ( ) > > {
1227
1244
let mut blocks = IndexVec :: from_elem ( None , & drops. drops ) ;
1228
1245
blocks[ ROOT_NODE ] = continue_block;
1229
1246
1230
1247
drops. build_mir :: < ExitScopes > ( & mut self . cfg , & mut blocks) ;
1248
+ let is_generator = self . generator_kind . is_some ( ) ;
1231
1249
1232
1250
// Link the exit drop tree to unwind drop tree.
1233
1251
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 ) ;
1235
1253
let mut unwind_indices = IndexVec :: from_elem_n ( unwind_target, 1 ) ;
1236
1254
for ( drop_idx, drop_data) in drops. drops . iter_enumerated ( ) . skip ( 1 ) {
1237
1255
match drop_data. 0 . kind {
1238
1256
DropKind :: Storage => {
1239
- if self . generator_kind . is_some ( ) {
1257
+ if is_generator {
1240
1258
let unwind_drop = self
1241
1259
. scopes
1242
1260
. unwind_drops
0 commit comments