Skip to content

Commit a38a1ce

Browse files
committed
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.
1 parent 9823cb9 commit a38a1ce

File tree

3 files changed

+42
-4
lines changed

3 files changed

+42
-4
lines changed

src/librustc_typeck/check/mod.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3841,10 +3841,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38413841
let ctxt = BreakableCtxt {
38423842
// cannot use break with a value from a while loop
38433843
coerce: None,
3844-
may_break: true,
3844+
may_break: false, // Will get updated if/when we find a `break`.
38453845
};
38463846

3847-
self.with_breakable_ctxt(expr.id, ctxt, || {
3847+
let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || {
38483848
self.check_expr_has_type_or_error(&cond, tcx.types.bool);
38493849
let cond_diverging = self.diverges.get();
38503850
self.check_block_no_value(&body);
@@ -3853,6 +3853,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38533853
self.diverges.set(cond_diverging);
38543854
});
38553855

3856+
if ctxt.may_break {
3857+
// No way to know whether it's diverging because
3858+
// of a `break` or an outer `break` or `return`.
3859+
self.diverges.set(Diverges::Maybe);
3860+
}
3861+
38563862
self.tcx.mk_nil()
38573863
}
38583864
hir::ExprLoop(ref body, _, source) => {
@@ -3871,7 +3877,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38713877

38723878
let ctxt = BreakableCtxt {
38733879
coerce,
3874-
may_break: false, // will get updated if/when we find a `break`
3880+
may_break: false, // Will get updated if/when we find a `break`.
38753881
};
38763882

38773883
let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || {
@@ -3880,7 +3886,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38803886

38813887
if ctxt.may_break {
38823888
// No way to know whether it's diverging because
3883-
// of a `break` or an outer `break` or `return.
3889+
// of a `break` or an outer `break` or `return`.
38843890
self.diverges.set(Diverges::Maybe);
38853891
}
38863892

src/test/ui/break-while-condition.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(never_type)]
12+
13+
fn main() {
14+
let _: ! = { //~ ERROR mismatched types
15+
'a: while break 'a {};
16+
};
17+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/break-while-condition.rs:14:16
3+
|
4+
LL | let _: ! = { //~ ERROR mismatched types
5+
| ________________^
6+
LL | | 'a: while break 'a {};
7+
LL | | };
8+
| |_____^ expected !, found ()
9+
|
10+
= note: expected type `!`
11+
found type `()`
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)