Skip to content

Commit 20958fc

Browse files
committed
Auto merge of #58902 - matthewjasper:generator-cleanup-blocks, r=davidtwco
Fixes for the generator transform * Moves cleanup annotations in pretty printed MIR so that they can be tested * Correctly determines which drops are in cleanup blocks when elaborating generator drops * Use the correct state for poisoning a generator Closes #58892
2 parents 33b3b13 + 5e68c57 commit 20958fc

13 files changed

+129
-60
lines changed

src/librustc_mir/transform/generator.rs

+42-37
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
//! }
2727
//!
2828
//! This pass computes the meaning of the state field and the MIR locals which are live
29-
//! across a suspension point. There are however two hardcoded generator states:
29+
//! across a suspension point. There are however three hardcoded generator states:
3030
//! 0 - Generator have not been resumed yet
3131
//! 1 - Generator has returned / is completed
3232
//! 2 - Generator has been poisoned
@@ -144,6 +144,13 @@ fn self_arg() -> Local {
144144
Local::new(1)
145145
}
146146

147+
/// Generator have not been resumed yet
148+
const UNRESUMED: u32 = 0;
149+
/// Generator has returned / is completed
150+
const RETURNED: u32 = 1;
151+
/// Generator has been poisoned
152+
const POISONED: u32 = 2;
153+
147154
struct SuspensionPoint {
148155
state: u32,
149156
resume: BasicBlock,
@@ -278,7 +285,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
278285

279286
state
280287
} else { // Return
281-
1 // state for returned
288+
RETURNED // state for returned
282289
};
283290
data.statements.push(self.set_state(state, source_info));
284291
data.terminator.as_mut().unwrap().kind = TerminatorKind::Return;
@@ -590,8 +597,15 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
590597
let param_env = tcx.param_env(def_id);
591598
let gen = self_arg();
592599

593-
for block in mir.basic_blocks().indices() {
594-
let (target, unwind, source_info) = match mir.basic_blocks()[block].terminator() {
600+
let mut elaborator = DropShimElaborator {
601+
mir: mir,
602+
patch: MirPatch::new(mir),
603+
tcx,
604+
param_env
605+
};
606+
607+
for (block, block_data) in mir.basic_blocks().iter_enumerated() {
608+
let (target, unwind, source_info) = match block_data.terminator() {
595609
&Terminator {
596610
source_info,
597611
kind: TerminatorKind::Drop {
@@ -602,31 +616,22 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
602616
} if local == gen => (target, unwind, source_info),
603617
_ => continue,
604618
};
605-
let unwind = if let Some(unwind) = unwind {
606-
Unwind::To(unwind)
607-
} else {
619+
let unwind = if block_data.is_cleanup {
608620
Unwind::InCleanup
621+
} else {
622+
Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block()))
609623
};
610-
let patch = {
611-
let mut elaborator = DropShimElaborator {
612-
mir: &mir,
613-
patch: MirPatch::new(mir),
614-
tcx,
615-
param_env
616-
};
617-
elaborate_drop(
618-
&mut elaborator,
619-
source_info,
620-
&Place::Base(PlaceBase::Local(gen)),
621-
(),
622-
target,
623-
unwind,
624-
block
625-
);
626-
elaborator.patch
627-
};
628-
patch.apply(mir);
624+
elaborate_drop(
625+
&mut elaborator,
626+
source_info,
627+
&Place::Base(PlaceBase::Local(gen)),
628+
(),
629+
target,
630+
unwind,
631+
block,
632+
);
629633
}
634+
elaborator.patch.apply(mir);
630635
}
631636

632637
fn create_generator_drop_shim<'a, 'tcx>(
@@ -643,10 +648,10 @@ fn create_generator_drop_shim<'a, 'tcx>(
643648

644649
let mut cases = create_cases(&mut mir, transform, |point| point.drop);
645650

646-
cases.insert(0, (0, drop_clean));
651+
cases.insert(0, (UNRESUMED, drop_clean));
647652

648-
// The returned state (1) and the poisoned state (2) falls through to
649-
// the default case which is just to return
653+
// The returned state and the poisoned state fall through to the default
654+
// case which is just to return
650655

651656
insert_switch(tcx, &mut mir, cases, &transform, TerminatorKind::Return);
652657

@@ -762,7 +767,7 @@ fn create_generator_resume_function<'a, 'tcx>(
762767
for block in mir.basic_blocks_mut() {
763768
let source_info = block.terminator().source_info;
764769
if let &TerminatorKind::Resume = &block.terminator().kind {
765-
block.statements.push(transform.set_state(1, source_info));
770+
block.statements.push(transform.set_state(POISONED, source_info));
766771
}
767772
}
768773

@@ -773,12 +778,12 @@ fn create_generator_resume_function<'a, 'tcx>(
773778
GeneratorResumedAfterReturn,
774779
};
775780

776-
// Jump to the entry point on the 0 state
777-
cases.insert(0, (0, BasicBlock::new(0)));
778-
// Panic when resumed on the returned (1) state
779-
cases.insert(1, (1, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn)));
780-
// Panic when resumed on the poisoned (2) state
781-
cases.insert(2, (2, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic)));
781+
// Jump to the entry point on the unresumed
782+
cases.insert(0, (UNRESUMED, BasicBlock::new(0)));
783+
// Panic when resumed on the returned state
784+
cases.insert(1, (RETURNED, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn)));
785+
// Panic when resumed on the poisoned state
786+
cases.insert(2, (POISONED, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic)));
782787

