[ci skip] Generate false edges from loop_block

As opposed to using weirdness involving pretending the body block
is the loop block. This does not pass tests

This commit is [ci skip] because I know it doesn't pass tests yet.
Somehow this commit introduces nondeterminism into the handling of
loops.
This commit is contained in:
bobtwinkles 2018-02-07 14:25:08 -05:00
parent eae1a35f55
commit 8e0c3f5c46
7 changed files with 86 additions and 72 deletions

View file

@ -147,24 +147,24 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
join_block.unit()
}
ExprKind::Loop { condition: opt_cond_expr, body } => {
// [block] --> [loop_block] ~~> [loop_block_end] -1-> [exit_block]
// ^ |
// | 0
// | |
// | v
// [body_block_end] <~~~ [body_block]
// [block] --> [loop_block] -/eval. cond./-> [loop_block_end] -1-> [exit_block]
// ^ |
// | 0
// | |
// | v
// [body_block_end] <-/eval. body/-- [body_block]
//
// If `opt_cond_expr` is `None`, then the graph is somewhat simplified:
//
// [block] --> [loop_block] ~~> [loop_block_end]
// | ^ |
// false link | |
// | +-------------------+
// v
// [cleanup_block]
//
// The false link is required in case something results in
// unwinding through the body.
// [block]
// |
// [loop_block] -> [body_block] -/eval. body/-> [body_block_end]
// | ^ |
// false link | |
// | +-----------------------------------------+
// +-> [diverge_cleanup]
// The false link is required to make sure borrowck considers unwinds through the
// body, even when the exact code in the body cannot unwind
let loop_block = this.cfg.start_new_block();
let exit_block = this.cfg.start_new_block();
@ -178,7 +178,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
move |this| {
// conduct the test, if necessary
let body_block;
let out_terminator;
if let Some(cond_expr) = opt_cond_expr {
let loop_block_end;
let cond = unpack!(
@ -192,15 +191,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// we have to do it; this overwrites any `break`-assigned value but it's
// always `()` anyway
this.cfg.push_assign_unit(exit_block, source_info, destination);
out_terminator = TerminatorKind::Goto { target: loop_block };
} else {
body_block = loop_block;
body_block = this.cfg.start_new_block();
let diverge_cleanup = this.diverge_cleanup();
out_terminator = TerminatorKind::FalseUnwind {
real_target: loop_block,
unwind: Some(diverge_cleanup)
}
this.cfg.terminate(loop_block, source_info,
TerminatorKind::FalseUnwind {
real_target: body_block,
unwind: Some(diverge_cleanup)
})
}
// The “return” value of the loop body must always be an unit. We therefore
@ -209,7 +207,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
// Execute the body, branching back to the test.
let body_block_end = unpack!(this.into(&tmp, body_block, body));
this.cfg.terminate(body_block_end, source_info,
out_terminator);
TerminatorKind::Goto { target: loop_block });
}
);
exit_block.unit()

View file

