about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew Jasper <mjjasper1@gmail.com>2019-06-15 10:08:20 +0100
committerMatthew Jasper <mjjasper1@gmail.com>2019-06-25 22:41:22 +0100
commit62bec714462129adcc622575d69db558b3750a6e (patch)
tree894c4681e1138db08d1efa9b04e027f8fc346e3a
parent5f9c0448dde167128d668da4555879f64e56af1d (diff)
downloadrust-62bec714462129adcc622575d69db558b3750a6e.tar.gz
rust-62bec714462129adcc622575d69db558b3750a6e.zip
Fix incorrect double assignment in MIR for while loops
-rw-r--r--src/librustc_mir/build/expr/into.rs20
-rw-r--r--src/test/ui/nll/assign-while-to-immutable.rs11
2 files changed, 25 insertions, 6 deletions
diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs
index f70ecef0c25..dc74466e633 100644
--- a/src/librustc_mir/build/expr/into.rs
+++ b/src/librustc_mir/build/expr/into.rs
@@ -184,15 +184,23 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 loop_block_end = this.as_local_operand(loop_block, cond_expr)
                             );
                             body_block = this.cfg.start_new_block();
-                            let term =
-                                TerminatorKind::if_(this.hir.tcx(), cond, body_block, exit_block);
+                            let false_block = this.cfg.start_new_block();
+                            let term = TerminatorKind::if_(
+                                this.hir.tcx(),
+                                cond,
+                                body_block,
+                                false_block,
+                            );
                             this.cfg.terminate(loop_block_end, source_info, term);
 
                             // if the test is false, there's no `break` to assign `destination`, so
-                            // 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);
+                            // we have to do it
+                            this.cfg.push_assign_unit(false_block, source_info, destination);
+                            this.cfg.terminate(
+                                false_block,
+                                source_info,
+                                TerminatorKind::Goto { target: exit_block },
+                            );
                         } else {
                             body_block = this.cfg.start_new_block();
                             let diverge_cleanup = this.diverge_cleanup();
diff --git a/src/test/ui/nll/assign-while-to-immutable.rs b/src/test/ui/nll/assign-while-to-immutable.rs
new file mode 100644
index 00000000000..c803321b508
--- /dev/null
+++ b/src/test/ui/nll/assign-while-to-immutable.rs
@@ -0,0 +1,11 @@
+// We used to incorrectly assign to `x` twice when generating MIR for this
+// function, preventing this from compiling.
+
+// check-pass
+
+fn main() {
+    let x = while false {
+        break;
+    };
+    let y = 'l: while break 'l {};
+}