783788
insert_switch(tcx, mir, cases, &transform, TerminatorKind::Unreachable);
784789

@@ -942,7 +947,7 @@ impl MirPass for StateTransform {
942947
mir.generator_layout = Some(layout);
943948

944949
// Insert `drop(generator_struct)` which is used to drop upvars for generators in
945-
// the unresumed (0) state.
950+
// the unresumed state.
946951
// This is expanded to a drop ladder in `elaborate_generator_drops`.
947952
let drop_clean = insert_clean_drop(mir);
948953

src/librustc_mir/util/pretty.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,8 @@ where
317317
let data = &mir[block];
318318

319319
// Basic block label at the top.
320-
let cleanup_text = if data.is_cleanup { " // cleanup" } else { "" };
321-
let lbl = format!("{}{:?}: {{", INDENT, block);
322-
writeln!(w, "{0:1$}{2}", lbl, ALIGN, cleanup_text)?;
320+
let cleanup_text = if data.is_cleanup { " (cleanup)" } else { "" };
321+
writeln!(w, "{}{:?}{}: {{", INDENT, block, cleanup_text)?;
323322

324323
// List of statements in the middle.
325324
let mut current_location = Location {

src/test/mir-opt/basic_assignment.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ fn main() {
4848
// drop(_6) -> [return: bb6, unwind: bb4];
4949
// }
5050
// ...
51-
// bb5: {
51+
// bb5 (cleanup): {
5252
// drop(_6) -> bb4;
5353
// }
5454
// END rustc.main.SimplifyCfg-initial.after.mir

src/test/mir-opt/box_expr.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl Drop for S {
3838
// (*_2) = const S::new() -> [return: bb2, unwind: bb3];
3939
// }
4040
//
41-
// bb1: {
41+
// bb1 (cleanup): {
4242
// resume;
4343
// }
4444
//
@@ -47,7 +47,7 @@ impl Drop for S {
4747
// drop(_2) -> bb4;
4848
// }
4949
//
50-
// bb3: {
50+
// bb3 (cleanup): {
5151
// drop(_2) -> bb1;
5252
// }
5353
//
@@ -62,11 +62,11 @@ impl Drop for S {
6262
// drop(_4) -> [return: bb8, unwind: bb6];
6363
// }
6464
//
65-
// bb6: {
65+
// bb6 (cleanup): {
6666
// drop(_1) -> bb1;
6767
// }
6868
//
69-
// bb7: {
69+
// bb7 (cleanup): {
7070
// drop(_4) -> bb6;
7171
// }
7272
//
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#![feature(generators, generator_trait)]
2+
3+
// Regression test for #58892, generator drop shims should not have blocks
4+
// spuriously marked as cleanup
5+
6+
fn main() {
7+
let gen = || {
8+
yield;
9+
};
10+
}
11+
12+
// END RUST SOURCE
13+
14+
// START rustc.main-{{closure}}.generator_drop.0.mir
15+
// bb0: {
16+
// switchInt(((*_1).0: u32)) -> [0u32: bb4, 3u32: bb7, otherwise: bb8];
17+
// }
18+
// bb1: {
19+
// goto -> bb5;
20+
// }
21+
// bb2: {
22+
// return;
23+
// }
24+
// bb3: {
25+
// return;
26+
// }
27+
// bb4: {
28+
// goto -> bb6;
29+
// }
30+
// bb5: {
31+
// goto -> bb2;
32+
// }
33+
// bb6: {
34+
// goto -> bb3;
35+
// }
36+
// bb7: {
37+
// StorageLive(_3);
38+
// goto -> bb1;
39+
// }
40+
// bb8: {
41+
// return;
42+
// }
43+
// END rustc.main-{{closure}}.generator_drop.0.mir

src/test/mir-opt/issue-38669.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn main() {
1818
// FakeRead(ForLet, _1);
1919
// goto -> bb2;
2020
// }
21-
// bb1: {
21+
// bb1 (cleanup): {
2222
// resume;
2323
// }
2424
// bb2: {

src/test/mir-opt/issue-49232.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn main() {
4343
// FakeRead(ForMatchedPlace, _3);
4444
// switchInt(_3) -> [false: bb9, otherwise: bb8];
4545
// }
46-
// bb4: {
46+
// bb4 (cleanup): {
4747
// resume;
4848
// }
4949
// bb5: {

src/test/mir-opt/loop_test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ fn main() {
1818
// END RUST SOURCE
1919
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
2020
// ...
21-
// bb1: { // The cleanup block
21+
// bb1 (cleanup): {
2222
// resume;
2323
// }
2424
// ...

src/test/mir-opt/match_false_edges.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn main() {
4747
// _3 = discriminant(_2);
4848
// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb7];
4949
// }
50-
// bb1: {
50+
// bb1 (cleanup): {
5151
// resume;
5252
// }
5353
// bb2: {
@@ -116,7 +116,7 @@ fn main() {
116116
// _3 = discriminant(_2);
117117
// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb7];
118118
// }
119-
// bb1: {
119+
// bb1 (cleanup): {
120120
// resume;
121121
// }
122122
// bb2: {
@@ -185,7 +185,7 @@ fn main() {
185185
// _3 = discriminant(_2);
186186
// switchInt(move _3) -> [1isize: bb2, otherwise: bb3];
187187
// }
188-
// bb1: {
188+
// bb1 (cleanup): {
189189
// resume;
190190
// }
191191
// bb2: {

src/test/mir-opt/packed-struct-drop-aligned.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,14 @@ impl Drop for Droppy {
3838
// _6 = move (_1.0: Aligned);
3939
// drop(_6) -> [return: bb4, unwind: bb3];
4040
// }
41-
// bb1: {
41+
// bb1 (cleanup): {
4242
// resume;
4343
// }
4444
// bb2: {
4545
// StorageDead(_1);
4646
// return;
4747
// }
48-
// bb3: {
48+
// bb3 (cleanup): {
4949
// (_1.0: Aligned) = move _4;
5050
// drop(_1) -> bb1;
5151
// }

src/test/mir-opt/remove_fake_borrows.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn main() {
6363
// StorageDead(_8);
6464
// return;
6565
// }
66-
// bb10: {
66+
// bb10 (cleanup): {
6767
// resume;
6868
// }
6969
// END rustc.match_guard.CleanupNonCodegenStatements.before.mir
@@ -114,7 +114,7 @@ fn main() {
114114
// StorageDead(_8);
115115
// return;
116116
// }
117-
// bb10: {
117+
// bb10 (cleanup): {
118118
// resume;
119119
// }
120120
// END rustc.match_guard.CleanupNonCodegenStatements.after.mir

src/test/mir-opt/unusual-item-types.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn main() {
2929
// _0 = const 2i32;
3030
// return;
3131
// }
32-
// bb1: {
32+
// bb1 (cleanup): {
3333
// resume;
3434
// }
3535
// END rustc.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir
@@ -39,7 +39,7 @@ fn main() {
3939
// _0 = const 5isize;
4040
// return;
4141
// }
42-
// bb1: {
42+
// bb1 (cleanup): {
4343
// resume;
4444
// }
4545
// END rustc.E-V-{{constant}}.mir_map.0.mir
@@ -51,16 +51,16 @@ fn main() {
5151
// bb1: {
5252
// return;
5353
// }
54-
// bb2: {
54+
// bb2 (cleanup): {
5555
// resume;
5656
// }
5757
// bb3: {
5858
// goto -> bb1;
5959
// }
60-
// bb4: {
60+
// bb4 (cleanup): {
6161
// goto -> bb2;
6262
// }
63-
// bb5: {
63+
// bb5 (cleanup): {
6464
// drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb4;
6565
// }
6666
// bb6: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// error-pattern:generator resumed after panicking
2+
3+
// Test that we get the correct message for resuming a panicked generator.
4+
5+
#![feature(generators, generator_trait)]
6+
7+
use std::{
8+
ops::Generator,
9+
pin::Pin,
10+
panic,
11+
};
12+
13+
fn main() {
14+
let mut g = || {
15+
panic!();
16+
yield;
17+
};
18+
panic::catch_unwind(panic::AssertUnwindSafe(|| {
19+
let x = Pin::new(&mut g).resume();
20+
}));
21+
Pin::new(&mut g).resume();
22+
}

0 commit comments

Comments
 (0)