Skip to content

Commit 7fcb61c

Browse files
committed
Closures can be called again even after an unwind.
1 parent a24b76a commit 7fcb61c

File tree

2 files changed

+22
-4
lines changed

2 files changed

+22
-4
lines changed

compiler/rustc_mir_transform/src/liveness.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,14 @@ pub(crate) fn check_liveness<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Den
107107
// `FnMut` closures can modify captured values and carry those
108108
// modified values with them in subsequent calls. To model this behaviour,
109109
// we consider the `FnMut` closure as jumping to `bb0` upon return.
110-
if let CaptureKind::Closure(ty::ClosureKind::FnMut) = capture_kind
111-
&& checked_places.captures.iter().any(|(_, by_ref)| !by_ref)
112-
{
110+
if let CaptureKind::Closure(ty::ClosureKind::FnMut) = capture_kind {
113111
// FIXME: stop cloning the body.
114112
body_mem = body.clone();
115113
for bbdata in body_mem.basic_blocks_mut() {
116-
if let TerminatorKind::Return = bbdata.terminator().kind {
114+
// We can call a closure again, either after a normal return or an unwind.
115+
if let TerminatorKind::Return | TerminatorKind::UnwindResume =
116+
bbdata.terminator().kind
117+
{
117118
bbdata.terminator_mut().kind = TerminatorKind::Goto { target: START_BLOCK };
118119
}
119120
}

tests/ui/liveness/liveness-upvars.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,21 @@ pub fn coroutine() {
147147
};
148148
}
149149

150+
pub fn panics() {
151+
use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind};
152+
153+
let mut panic = true;
154+
155+
// `a` can be called again, even if it has panicked at an earlier run.
156+
let mut a = || {
157+
if panic {
158+
panic = false;
159+
resume_unwind(Box::new(()))
160+
}
161+
};
162+
163+
catch_unwind(AssertUnwindSafe(|| a())).ok();
164+
a();
165+
}
166+
150167
fn main() {}

0 commit comments

Comments
 (0)