Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

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)