diff options
| author | bobtwinkles <srkoser+GitHub@gmail.com> | 2018-01-26 18:25:25 -0500 |
|---|---|---|
| committer | bobtwinkles <srkoser+GitHub@gmail.com> | 2018-02-05 15:00:40 -0500 |
| commit | ed6a2ebcd6d36f2e0760d419094a653bda984bc2 (patch) | |
| tree | bd57d5e7217d3eddf00b4bd20970a998b736c127 /src | |
| parent | bdc37aa05722818e8edb5d93825a62921f351913 (diff) | |
| download | rust-ed6a2ebcd6d36f2e0760d419094a653bda984bc2.tar.gz rust-ed6a2ebcd6d36f2e0760d419094a653bda984bc2.zip | |
mir: Add false edge cleanup out of infinite loops
Fixes #46036
Diffstat (limited to 'src')
| -rw-r--r-- | src/librustc_mir/build/expr/into.rs | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index fa98dc8b110..089ce3f71a5 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -156,11 +156,15 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // // If `opt_cond_expr` is `None`, then the graph is somewhat simplified: // - // [block] --> [loop_block / body_block ] ~~> [body_block_end] [exit_block] - // ^ | - // | | - // +--------------------------+ + // [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. let loop_block = this.cfg.start_new_block(); let exit_block = this.cfg.start_new_block(); @@ -174,6 +178,7 @@ 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!( @@ -187,8 +192,15 @@ 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; + let diverge_cleanup = this.diverge_cleanup(); + out_terminator = TerminatorKind::FalseUnwind { + real_target: loop_block, + unwind: Some(diverge_cleanup) + } } // The “return” value of the loop body must always be an unit. We therefore @@ -197,7 +209,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, - TerminatorKind::Goto { target: loop_block }); + out_terminator); } ); exit_block.unit() |
