Skip to content

Commit

Permalink
Rollup merge of rust-lang#58902 - matthewjasper:generator-cleanup-blo…
Browse files Browse the repository at this point in the history
…cks, 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 rust-lang#58892
  • Loading branch information
Centril committed Mar 19, 2019
2 parents 3eb4890 + 5e68c57 commit fdb2ecd
Show file tree
Hide file tree
Showing 13 changed files with 129 additions and 60 deletions.
79 changes: 42 additions & 37 deletions src/librustc_mir/transform/generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
//! }
//!
//! This pass computes the meaning of the state field and the MIR locals which are live
//! across a suspension point. There are however two hardcoded generator states:
//! across a suspension point. There are however three hardcoded generator states:
//! 0 - Generator have not been resumed yet
//! 1 - Generator has returned / is completed
//! 2 - Generator has been poisoned
Expand Down Expand Up @@ -144,6 +144,13 @@ fn self_arg() -> Local {
Local::new(1)
}

/// Generator have not been resumed yet
const UNRESUMED: u32 = 0;
/// Generator has returned / is completed
const RETURNED: u32 = 1;
/// Generator has been poisoned
const POISONED: u32 = 2;

struct SuspensionPoint {
state: u32,
resume: BasicBlock,
Expand Down Expand Up @@ -278,7 +285,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {

state
} else { // Return
1 // state for returned
RETURNED // state for returned
};
data.statements.push(self.set_state(state, source_info));
data.terminator.as_mut().unwrap().kind = TerminatorKind::Return;
Expand Down Expand Up @@ -590,8 +597,15 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
let param_env = tcx.param_env(def_id);
let gen = self_arg();

for block in mir.basic_blocks().indices() {
let (target, unwind, source_info) = match mir.basic_blocks()[block].terminator() {
let mut elaborator = DropShimElaborator {
mir: mir,
patch: MirPatch::new(mir),
tcx,
param_env
};

for (block, block_data) in mir.basic_blocks().iter_enumerated() {
let (target, unwind, source_info) = match block_data.terminator() {
&Terminator {
source_info,
kind: TerminatorKind::Drop {
Expand All @@ -602,31 +616,22 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
} if local == gen => (target, unwind, source_info),
_ => continue,
};
let unwind = if let Some(unwind) = unwind {
Unwind::To(unwind)
} else {
let unwind = if block_data.is_cleanup {
Unwind::InCleanup
} else {
Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block()))
};
let patch = {
let mut elaborator = DropShimElaborator {
mir: &mir,
patch: MirPatch::new(mir),
tcx,
param_env
};
elaborate_drop(
&mut elaborator,
source_info,
&Place::Base(PlaceBase::Local(gen)),
(),
target,
unwind,
block
);
elaborator.patch
};
patch.apply(mir);
elaborate_drop(
&mut elaborator,
source_info,
&Place::Base(PlaceBase::Local(gen)),
(),
target,
unwind,
block,
);
}
elaborator.patch.apply(mir);
}

fn create_generator_drop_shim<'a, 'tcx>(
Expand All @@ -643,10 +648,10 @@ fn create_generator_drop_shim<'a, 'tcx>(

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

cases.insert(0, (0, drop_clean));
cases.insert(0, (UNRESUMED, drop_clean));

// The returned state (1) and the poisoned state (2) falls through to
// the default case which is just to return
// The returned state and the poisoned state fall through to the default
// case which is just to return

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

Expand Down Expand Up @@ -762,7 +767,7 @@ fn create_generator_resume_function<'a, 'tcx>(
for block in mir.basic_blocks_mut() {
let source_info = block.terminator().source_info;
if let &TerminatorKind::Resume = &block.terminator().kind {
block.statements.push(transform.set_state(1, source_info));
block.statements.push(transform.set_state(POISONED, source_info));
}
}

Expand All @@ -773,12 +778,12 @@ fn create_generator_resume_function<'a, 'tcx>(
GeneratorResumedAfterReturn,
};

// Jump to the entry point on the 0 state
cases.insert(0, (0, BasicBlock::new(0)));
// Panic when resumed on the returned (1) state
cases.insert(1, (1, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn)));
// Panic when resumed on the poisoned (2) state
cases.insert(2, (2, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic)));
// Jump to the entry point on the unresumed
cases.insert(0, (UNRESUMED, BasicBlock::new(0)));
// Panic when resumed on the returned state
cases.insert(1, (RETURNED, insert_panic_block(tcx, mir, GeneratorResumedAfterReturn)));
// Panic when resumed on the poisoned state
cases.insert(2, (POISONED, insert_panic_block(tcx, mir, GeneratorResumedAfterPanic)));

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

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

// Insert `drop(generator_struct)` which is used to drop upvars for generators in
// the unresumed (0) state.
// the unresumed state.
// This is expanded to a drop ladder in `elaborate_generator_drops`.
let drop_clean = insert_clean_drop(mir);

Expand Down
5 changes: 2 additions & 3 deletions src/librustc_mir/util/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,8 @@ where
let data = &mir[block];

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

// List of statements in the middle.
let mut current_location = Location {
Expand Down
2 changes: 1 addition & 1 deletion src/test/mir-opt/basic_assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn main() {
// drop(_6) -> [return: bb6, unwind: bb4];
// }
// ...
// bb5: {
// bb5 (cleanup): {
// drop(_6) -> bb4;
// }
// END rustc.main.SimplifyCfg-initial.after.mir
8 changes: 4 additions & 4 deletions src/test/mir-opt/box_expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl Drop for S {
// (*_2) = const S::new() -> [return: bb2, unwind: bb3];
// }
//
// bb1: {
// bb1 (cleanup): {
// resume;
// }
//
Expand All @@ -47,7 +47,7 @@ impl Drop for S {
// drop(_2) -> bb4;
// }
//
// bb3: {
// bb3 (cleanup): {
// drop(_2) -> bb1;
// }
//
Expand All @@ -62,11 +62,11 @@ impl Drop for S {
// drop(_4) -> [return: bb8, unwind: bb6];
// }
//
// bb6: {
// bb6 (cleanup): {
// drop(_1) -> bb1;
// }
//
// bb7: {
// bb7 (cleanup): {
// drop(_4) -> bb6;
// }
//
Expand Down
43 changes: 43 additions & 0 deletions src/test/mir-opt/generator-drop-cleanup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#![feature(generators, generator_trait)]

// Regression test for #58892, generator drop shims should not have blocks
// spuriously marked as cleanup

fn main() {
let gen = || {
yield;
};
}

// END RUST SOURCE

// START rustc.main-{{closure}}.generator_drop.0.mir
// bb0: {
// switchInt(((*_1).0: u32)) -> [0u32: bb4, 3u32: bb7, otherwise: bb8];
// }
// bb1: {
// goto -> bb5;
// }
// bb2: {
// return;
// }
// bb3: {
// return;
// }
// bb4: {
// goto -> bb6;
// }
// bb5: {
// goto -> bb2;
// }
// bb6: {
// goto -> bb3;
// }
// bb7: {
// StorageLive(_3);
// goto -> bb1;
// }
// bb8: {
// return;
// }
// END rustc.main-{{closure}}.generator_drop.0.mir
2 changes: 1 addition & 1 deletion src/test/mir-opt/issue-38669.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main() {
// FakeRead(ForLet, _1);
// goto -> bb2;
// }
// bb1: {
// bb1 (cleanup): {
// resume;
// }
// bb2: {
Expand Down
2 changes: 1 addition & 1 deletion src/test/mir-opt/issue-49232.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fn main() {
// FakeRead(ForMatchedPlace, _3);
// switchInt(_3) -> [false: bb9, otherwise: bb8];
// }
// bb4: {
// bb4 (cleanup): {
// resume;
// }
// bb5: {
Expand Down
2 changes: 1 addition & 1 deletion src/test/mir-opt/loop_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main() {
// END RUST SOURCE
// START rustc.main.SimplifyCfg-qualify-consts.after.mir
// ...
// bb1: { // The cleanup block
// bb1 (cleanup): {
// resume;
// }
// ...
Expand Down
6 changes: 3 additions & 3 deletions src/test/mir-opt/match_false_edges.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ fn main() {
// _3 = discriminant(_2);
// switchInt(move _3) -> [0isize: bb4, 1isize: bb2, otherwise: bb7];
// }
// bb1: {
// bb1 (cleanup): {
// resume;
// }
// bb2: {
Expand Down Expand Up @@ -116,7 +116,7 @@ fn main() {
// _3 = discriminant(_2);
// switchInt(move _3) -> [0isize: bb3, 1isize: bb2, otherwise: bb7];
// }
// bb1: {
// bb1 (cleanup): {
// resume;
// }
// bb2: {
Expand Down Expand Up @@ -185,7 +185,7 @@ fn main() {
// _3 = discriminant(_2);
// switchInt(move _3) -> [1isize: bb2, otherwise: bb3];
// }
// bb1: {
// bb1 (cleanup): {
// resume;
// }
// bb2: {
Expand Down
4 changes: 2 additions & 2 deletions src/test/mir-opt/packed-struct-drop-aligned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ impl Drop for Droppy {
// _6 = move (_1.0: Aligned);
// drop(_6) -> [return: bb4, unwind: bb3];
// }
// bb1: {
// bb1 (cleanup): {
// resume;
// }
// bb2: {
// StorageDead(_1);
// return;
// }
// bb3: {
// bb3 (cleanup): {
// (_1.0: Aligned) = move _4;
// drop(_1) -> bb1;
// }
Expand Down
4 changes: 2 additions & 2 deletions src/test/mir-opt/remove_fake_borrows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn main() {
// StorageDead(_8);
// return;
// }
// bb10: {
// bb10 (cleanup): {
// resume;
// }
// END rustc.match_guard.CleanupNonCodegenStatements.before.mir
Expand Down Expand Up @@ -114,7 +114,7 @@ fn main() {
// StorageDead(_8);
// return;
// }
// bb10: {
// bb10 (cleanup): {
// resume;
// }
// END rustc.match_guard.CleanupNonCodegenStatements.after.mir
10 changes: 5 additions & 5 deletions src/test/mir-opt/unusual-item-types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn main() {
// _0 = const 2i32;
// return;
// }
// bb1: {
// bb1 (cleanup): {
// resume;
// }
// END rustc.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir
Expand All @@ -39,7 +39,7 @@ fn main() {
// _0 = const 5isize;
// return;
// }
// bb1: {
// bb1 (cleanup): {
// resume;
// }
// END rustc.E-V-{{constant}}.mir_map.0.mir
Expand All @@ -51,16 +51,16 @@ fn main() {
// bb1: {
// return;
// }
// bb2: {
// bb2 (cleanup): {
// resume;
// }
// bb3: {
// goto -> bb1;
// }
// bb4: {
// bb4 (cleanup): {
// goto -> bb2;
// }
// bb5: {
// bb5 (cleanup): {
// drop(((*_1).0: alloc::raw_vec::RawVec<i32>)) -> bb4;
// }
// bb6: {
Expand Down
22 changes: 22 additions & 0 deletions src/test/run-fail/generator-resume-after-panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// error-pattern:generator resumed after panicking

// Test that we get the correct message for resuming a panicked generator.

#![feature(generators, generator_trait)]

use std::{
ops::Generator,
pin::Pin,
panic,
};

fn main() {
let mut g = || {
panic!();
yield;
};
panic::catch_unwind(panic::AssertUnwindSafe(|| {
let x = Pin::new(&mut g).resume();
}));
Pin::new(&mut g).resume();
}

0 comments on commit fdb2ecd

Please sign in to comment.