@ -40,18 +40,21 @@ fn main() {
// goto -> bb1;
// }
// bb1: {
// falseUnwind -> [real: bb2, cleanup: bb3];
// }
// bb2: {
// StorageLive(_2);
// _2 = const true;
// StorageLive(_3);
// _3 = &'23_1rs _2;
// StorageLive(_5);
// _5 = _2;
// switchInt(move _5) -> [0u8: bb4, otherwise: bb3];
// }
// bb2: {
// ...
// switchInt(move _5) -> [0u8: bb5, otherwise: bb4];
// }
// bb3: {
// ...
// }
// bb4: {
// _0 = ();
// StorageDead(_5);
// EndRegion('23_1rs);
@ -59,7 +62,7 @@ fn main() {
// StorageDead(_2);
// return;
// }
// bb4: {
// bb5: {
// _4 = ();
// StorageDead(_5);
// StorageLive(_7);
@ -70,6 +73,6 @@ fn main() {
// EndRegion('23_1rs);
// StorageDead(_3);
// StorageDead(_2);
// falseUnwind -> [real: bb1, cleanup: bb2];
// goto -> bb1;
// }
// END rustc.main.SimplifyCfg-qualify-consts.after.mir

View file

@ -43,17 +43,20 @@ fn main() {
// goto -> bb1;
// }
// bb1: {
// falseUnwind -> [real: bb2, cleanup: bb3];
// }
// bb2: {
// _1 = const true;
// StorageLive(_3);
// _3 = &'26_1rs _1;
// StorageLive(_5);
// _5 = _1;
// switchInt(move _5) -> [0u8: bb4, otherwise: bb3];
// }
// bb2: {
// ...
// switchInt(move _5) -> [0u8: bb5, otherwise: bb4];
// }
// bb3: {
// ...
// }
// bb4: {
// _0 = ();
// StorageDead(_5);
// EndRegion('26_1rs);
@ -61,7 +64,7 @@ fn main() {
// StorageDead(_1);
// return;
// }
// bb4: {
// bb5: {
// _4 = ();
// StorageDead(_5);
// StorageLive(_7);
@ -71,6 +74,6 @@ fn main() {
// StorageDead(_7);
// EndRegion('26_1rs);
// StorageDead(_3);
// falseUnwind -> [real: bb1, cleanup: bb2];
// goto -> bb1;
// }
// END rustc.main.SimplifyCfg-qualify-consts.after.mir

View file

@ -57,18 +57,24 @@ fn main() {
// _1 = const false;
// StorageLive(_2);
// _2 = const 3i32;
// StorageLive(_4);
// goto -> bb2;
// falseUnwind -> [real: bb2, cleanup: bb1];
// }
// bb1: {
// ...
// }
// bb2: {
// StorageLive(_7);
// _7 = _1;
// switchInt(move _7) -> [0u8: bb4, otherwise: bb3];
// StorageLive(_4);
// goto -> bb3;
// }
// bb3: {
// falseUnwind -> [real: bb4, cleanup: bb1];
// }
// bb4: {
// StorageLive(_7);
// _7 = _1;
// switchInt(move _7) -> [0u8: bb6, otherwise: bb5];
// }
// bb5: {
// _0 = ();
// StorageDead(_7);
// EndRegion('33_0rs);
@ -77,13 +83,13 @@ fn main() {
// StorageDead(_1);
// return;
// }
// bb4: {
// bb6: {
// _4 = &'33_0rs _2;
// _6 = ();
// StorageDead(_7);
// _1 = const true;
// _3 = ();
// falseUnwind -> [real: bb2, cleanup: bb1];
// goto -> bb3;
// }
// }
// END rustc.main.SimplifyCfg-qualify-consts.after.mir

View file

@ -67,16 +67,19 @@ fn query() -> bool { true }
// goto -> bb1;
// }
// bb1: {
// falseUnwind -> [real: bb2, cleanup: bb3];
// }
// bb2: {
// StorageLive(_2);
// StorageLive(_3);
// StorageLive(_4);
// _4 = std::option::Option<&'35_0rs S<'35_0rs>>::None;
// _3 = const <std::cell::Cell<T>>::new(move _4) -> [return: bb3, unwind: bb2];
// }
// bb2: {
// resume;
// _3 = const <std::cell::Cell<T>>::new(move _4) -> [return: bb4, unwind: bb3];
// }
// bb3: {
// resume;
// }
// bb4: {
// StorageDead(_4);
// _2 = S<'35_0rs> { r: move _3 };
// StorageDead(_3);
@ -89,27 +92,27 @@ fn query() -> bool { true }
// _8 = &'35_0rs (*_9);
// _7 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _8,);
// StorageDead(_8);
// _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> [return: bb4, unwind: bb2];
// _5 = const <std::cell::Cell<T>>::set(move _6, move _7) -> [return: bb5, unwind: bb3];
// }
// bb4: {
// bb5: {
// EndRegion('16s);
// StorageDead(_7);
// StorageDead(_6);
// StorageDead(_9);
// StorageLive(_11);
// _11 = const query() -> [return: bb5, unwind: bb2];
// }
// bb5: {
// switchInt(move _11) -> [0u8: bb7, otherwise: bb6];
// _11 = const query() -> [return: bb6, unwind: bb3];
// }
// bb6: {
// switchInt(move _11) -> [0u8: bb8, otherwise: bb7];
// }
// bb7: {
// _0 = ();
// StorageDead(_11);
// EndRegion('35_0rs);
// StorageDead(_2);
// return;
// }
// bb7: {
// bb8: {
// _10 = ();
// StorageDead(_11);
// StorageLive(_14);
@ -121,9 +124,9 @@ fn query() -> bool { true }
// _16 = &'35_0rs (*_17);
// _15 = std::option::Option<&'35_0rs S<'35_0rs>>::Some(move _16,);
// StorageDead(_16);
// _13 = const <std::cell::Cell<T>>::set(move _14, move _15) -> [return: bb8, unwind: bb2];
// _13 = const <std::cell::Cell<T>>::set(move _14, move _15) -> [return: bb9, unwind: bb3];
// }
// bb8: {
// bb9: {
// EndRegion('33s);
// StorageDead(_15);
// StorageDead(_14);
@ -131,7 +134,7 @@ fn query() -> bool { true }
// _1 = ();
// EndRegion('35_0rs);
// StorageDead(_2);
// falseUnwind -> [real: bb1, cleanup: bb2];
// goto -> bb1;
// }
// }
// END rustc.main.SimplifyCfg-qualify-consts.after.mir

View file

@ -27,27 +27,28 @@ fn main() {
// _1 = const false;
// goto -> bb2;
// }
//
// bb1: {
// resume;
// }
// bb2: {
// StorageLive(_4);
// _4 = _1;
// switchInt(move _4) -> [0u8: bb4, otherwise: bb3];
// falseUnwind -> [real: bb3, cleanup: bb1];
// }
// bb3: {
// StorageLive(_4);
// _4 = _1;
// switchInt(move _4) -> [0u8: bb5, otherwise: bb4];
// }
// bb4: {
// _0 = ();
// StorageDead(_4);
// StorageDead(_1);
// return;
// }
//
// bb4: {
// bb5: {
// _3 = ();
// StorageDead(_4);
// _1 = const true;
// _2 = ();
// falseUnwind -> [real: bb2, cleanup: bb1];
// goto -> bb2;
// }
// END rustc.main.SimplifyCfg-initial.after.mir

View file

@ -25,17 +25,17 @@ fn main() {
// END RUST SOURCE
// START rustc.main.nll.0.mir
// | Live variables on entry to bb2: []
// bb2: {
// | Live variables on entry to bb2[0]: []
// | Live variables on entry to bb3: []
// bb3: {
// | Live variables on entry to bb3[0]: []
// _1 = const 55usize;
// | Live variables on entry to bb2[1]: [_1]
// | Live variables on entry to bb3[1]: [_1]
// StorageLive(_3);
// | Live variables on entry to bb2[2]: [_1]
// | Live variables on entry to bb3[2]: [_1]
// StorageLive(_4);
// | Live variables on entry to bb2[3]: [_1]
// | Live variables on entry to bb3[3]: [_1]
// _4 = _1;
// | Live variables on entry to bb2[4]: [_4]
// _3 = const use_x(move _4) -> [return: bb3, unwind: bb1];
// | Live variables on entry to bb3[4]: [_4]
// _3 = const use_x(move _4) -> [return: bb4, unwind: bb1];
// }
// END rustc.main.nll.0.mir