@@ -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