about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbobtwinkles <srkoser+GitHub@gmail.com>2018-01-26 18:25:25 -0500
committerbobtwinkles <srkoser+GitHub@gmail.com>2018-02-05 15:00:40 -0500
commited6a2ebcd6d36f2e0760d419094a653bda984bc2 (patch)
treebd57d5e7217d3eddf00b4bd20970a998b736c127 /src
parentbdc37aa05722818e8edb5d93825a62921f351913 (diff)
downloadrust-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.rs22
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()