about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMark Simulacrum <mark.simulacrum@gmail.com>2018-05-26 11:22:53 -0600
committerGitHub <noreply@github.com>2018-05-26 11:22:53 -0600
commit90b7bf6e0a7c9ecd32bc7fd96a76e5e800f3e6ea (patch)
tree01627ef6c6279cb181485cbc488307d9ab8babcc /src
parent1594c6c650dfbb9606ead602548b96997d507f64 (diff)
parentd5bf4de0e4c86d5cacd5ca738e1ba65afc5586ca (diff)
downloadrust-90b7bf6e0a7c9ecd32bc7fd96a76e5e800f3e6ea.tar.gz
rust-90b7bf6e0a7c9ecd32bc7fd96a76e5e800f3e6ea.zip
Rollup merge of #51049 - varkor:break-while-condition, r=nikomatsakis
Fix behaviour of divergence in while loop conditions

This fixes `'a: while break 'a {};` being treated as diverging, by tracking break expressions in the same way as in `loop` expressions.

Fixes #50856.

r? @nikomatsakis
Diffstat (limited to 'src')
-rw-r--r--src/librustc_typeck/check/mod.rs14
-rw-r--r--src/test/ui/break-while-condition.rs39
-rw-r--r--src/test/ui/break-while-condition.stderr43
3 files changed, 92 insertions, 4 deletions
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 16695dcef8f..2007ab556c2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3844,10 +3844,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
               let ctxt = BreakableCtxt {
                   // cannot use break with a value from a while loop
                   coerce: None,
-                  may_break: true,
+                  may_break: false,  // Will get updated if/when we find a `break`.
               };
 
-              self.with_breakable_ctxt(expr.id, ctxt, || {
+              let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || {
                   self.check_expr_has_type_or_error(&cond, tcx.types.bool);
                   let cond_diverging = self.diverges.get();
                   self.check_block_no_value(&body);
@@ -3856,6 +3856,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                   self.diverges.set(cond_diverging);
               });
 
+              if ctxt.may_break {
+                  // No way to know whether it's diverging because
+                  // of a `break` or an outer `break` or `return`.
+                  self.diverges.set(Diverges::Maybe);
+              }
+
               self.tcx.mk_nil()
           }
           hir::ExprLoop(ref body, _, source) => {
@@ -3874,7 +3880,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
               let ctxt = BreakableCtxt {
                   coerce,
-                  may_break: false, // will get updated if/when we find a `break`
+                  may_break: false, // Will get updated if/when we find a `break`.
               };
 
               let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || {
@@ -3883,7 +3889,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
               if ctxt.may_break {
                   // No way to know whether it's diverging because
-                  // of a `break` or an outer `break` or `return.
+                  // of a `break` or an outer `break` or `return`.
                   self.diverges.set(Diverges::Maybe);
               }
 
diff --git a/src/test/ui/break-while-condition.rs b/src/test/ui/break-while-condition.rs
new file mode 100644
index 00000000000..050b479d485
--- /dev/null
+++ b/src/test/ui/break-while-condition.rs
@@ -0,0 +1,39 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(never_type)]
+
+fn main() {
+    // The `if false` expressions are simply to
+    // make sure we don't avoid checking everything
+    // simply because a few expressions are unreachable.
+
+    if false {
+        let _: ! = { //~ ERROR mismatched types
+            'a: while break 'a {};
+        };
+    }
+
+    if false {
+        let _: ! = {
+            while false { //~ ERROR mismatched types
+                break
+            }
+        };
+    }
+
+    if false {
+        let _: ! = {
+            while false { //~ ERROR mismatched types
+                return
+            }
+        };
+    }
+}
diff --git a/src/test/ui/break-while-condition.stderr b/src/test/ui/break-while-condition.stderr
new file mode 100644
index 00000000000..c8f06db9603
--- /dev/null
+++ b/src/test/ui/break-while-condition.stderr
@@ -0,0 +1,43 @@
+error[E0308]: mismatched types
+  --> $DIR/break-while-condition.rs:19:20
+   |
+LL |           let _: ! = { //~ ERROR mismatched types
+   |  ____________________^
+LL | |             'a: while break 'a {};
+LL | |         };
+   | |_________^ expected !, found ()
+   |
+   = note: expected type `!`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/break-while-condition.rs:26:13
+   |
+LL |   fn main() {
+   |             - expected `()` because of default return type
+...
+LL | /             while false { //~ ERROR mismatched types
+LL | |                 break
+LL | |             }
+   | |_____________^ expected !, found ()
+   |
+   = note: expected type `!`
+              found type `()`
+
+error[E0308]: mismatched types
+  --> $DIR/break-while-condition.rs:34:13
+   |
+LL |   fn main() {
+   |             - expected `()` because of default return type
+...
+LL | /             while false { //~ ERROR mismatched types
+LL | |                 return
+LL | |             }
+   | |_____________^ expected !, found ()
+   |
+   = note: expected type `!`
+              found type `()`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.