Skip to content

Commit 4a2c1a1

Browse files
fix unwind drop glue for if-then scopes
1 parent 837bf37 commit 4a2c1a1

File tree

6 files changed

+90
-14
lines changed

6 files changed

+90
-14
lines changed

Diff for: compiler/rustc_mir_build/src/build/block.rs

-5
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
245245
OutsideGuard,
246246
true,
247247
);
248-
this.schedule_drop_for_binding(
249-
node,
250-
span,
251-
OutsideGuard,
252-
);
253248
},
254249
);
255250
this.ast_let_else(

Diff for: compiler/rustc_mir_build/src/build/expr/into.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
7474
this.source_info(then_expr.span)
7575
};
7676
let (then_block, else_block) =
77-
this.in_if_then_scope(condition_scope, |this| {
77+
this.in_if_then_scope(condition_scope, then_expr.span, |this| {
7878
let then_blk = unpack!(this.then_else_break(
7979
block,
8080
&this.thir[cond],
@@ -107,7 +107,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
107107
}
108108
ExprKind::Let { expr, ref pat } => {
109109
let scope = this.local_scope();
110-
let (true_block, false_block) = this.in_if_then_scope(scope, |this| {
110+
let (true_block, false_block) = this.in_if_then_scope(scope, expr_span, |this| {
111111
this.lower_let_expr(block, &this.thir[expr], pat, scope, None, expr_span)
112112
});
113113

Diff for: compiler/rustc_mir_build/src/build/matches/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1986,7 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
19861986
let mut guard_span = rustc_span::DUMMY_SP;
19871987

19881988
let (post_guard_block, otherwise_post_guard_block) =
1989-
self.in_if_then_scope(match_scope, |this| match *guard {
1989+
self.in_if_then_scope(match_scope, guard_span, |this| match *guard {
19901990
Guard::If(e) => {
19911991
let e = &this.thir[e];
19921992
guard_span = e.span;
@@ -2301,7 +2301,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
23012301
pattern: &Pat<'tcx>,
23022302
) -> BlockAnd<BasicBlock> {
23032303
let else_block_span = self.thir[else_block].span;
2304-
let (matching, failure) = self.in_if_then_scope(*let_else_scope, |this| {
2304+
let (matching, failure) = self.in_if_then_scope(*let_else_scope, else_block_span, |this| {
23052305
let scrutinee = unpack!(block = this.lower_scrutinee(block, init, initializer_span));
23062306
let pat = Pat { ty: init.ty, span: else_block_span, kind: PatKind::Wild };
23072307
let mut wildcard = Candidate::new(scrutinee.clone(), &pat, false, this);

Diff for: compiler/rustc_mir_build/src/build/scope.rs

+42-5
Original file line numberDiff line numberDiff line change
@@ -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

Diff for: src/test/ui/let-else/issue-102317.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// issue #102317
2+
// run-pass
3+
// compile-flags: --edition 2021 -C opt-level=3 -Zvalidate-mir
4+
5+
struct SegmentJob;
6+
7+
impl Drop for SegmentJob {
8+
fn drop(&mut self) {}
9+
}
10+
11+
pub async fn run() -> Result<(), ()> {
12+
let jobs = Vec::<SegmentJob>::new();
13+
let Some(_job) = jobs.into_iter().next() else {
14+
return Ok(())
15+
};
16+
17+
Ok(())
18+
}
19+
20+
fn main() {}

Diff for: src/test/ui/mir/issue-99852.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// check-pass
2+
// compile-flags: -Z validate-mir
3+
#![feature(let_chains)]
4+
5+
fn lambda<T, U>() -> U
6+
where
7+
T: Default,
8+
U: Default,
9+
{
10+
let foo: Result<T, ()> = Ok(T::default());
11+
let baz: U = U::default();
12+
13+
if let Ok(foo) = foo && let Ok(bar) = transform(foo) {
14+
bar
15+
} else {
16+
baz
17+
}
18+
}
19+
20+
fn transform<T, U>(input: T) -> Result<U, ()> {
21+
todo!()
22+
}
23+
24+
fn main() {}

0 commit comments

Comments
 (0)