Skip to content

Commit 46aeef6

Browse files
Poison generators when any terminator unwinds
This didn't cause issues before since generator types were always considered to "need drop", leading to unwind paths (including a `Resume` block) always getting generated.
1 parent 5ac41a1 commit 46aeef6

File tree

1 file changed

+31
-5
lines changed

1 file changed

+31
-5
lines changed

src/librustc_mir/transform/generator.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,11 +1055,37 @@ fn create_generator_resume_function<'tcx>(
10551055
body: &mut BodyAndCache<'tcx>,
10561056
can_return: bool,
10571057
) {
1058+
let can_unwind = can_unwind(tcx, body);
1059+
10581060
// Poison the generator when it unwinds
1059-
for block in body.basic_blocks_mut() {
1060-
let source_info = block.terminator().source_info;
1061-
if let &TerminatorKind::Resume = &block.terminator().kind {
1062-
block.statements.push(transform.set_discr(VariantIdx::new(POISONED), source_info));
1061+
if can_unwind {
1062+
let poison_block = BasicBlock::new(body.basic_blocks().len());
1063+
let source_info = source_info(body);
1064+
body.basic_blocks_mut().push(BasicBlockData {
1065+
statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)],
1066+
terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }),
1067+
is_cleanup: true,
1068+
});
1069+
1070+
for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() {
1071+
let source_info = block.terminator().source_info;
1072+
1073+
if let TerminatorKind::Resume = block.terminator().kind {
1074+
// An existing `Resume` terminator is redirected to jump to our dedicated
1075+
// "poisoning block" above.
1076+
if idx != poison_block {
1077+
*block.terminator_mut() = Terminator {
1078+
source_info,
1079+
kind: TerminatorKind::Goto { target: poison_block },
1080+
};
1081+
}
1082+
} else if !block.is_cleanup {
1083+
// Any terminators that *can* unwind but don't have an unwind target set are also
1084+
// pointed at our poisoning block (unless they're part of the cleanup path).
1085+
if let Some(unwind @ None) = block.terminator_mut().unwind_mut() {
1086+
*unwind = Some(poison_block);
1087+
}
1088+
}
10631089
}
10641090
}
10651091

@@ -1080,7 +1106,7 @@ fn create_generator_resume_function<'tcx>(
10801106
);
10811107
}
10821108

1083-
if can_unwind(tcx, body) {
1109+
if can_unwind {
10841110
cases.insert(
10851111
2,
10861112
(POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))),

0 commit comments

Comments
 (0)