Skip to content

Commit 90b7bf6

Browse files
Rollup merge of rust-lang#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 rust-lang#50856. r? @nikomatsakis
2 parents 1594c6c + d5bf4de commit 90b7bf6

File tree

3 files changed

+92
-4
lines changed

3 files changed

+92
-4
lines changed

src/librustc_typeck/check/mod.rs

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

3850-
self.with_breakable_ctxt(expr.id, ctxt, || {
3850+
let (ctxt, ()) = self.with_breakable_ctxt(expr.id, ctxt, || {
38513851
self.check_expr_has_type_or_error(&cond, tcx.types.bool);
38523852
let cond_diverging = self.diverges.get();
38533853
self.check_block_no_value(&body);
@@ -3856,6 +3856,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38563856
self.diverges.set(cond_diverging);
38573857
});
38583858

3859+
if ctxt.may_break {
3860+
// No way to know whether it's diverging because
3861+
// of a `break` or an outer `break` or `return`.
3862+
self.diverges.set(Diverges::Maybe);
3863+
}
3864+
38593865
self.tcx.mk_nil()
38603866
}
38613867
hir::ExprLoop(ref body, _, source) => {
@@ -3874,7 +3880,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38743880

38753881
let ctxt = BreakableCtxt {
38763882
coerce,
3877-
may_break: false, // will get updated if/when we find a `break`
3883+
may_break: false, // Will get updated if/when we find a `break`.
38783884
};
38793885

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

38843890
if ctxt.may_break {
38853891
// No way to know whether it's diverging because
3886-
// of a `break` or an outer `break` or `return.
3892+
// of a `break` or an outer `break` or `return`.
38873893
self.diverges.set(Diverges::Maybe);
38883894
}
38893895

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

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
// The `if false` expressions are simply to
15+
// make sure we don't avoid checking everything
16+
// simply because a few expressions are unreachable.
17+
18+
if false {
19+
let _: ! = { //~ ERROR mismatched types
20+
'a: while break 'a {};
21+
};
22+
}
23+
24+
if false {
25+
let _: ! = {
26+
while false { //~ ERROR mismatched types
27+
break
28+
}
29+
};
30+
}
31+
32+
if false {
33+
let _: ! = {
34+
while false { //~ ERROR mismatched types
35+
return
36+
}
37+
};
38+
}
39+
}
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/break-while-condition.rs:19:20
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[E0308]: mismatched types
14+
--> $DIR/break-while-condition.rs:26:13
15+
|
16+
LL | fn main() {
17+
| - expected `()` because of default return type
18+
...
19+
LL | / while false { //~ ERROR mismatched types
20+
LL | | break
21+
LL | | }
22+
| |_____________^ expected !, found ()
23+
|
24+
= note: expected type `!`
25+
found type `()`
26+
27+
error[E0308]: mismatched types
28+
--> $DIR/break-while-condition.rs:34:13
29+
|
30+
LL | fn main() {
31+
| - expected `()` because of default return type
32+
...
33+
LL | / while false { //~ ERROR mismatched types
34+
LL | | return
35+
LL | | }
36+
| |_____________^ expected !, found ()
37+
|
38+
= note: expected type `!`
39+
found type `()`
40+
41+
error: aborting due to 3 previous errors
42+
43+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)