Having the following main function results in an illigal instruction on stable, beta and nighlty.
It should be noted that when n is not used after the loop, the illigal instruction does not occur
https://play.rust-lang.org/?gist=96a11fd41327de4bf4e2c371dd7c1660&version=stable&mode=debug
fn main() {
let mut n = 0;
'a: while {break 'a; true} {
n += 1;
}
n += 2;
}
Interestingly putting the same while-loop in a function works fine:
https://play.rust-lang.org/?gist=ed60d2118b970be39e09bc8653a25345&version=stable&mode=debug
Update:
A more simple version that also results in an illigal instruction:
https://play.rust-lang.org/?gist=489a23ba854eea0b1e435b447ba81dc1&version=stable&mode=debug
fn main() {
'a: while {break 'a; true} { }
1;
}
after some more trying, it can be shortened to this (and works for functions other than in main, as shown here: https://play.rust-lang.org/?gist=79ea8fe2b5a1b96ba49089e1b4df1254&version=nightly&mode=debug) :
fn main() {
'a: while break 'a{};
}
adding a return; statement at the end of main seems to 'fix' the problem
Checking the last example with godbolt,
'a"Err the last example is even featured in E0590 (introduced in #39864), but why this seems not tested at all 馃槖.
Edit: It generates an unreachable at MIR level.
// WARNING: This output format is intended for human consumers only
// and is subject to change without notice. Knock yourself out.
fn main() -> (){
let mut _0: (); // return place
bb0: {
unreachable; // bb0[0]: scope 0 at src/main.rs:1:11: 3:2
}
}
The initial MIR already contains an unreachable.
// MIR for `main`
// source = MirSource { def_id: DefId(0/0:3 ~ 3[317d]::main[0]), promoted: None }
// pass_name = mir_map
// disambiguator = 0
fn main() -> (){
let mut _0: (); // return place
let mut _1: !;
let mut _2: ();
let mut _3: bool;
let mut _4: !;
let mut _5: ();
bb0: {
goto -> bb1; // bb0[0]: scope 0 at 3.rs:2:5: 2:25
}
bb1: {
StorageLive(_3); // bb1[0]: scope 0 at 3.rs:2:15: 2:23
_2 = (); // bb1[1]: scope 0 at 3.rs:2:15: 2:23
goto -> bb4; // bb1[2]: scope 0 at 3.rs:2:15: 2:23
}
bb2: {
_2 = (); // bb2[0]: scope 0 at 3.rs:2:5: 2:25
StorageDead(_3); // bb2[1]: scope 0 at 3.rs:2:24: 2:25
unreachable; // bb2[2]: scope 0 at 3.rs:1:11: 3:2
}
bb3: { // cleanup
resume; // bb3[0]: scope 0 at 3.rs:1:1: 3:2
}
bb4: {
goto -> bb5; // bb4[0]: scope 0 at 3.rs:2:15: 2:23
}
bb5: {
goto -> bb6; // bb5[0]: scope 0 at 3.rs:2:15: 2:23
}
bb6: {
goto -> bb2; // bb6[0]: scope 0 at 3.rs:2:15: 2:23
}
bb7: {
_4 = (); // bb7[0]: scope 0 at 3.rs:2:15: 2:23
unreachable; // bb7[1]: scope 0 at 3.rs:2:15: 2:23
}
bb8: {
StorageDead(_4); // bb8[0]: scope 0 at 3.rs:2:22: 2:23
switchInt(move _3) -> [false: bb2, otherwise: bb9]; // bb8[1]: scope 0 at 3.rs:2:5: 2:25
}
bb9: {
_5 = (); // bb9[0]: scope 0 at 3.rs:2:23: 2:25
goto -> bb1; // bb9[1]: scope 0 at 3.rs:2:5: 2:25
}
bb10: {
StorageDead(_1); // bb10[0]: scope 0 at 3.rs:3:1: 3:2
goto -> bb11; // bb10[1]: scope 0 at 3.rs:3:2: 3:2
}
bb11: {
return; // bb11[0]: scope 0 at 3.rs:3:2: 3:2
}
}
-Zunpretty=hir,typed
#[prelude_import]
use std::prelude::v1::*;
#[macro_use]
extern crate std;
fn main() ({ ('a: while ((break 'a as !)) { } as ()); } as !)
Err the last example is even featured in E0590 (introduced in #39864), but why this seems not tested at all 馃槖.
It's because in the example that is tested, there's no semicolon:
fn main() {
'foo: while break 'foo {} // ok
}
fn main() {
'foo: while break 'foo {}; // uh-oh
}
_Why_ that makes a difference, I haven't determined yet.
The problem is, for some reason, the type checker inferred 'a: while break 'a {}; to have type !, and thus the rest of the block is unreachable.
// compile-pass, but shouldn't.
#![feature(never_type)]
fn main() {
let _: ! = { 'a: while break 'a {}; };
}
However, without the ; the inferred type is just () as expected.
Maybe slightly off-topic, but why are references to the label even allowed in the condition, rather than solely the body? You don't achieve extra expressiveness, as it's equivalent to returning false in the condition, and it makes things more complicated.
having code like this results in an ICE:
const ARR: [(); 0] = [ 'a: while break 'a {}; 0];
fn main() {
}
error: internal compiler error: librustc_mir/transform/qualify_consts.rs:273: multiple assignments to _1
--> src/main.rs:1:24
|
1 | const ARR: [(); 0] = [ 'a: while break 'a {}; 0];
| ^^^^^^^^^^^^^^^^^^^^^
thread 'rustc' panicked at 'Box<Any>', librustc_errors/lib.rs:488:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: aborting due to previous error
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports
note: rustc 1.26.0 (a77568041 2018-05-07) running on x86_64-unknown-linux-gnu
note: compiler flags: -C codegen-units=1 -C debuginfo=2 --crate-type bin
note: some of the compiler flags provided by cargo are hidden
error: Could not compile `playground`.
https://play.rust-lang.org/?gist=56a8ce6081021416d64f4a056aeae8ca&version=stable&mode=debug
Maybe slightly off-topic, but why are references to the label even allowed in the condition, rather than solely the body? You don't achieve extra expressiveness, as it's equivalent to returning false in the condition, and it makes things more complicated.
Because it is consistent with the desugaring of the while loop to a
'a: loop {
if { break 'a } { break 'a }
}
which is a valid and fairly sensible code.
I think the bug in in the type-checker then: it should not be giving 'a: while (break 'a) the type of !, clear. @varkor 鈥斅爕ou interested in fixing? I can give a few tips...
Marking as P-medium: technically a regression, but a very old one, and kind of a corner case. Still, I'll try to leave some notes on how to fix.
@nikomatsakis: yeah, I can have a look into this. Might be a little delayed, but definitely within the next couple of weeks.
Most helpful comment
Maybe slightly off-topic, but why are references to the label even allowed in the condition, rather than solely the body? You don't achieve extra expressiveness, as it's equivalent to returning false in the condition, and it makes things more complicated.