summaryrefslogtreecommitdiffstats
path: root/src/test/ui/for-loop-while
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/for-loop-while
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/test/ui/for-loop-while/auto-loop.rs10
-rw-r--r--src/test/ui/for-loop-while/break-outside-loop.rs35
-rw-r--r--src/test/ui/for-loop-while/break-outside-loop.stderr58
-rw-r--r--src/test/ui/for-loop-while/break-value.rs7
-rw-r--r--src/test/ui/for-loop-while/break-while-condition.rs29
-rw-r--r--src/test/ui/for-loop-while/break-while-condition.stderr37
-rw-r--r--src/test/ui/for-loop-while/break.rs25
-rw-r--r--src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs41
-rw-r--r--src/test/ui/for-loop-while/for-destruct.rs9
-rw-r--r--src/test/ui/for-loop-while/for-loop-goofiness.rs16
-rw-r--r--src/test/ui/for-loop-while/for-loop-has-unit-body.rs13
-rw-r--r--src/test/ui/for-loop-while/for-loop-into-iterator.rs19
-rw-r--r--src/test/ui/for-loop-while/for-loop-lifetime-of-unbound-values.rs34
-rw-r--r--src/test/ui/for-loop-while/for-loop-macro.rs11
-rw-r--r--src/test/ui/for-loop-while/for-loop-mut-ref-element.rs6
-rw-r--r--src/test/ui/for-loop-while/for-loop-no-std.rs14
-rw-r--r--src/test/ui/for-loop-while/for-loop-panic.rs4
-rw-r--r--src/test/ui/for-loop-while/for-loop-unconstrained-element-type-i32-fallback.rs11
-rw-r--r--src/test/ui/for-loop-while/foreach-external-iterators-break.rs13
-rw-r--r--src/test/ui/for-loop-while/foreach-external-iterators-hashmap-break-restart.rs33
-rw-r--r--src/test/ui/for-loop-while/foreach-external-iterators-hashmap.rs19
-rw-r--r--src/test/ui/for-loop-while/foreach-external-iterators-loop.rs13
-rw-r--r--src/test/ui/for-loop-while/foreach-external-iterators-nested.rs15
-rw-r--r--src/test/ui/for-loop-while/foreach-external-iterators.rs10
-rw-r--r--src/test/ui/for-loop-while/foreach-nested.rs16
-rw-r--r--src/test/ui/for-loop-while/foreach-put-structured.rs22
-rw-r--r--src/test/ui/for-loop-while/foreach-simple-outer-slot.rs16
-rw-r--r--src/test/ui/for-loop-while/issue-2216.rs24
-rw-r--r--src/test/ui/for-loop-while/issue-51345.rs8
-rw-r--r--src/test/ui/for-loop-while/issue-69841.rs31
-rw-r--r--src/test/ui/for-loop-while/label_break_value.rs167
-rw-r--r--src/test/ui/for-loop-while/label_break_value_invalid.rs36
-rw-r--r--src/test/ui/for-loop-while/label_break_value_invalid.stderr32
-rw-r--r--src/test/ui/for-loop-while/labeled-break.rs22
-rw-r--r--src/test/ui/for-loop-while/linear-for-loop.rs23
-rw-r--r--src/test/ui/for-loop-while/liveness-assign-imm-local-after-loop.rs18
-rw-r--r--src/test/ui/for-loop-while/liveness-loop-break.rs13
-rw-r--r--src/test/ui/for-loop-while/liveness-move-in-loop.rs20
-rw-r--r--src/test/ui/for-loop-while/long-while.rs12
-rw-r--r--src/test/ui/for-loop-while/loop-break-cont-1.rs9
-rw-r--r--src/test/ui/for-loop-while/loop-break-cont.rs39
-rw-r--r--src/test/ui/for-loop-while/loop-break-value.rs139
-rw-r--r--src/test/ui/for-loop-while/loop-diverges.rs14
-rw-r--r--src/test/ui/for-loop-while/loop-label-shadowing.rs12
-rw-r--r--src/test/ui/for-loop-while/loop-labeled-break-value.rs11
-rw-r--r--src/test/ui/for-loop-while/loop-no-reinit-needed-post-bot.rs34
-rw-r--r--src/test/ui/for-loop-while/loop-scope.rs8
-rw-r--r--src/test/ui/for-loop-while/while-cont.rs11
-rw-r--r--src/test/ui/for-loop-while/while-flow-graph.rs6
-rw-r--r--src/test/ui/for-loop-while/while-label.rs15
-rw-r--r--src/test/ui/for-loop-while/while-let-2.rs31
-rw-r--r--src/test/ui/for-loop-while/while-let-2.stderr42
-rw-r--r--src/test/ui/for-loop-while/while-let.rs46
-rw-r--r--src/test/ui/for-loop-while/while-loop-constraints-2.rs15
-rw-r--r--src/test/ui/for-loop-while/while-prelude-drop.rs24
-rw-r--r--src/test/ui/for-loop-while/while-with-break.rs17
-rw-r--r--src/test/ui/for-loop-while/while.rs13
57 files changed, 1428 insertions, 0 deletions
diff --git a/src/test/ui/for-loop-while/auto-loop.rs b/src/test/ui/for-loop-while/auto-loop.rs
new file mode 100644
index 000000000..f02ac43c7
--- /dev/null
+++ b/src/test/ui/for-loop-while/auto-loop.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+pub fn main() {
+ let mut sum = 0;
+ let xs = vec![1, 2, 3, 4, 5];
+ for x in &xs {
+ sum += *x;
+ }
+ assert_eq!(sum, 15);
+}
diff --git a/src/test/ui/for-loop-while/break-outside-loop.rs b/src/test/ui/for-loop-while/break-outside-loop.rs
new file mode 100644
index 000000000..26769b30d
--- /dev/null
+++ b/src/test/ui/for-loop-while/break-outside-loop.rs
@@ -0,0 +1,35 @@
+struct Foo {
+ t: String
+}
+
+fn cond() -> bool { true }
+
+fn foo<F>(_: F) where F: FnOnce() {}
+
+fn main() {
+ let pth = break; //~ ERROR: `break` outside of a loop
+ if cond() { continue } //~ ERROR: `continue` outside of a loop
+
+ while cond() {
+ if cond() { break }
+ if cond() { continue }
+ foo(|| {
+ if cond() { break } //~ ERROR: `break` inside of a closure
+ if cond() { continue } //~ ERROR: `continue` inside of a closure
+ })
+ }
+
+ let rs: Foo = Foo{t: pth};
+
+ let unconstrained = break; //~ ERROR: `break` outside of a loop
+
+ // This used to ICE because `target_id` passed to `check_expr_break` would be the closure and
+ // not the `loop`, which failed in the call to `find_breakable`. (#65383)
+ 'lab: loop {
+ || {
+ break 'lab;
+ //~^ ERROR use of unreachable label `'lab`
+ //~| ERROR `break` inside of a closure
+ };
+ }
+}
diff --git a/src/test/ui/for-loop-while/break-outside-loop.stderr b/src/test/ui/for-loop-while/break-outside-loop.stderr
new file mode 100644
index 000000000..287bf9af6
--- /dev/null
+++ b/src/test/ui/for-loop-while/break-outside-loop.stderr
@@ -0,0 +1,58 @@
+error[E0767]: use of unreachable label `'lab`
+ --> $DIR/break-outside-loop.rs:30:19
+ |
+LL | 'lab: loop {
+ | ---- unreachable label defined here
+LL | || {
+LL | break 'lab;
+ | ^^^^ unreachable label `'lab`
+ |
+ = note: labels are unreachable through functions, closures, async blocks and modules
+
+error[E0268]: `break` outside of a loop
+ --> $DIR/break-outside-loop.rs:10:15
+ |
+LL | let pth = break;
+ | ^^^^^ cannot `break` outside of a loop
+
+error[E0268]: `continue` outside of a loop
+ --> $DIR/break-outside-loop.rs:11:17
+ |
+LL | if cond() { continue }
+ | ^^^^^^^^ cannot `continue` outside of a loop
+
+error[E0267]: `break` inside of a closure
+ --> $DIR/break-outside-loop.rs:17:25
+ |
+LL | foo(|| {
+ | -- enclosing closure
+LL | if cond() { break }
+ | ^^^^^ cannot `break` inside of a closure
+
+error[E0267]: `continue` inside of a closure
+ --> $DIR/break-outside-loop.rs:18:25
+ |
+LL | foo(|| {
+ | -- enclosing closure
+LL | if cond() { break }
+LL | if cond() { continue }
+ | ^^^^^^^^ cannot `continue` inside of a closure
+
+error[E0268]: `break` outside of a loop
+ --> $DIR/break-outside-loop.rs:24:25
+ |
+LL | let unconstrained = break;
+ | ^^^^^ cannot `break` outside of a loop
+
+error[E0267]: `break` inside of a closure
+ --> $DIR/break-outside-loop.rs:30:13
+ |
+LL | || {
+ | -- enclosing closure
+LL | break 'lab;
+ | ^^^^^^^^^^ cannot `break` inside of a closure
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0267, E0268, E0767.
+For more information about an error, try `rustc --explain E0267`.
diff --git a/src/test/ui/for-loop-while/break-value.rs b/src/test/ui/for-loop-while/break-value.rs
new file mode 100644
index 000000000..9fc49fa81
--- /dev/null
+++ b/src/test/ui/for-loop-while/break-value.rs
@@ -0,0 +1,7 @@
+// run-pass
+#![allow(unreachable_code)]
+// pretty-expanded FIXME #23616
+
+fn int_id(x: isize) -> isize { return x; }
+
+pub fn main() { loop { int_id(break); } }
diff --git a/src/test/ui/for-loop-while/break-while-condition.rs b/src/test/ui/for-loop-while/break-while-condition.rs
new file mode 100644
index 000000000..6064e6ab0
--- /dev/null
+++ b/src/test/ui/for-loop-while/break-while-condition.rs
@@ -0,0 +1,29 @@
+#![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/for-loop-while/break-while-condition.stderr b/src/test/ui/for-loop-while/break-while-condition.stderr
new file mode 100644
index 000000000..6960c4fd8
--- /dev/null
+++ b/src/test/ui/for-loop-while/break-while-condition.stderr
@@ -0,0 +1,37 @@
+error[E0308]: mismatched types
+ --> $DIR/break-while-condition.rs:9:20
+ |
+LL | let _: ! = {
+ | ____________________^
+LL | | 'a: while break 'a {};
+LL | | };
+ | |_________^ expected `!`, found `()`
+ |
+ = note: expected type `!`
+ found unit type `()`
+
+error[E0308]: mismatched types
+ --> $DIR/break-while-condition.rs:16:13
+ |
+LL | / while false {
+LL | | break
+LL | | }
+ | |_____________^ expected `!`, found `()`
+ |
+ = note: expected type `!`
+ found unit type `()`
+
+error[E0308]: mismatched types
+ --> $DIR/break-while-condition.rs:24:13
+ |
+LL | / while false {
+LL | | return
+LL | | }
+ | |_____________^ expected `!`, found `()`
+ |
+ = note: expected type `!`
+ found unit type `()`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/for-loop-while/break.rs b/src/test/ui/for-loop-while/break.rs
new file mode 100644
index 000000000..427b1b7a0
--- /dev/null
+++ b/src/test/ui/for-loop-while/break.rs
@@ -0,0 +1,25 @@
+// run-pass
+
+pub fn main() {
+ let mut i = 0;
+ while i < 20 { i += 1; if i == 10 { break; } }
+ assert_eq!(i, 10);
+ loop { i += 1; if i == 20 { break; } }
+ assert_eq!(i, 20);
+ let xs = [1, 2, 3, 4, 5, 6];
+ for x in &xs {
+ if *x == 3 { break; } assert!((*x <= 3));
+ }
+ i = 0;
+ while i < 10 { i += 1; if i % 2 == 0 { continue; } assert!((i % 2 != 0)); }
+ i = 0;
+ loop {
+ i += 1; if i % 2 == 0 { continue; } assert!((i % 2 != 0));
+ if i >= 10 { break; }
+ }
+ let ys = vec![1, 2, 3, 4, 5, 6];
+ for x in &ys {
+ if *x % 2 == 0 { continue; }
+ assert!((*x % 2 != 0));
+ }
+}
diff --git a/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs b/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs
new file mode 100644
index 000000000..afc77355a
--- /dev/null
+++ b/src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs
@@ -0,0 +1,41 @@
+// run-pass
+// This test verifies that temporaries created for `while`'s and `if`
+// conditions are dropped after the condition is evaluated.
+
+struct Temporary;
+
+static mut DROPPED: isize = 0;
+
+impl Drop for Temporary {
+ fn drop(&mut self) {
+ unsafe { DROPPED += 1; }
+ }
+}
+
+impl Temporary {
+ fn do_stuff(&self) -> bool {true}
+}
+
+fn borrow() -> Box<Temporary> { Box::new(Temporary) }
+
+
+pub fn main() {
+ let mut i = 0;
+
+ // This loop's condition
+ // should call `Temporary`'s
+ // `drop` 6 times.
+ while borrow().do_stuff() {
+ i += 1;
+ unsafe { assert_eq!(DROPPED, i) }
+ if i > 5 {
+ break;
+ }
+ }
+
+ // This if condition should
+ // call it 1 time
+ if borrow().do_stuff() {
+ unsafe { assert_eq!(DROPPED, i + 1) }
+ }
+}
diff --git a/src/test/ui/for-loop-while/for-destruct.rs b/src/test/ui/for-loop-while/for-destruct.rs
new file mode 100644
index 000000000..7ca8d4ded
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-destruct.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+struct Pair { x: isize, y: isize }
+
+pub fn main() {
+ for elt in &(vec![Pair {x: 10, y: 20}, Pair {x: 30, y: 0}]) {
+ assert_eq!(elt.x + elt.y, 30);
+ }
+}
diff --git a/src/test/ui/for-loop-while/for-loop-goofiness.rs b/src/test/ui/for-loop-while/for-loop-goofiness.rs
new file mode 100644
index 000000000..872ab168b
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-goofiness.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![allow(dead_code)]
+
+enum BogusOption<T> {
+ None,
+ Some(T),
+}
+
+type Iterator = isize;
+
+pub fn main() {
+ let x = [ 3, 3, 3 ];
+ for i in &x {
+ assert_eq!(*i, 3);
+ }
+}
diff --git a/src/test/ui/for-loop-while/for-loop-has-unit-body.rs b/src/test/ui/for-loop-while/for-loop-has-unit-body.rs
new file mode 100644
index 000000000..eba385461
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-has-unit-body.rs
@@ -0,0 +1,13 @@
+// run-pass
+fn main() {
+ // Check that the tail statement in the body unifies with something
+ for _ in 0..3 {
+ // `()` is fine to zero-initialize as it is zero sized and inhabited.
+ unsafe { std::mem::zeroed() }
+ }
+
+ // Check that the tail statement in the body can be unit
+ for _ in 0..3 {
+ ()
+ }
+}
diff --git a/src/test/ui/for-loop-while/for-loop-into-iterator.rs b/src/test/ui/for-loop-while/for-loop-into-iterator.rs
new file mode 100644
index 000000000..199d4ddb2
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-into-iterator.rs
@@ -0,0 +1,19 @@
+// run-pass
+// Test that for loops can do what RFC #235 claims
+
+
+fn main() {
+ let mut v = vec![1];
+
+ for x in &v {
+ assert_eq!(x, &1);
+ }
+
+ for x in &mut v {
+ assert_eq!(x, &mut 1);
+ }
+
+ for x in v {
+ assert_eq!(x, 1);
+ }
+}
diff --git a/src/test/ui/for-loop-while/for-loop-lifetime-of-unbound-values.rs b/src/test/ui/for-loop-while/for-loop-lifetime-of-unbound-values.rs
new file mode 100644
index 000000000..6a38764a1
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-lifetime-of-unbound-values.rs
@@ -0,0 +1,34 @@
+// run-pass
+// Test when destructors run in a for loop. The intention is
+// that the value for each iteration is dropped *after* the loop
+// body has executed. This is true even when the value is assigned
+// to a `_` pattern (and hence ignored).
+
+use std::cell::Cell;
+
+struct Flag<'a>(&'a Cell<bool>);
+
+impl<'a> Drop for Flag<'a> {
+ fn drop(&mut self) {
+ self.0.set(false)
+ }
+}
+
+fn main() {
+ let alive2 = Cell::new(true);
+ for _i in std::iter::once(Flag(&alive2)) {
+ // The Flag value should be alive in the for loop body
+ assert_eq!(alive2.get(), true);
+ }
+ // The Flag value should be dead outside of the loop
+ assert_eq!(alive2.get(), false);
+
+ let alive = Cell::new(true);
+ for _ in std::iter::once(Flag(&alive)) {
+ // The Flag value should be alive in the for loop body even if it wasn't
+ // bound by the for loop
+ assert_eq!(alive.get(), true);
+ }
+ // The Flag value should be dead outside of the loop
+ assert_eq!(alive.get(), false);
+}
diff --git a/src/test/ui/for-loop-while/for-loop-macro.rs b/src/test/ui/for-loop-while/for-loop-macro.rs
new file mode 100644
index 000000000..5abccd2a1
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-macro.rs
@@ -0,0 +1,11 @@
+// run-pass
+macro_rules! var {
+ ( $name:ident ) => ( $name );
+}
+
+pub fn main() {
+ let x = [ 3, 3, 3 ];
+ for var!(i) in &x {
+ assert_eq!(*i, 3);
+ }
+}
diff --git a/src/test/ui/for-loop-while/for-loop-mut-ref-element.rs b/src/test/ui/for-loop-while/for-loop-mut-ref-element.rs
new file mode 100644
index 000000000..a3d82ace9
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-mut-ref-element.rs
@@ -0,0 +1,6 @@
+// run-pass
+// Tests that for loops can bind elements as mutable references
+
+fn main() {
+ for ref mut _a in std::iter::once(true) {}
+}
diff --git a/src/test/ui/for-loop-while/for-loop-no-std.rs b/src/test/ui/for-loop-while/for-loop-no-std.rs
new file mode 100644
index 000000000..65a33c5f1
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-no-std.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![allow(unused_imports)]
+#![feature(lang_items, start)]
+#![no_std]
+
+extern crate std as other;
+
+#[macro_use] extern crate alloc;
+
+#[start]
+fn start(_argc: isize, _argv: *const *const u8) -> isize {
+ for _ in [1,2,3].iter() { }
+ 0
+}
diff --git a/src/test/ui/for-loop-while/for-loop-panic.rs b/src/test/ui/for-loop-while/for-loop-panic.rs
new file mode 100644
index 000000000..ac607d6d7
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-panic.rs
@@ -0,0 +1,4 @@
+// run-pass
+
+
+pub fn main() { let x: Vec<isize> = Vec::new(); for _ in &x { panic!("moop"); } }
diff --git a/src/test/ui/for-loop-while/for-loop-unconstrained-element-type-i32-fallback.rs b/src/test/ui/for-loop-while/for-loop-unconstrained-element-type-i32-fallback.rs
new file mode 100644
index 000000000..a1e9b1ed8
--- /dev/null
+++ b/src/test/ui/for-loop-while/for-loop-unconstrained-element-type-i32-fallback.rs
@@ -0,0 +1,11 @@
+// run-pass
+// Test that the type of `sum` falls back to `i32` here,
+// and that the for loop desugaring doesn't interfere with
+// that.
+
+fn main() {
+ let mut sum = 0;
+ for i in Vec::new() {
+ sum += &i;
+ }
+}
diff --git a/src/test/ui/for-loop-while/foreach-external-iterators-break.rs b/src/test/ui/for-loop-while/foreach-external-iterators-break.rs
new file mode 100644
index 000000000..7de6a4f8a
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-external-iterators-break.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+pub fn main() {
+ let x = [1; 100];
+ let mut y = 0;
+ for i in &x[..] {
+ if y > 10 {
+ break;
+ }
+ y += *i;
+ }
+ assert_eq!(y, 11);
+}
diff --git a/src/test/ui/for-loop-while/foreach-external-iterators-hashmap-break-restart.rs b/src/test/ui/for-loop-while/foreach-external-iterators-hashmap-break-restart.rs
new file mode 100644
index 000000000..5d690807e
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-external-iterators-hashmap-break-restart.rs
@@ -0,0 +1,33 @@
+// run-pass
+
+use std::collections::HashMap;
+
+// This is a fancy one: it uses an external iterator established
+// outside the loop, breaks, then _picks back up_ and continues
+// iterating with it.
+
+pub fn main() {
+ let mut h = HashMap::new();
+ let kvs = [(1, 10), (2, 20), (3, 30)];
+ for &(k,v) in &kvs {
+ h.insert(k,v);
+ }
+ let mut x = 0;
+ let mut y = 0;
+
+ let mut i = h.iter();
+
+ for (&k,&v) in i.by_ref() {
+ x += k;
+ y += v;
+ break;
+ }
+
+ for (&k,&v) in i {
+ x += k;
+ y += v;
+ }
+
+ assert_eq!(x, 6);
+ assert_eq!(y, 60);
+}
diff --git a/src/test/ui/for-loop-while/foreach-external-iterators-hashmap.rs b/src/test/ui/for-loop-while/foreach-external-iterators-hashmap.rs
new file mode 100644
index 000000000..9f2ca05cd
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-external-iterators-hashmap.rs
@@ -0,0 +1,19 @@
+// run-pass
+
+use std::collections::HashMap;
+
+pub fn main() {
+ let mut h = HashMap::new();
+ let kvs = [(1, 10), (2, 20), (3, 30)];
+ for &(k,v) in &kvs {
+ h.insert(k,v);
+ }
+ let mut x = 0;
+ let mut y = 0;
+ for (&k,&v) in &h {
+ x += k;
+ y += v;
+ }
+ assert_eq!(x, 6);
+ assert_eq!(y, 60);
+}
diff --git a/src/test/ui/for-loop-while/foreach-external-iterators-loop.rs b/src/test/ui/for-loop-while/foreach-external-iterators-loop.rs
new file mode 100644
index 000000000..78af195bc
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-external-iterators-loop.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+pub fn main() {
+ let x = [1; 100];
+ let mut y = 0;
+ for (n,i) in x.iter().enumerate() {
+ if n < 10 {
+ continue;
+ }
+ y += *i;
+ }
+ assert_eq!(y, 90);
+}
diff --git a/src/test/ui/for-loop-while/foreach-external-iterators-nested.rs b/src/test/ui/for-loop-while/foreach-external-iterators-nested.rs
new file mode 100644
index 000000000..8a95f160a
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-external-iterators-nested.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+pub fn main() {
+ let x = [1; 100];
+ let y = [2; 100];
+ let mut p = 0;
+ let mut q = 0;
+ for i in &x[..] {
+ for j in &y[..] {
+ p += *j;
+ }
+ q += *i + p;
+ }
+ assert_eq!(q, 1010100);
+}
diff --git a/src/test/ui/for-loop-while/foreach-external-iterators.rs b/src/test/ui/for-loop-while/foreach-external-iterators.rs
new file mode 100644
index 000000000..24ecfe9b6
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-external-iterators.rs
@@ -0,0 +1,10 @@
+// run-pass
+
+pub fn main() {
+ let x = [1; 100];
+ let mut y = 0;
+ for i in &x[..] {
+ y += *i
+ }
+ assert_eq!(y, 100);
+}
diff --git a/src/test/ui/for-loop-while/foreach-nested.rs b/src/test/ui/for-loop-while/foreach-nested.rs
new file mode 100644
index 000000000..bb6edbc07
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-nested.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+
+fn two<F>(mut it: F) where F: FnMut(isize) { it(0); it(1); }
+
+pub fn main() {
+ let mut a: Vec<isize> = vec![-1, -1, -1, -1];
+ let mut p: isize = 0;
+ two(|i| {
+ two(|j| { a[p as usize] = 10 * i + j; p += 1; })
+ });
+ assert_eq!(a[0], 0);
+ assert_eq!(a[1], 1);
+ assert_eq!(a[2], 10);
+ assert_eq!(a[3], 11);
+}
diff --git a/src/test/ui/for-loop-while/foreach-put-structured.rs b/src/test/ui/for-loop-while/foreach-put-structured.rs
new file mode 100644
index 000000000..3a47fcf34
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-put-structured.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+
+fn pairs<F>(mut it: F) where F: FnMut((isize, isize)) {
+ let mut i: isize = 0;
+ let mut j: isize = 0;
+ while i < 10 { it((i, j)); i += 1; j += i; }
+}
+
+pub fn main() {
+ let mut i: isize = 10;
+ let mut j: isize = 0;
+ pairs(|p| {
+ let (_0, _1) = p;
+ println!("{}", _0);
+ println!("{}", _1);
+ assert_eq!(_0 + 10, i);
+ i += 1;
+ j = _1;
+ });
+ assert_eq!(j, 45);
+}
diff --git a/src/test/ui/for-loop-while/foreach-simple-outer-slot.rs b/src/test/ui/for-loop-while/foreach-simple-outer-slot.rs
new file mode 100644
index 000000000..a8d42a789
--- /dev/null
+++ b/src/test/ui/for-loop-while/foreach-simple-outer-slot.rs
@@ -0,0 +1,16 @@
+// run-pass
+
+
+
+pub fn main() {
+ let mut sum: isize = 0;
+ first_ten(|i| { println!("main"); println!("{}", i); sum = sum + i; });
+ println!("sum");
+ println!("{}", sum);
+ assert_eq!(sum, 45);
+}
+
+fn first_ten<F>(mut it: F) where F: FnMut(isize) {
+ let mut i: isize = 0;
+ while i < 10 { println!("first_ten"); it(i); i = i + 1; }
+}
diff --git a/src/test/ui/for-loop-while/issue-2216.rs b/src/test/ui/for-loop-while/issue-2216.rs
new file mode 100644
index 000000000..ad5410742
--- /dev/null
+++ b/src/test/ui/for-loop-while/issue-2216.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![allow(unreachable_code)]
+pub fn main() {
+ let mut x = 0;
+
+ 'foo: loop {
+ 'bar: loop {
+ loop {
+ if 1 == 2 {
+ break 'foo;
+ }
+ else {
+ break 'bar;
+ }
+ }
+ continue 'foo;
+ }
+ x = 42;
+ break;
+ }
+
+ println!("{}", x);
+ assert_eq!(x, 42);
+}
diff --git a/src/test/ui/for-loop-while/issue-51345.rs b/src/test/ui/for-loop-while/issue-51345.rs
new file mode 100644
index 000000000..15571e8bf
--- /dev/null
+++ b/src/test/ui/for-loop-while/issue-51345.rs
@@ -0,0 +1,8 @@
+// run-pass
+#![allow(unreachable_code)]
+
+fn main() {
+ let mut v = Vec::new();
+
+ loop { v.push(break) }
+}
diff --git a/src/test/ui/for-loop-while/issue-69841.rs b/src/test/ui/for-loop-while/issue-69841.rs
new file mode 100644
index 000000000..1aca16ca8
--- /dev/null
+++ b/src/test/ui/for-loop-while/issue-69841.rs
@@ -0,0 +1,31 @@
+// This is a regression test for issue rust-lang/rust#69841, which exposed an
+// LLVM bug which needed a fix to be backported.
+
+// run-pass
+// no-system-llvm
+
+fn main() {
+ let buffer = [49u8, 10];
+ let mut a : u64 = 0;
+ 'read: loop {
+ for c in &buffer {
+ match c {
+ 48..=57 => {
+ a*= 10;
+ a+= *c as u64 - 48;
+ }
+ 10 => {
+ break 'read;
+ }
+ _ => {
+ unsafe { std::hint::unreachable_unchecked() };
+ }
+ }
+ }
+ }
+ if a == 1 {
+ println!("What did you expect?");
+ } else {
+ panic!("this should be unreachable.");
+ }
+}
diff --git a/src/test/ui/for-loop-while/label_break_value.rs b/src/test/ui/for-loop-while/label_break_value.rs
new file mode 100644
index 000000000..ca9d71a7a
--- /dev/null
+++ b/src/test/ui/for-loop-while/label_break_value.rs
@@ -0,0 +1,167 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+#![feature(label_break_value)]
+
+// Test control flow to follow label_break_value semantics
+fn label_break(a: bool, b: bool) -> u32 {
+ let mut v = 0;
+ 'b: {
+ v = 1;
+ if a {
+ break 'b;
+ }
+ v = 2;
+ if b {
+ break 'b;
+ }
+ v = 3;
+ }
+ return v;
+}
+
+// Test that values can be returned
+fn break_value(a: bool, b: bool) -> u32 {
+ let result = 'block: {
+ if a { break 'block 1; }
+ if b { break 'block 2; }
+ 3
+ };
+ result
+}
+
+// Test nesting of labeled blocks
+// here we only check that it compiles
+fn label_break_nested() {
+ 'b: {
+ println!("hi");
+ if false {
+ break 'b;
+ }
+ 'c: {
+ if false {
+ break 'b;
+ }
+ break 'c;
+ }
+ println!("hello");
+ if true {
+ break 'b;
+ }
+ }
+}
+
+// Tests for mixing labeled blocks with loop constructs
+// This function should be the identity function
+fn label_break_mixed(v: u32) -> u32 {
+ let mut r = 0;
+ 'b: {
+ // Unlabeled break still works
+ // (only crossing boundaries is an error)
+ loop {
+ break;
+ }
+ if v == 0 {
+ break 'b;
+ }
+ // Labeled breaking an inner loop still works
+ 'c: loop {
+ if r == 1 {
+ break 'c;
+ }
+ r += 1;
+ }
+ assert_eq!(r, 1);
+ if v == 1 {
+ break 'b;
+ }
+ // Labeled breaking an outer loop still works
+ 'd: loop {
+ {
+ if v == r {
+ break 'b;
+ }
+ if r == 5 {
+ break 'd;
+ }
+ r += 1;
+ }
+ }
+ assert_eq!(r, 5);
+ assert!(v > r);
+ // Here we test return from inside a labeled block
+ return v;
+ }
+ r
+}
+
+fn label_break_match(c: u8, xe: u8, ye: i8) {
+ let mut x = 0;
+ let y = 'a: {
+ match c {
+ 0 => break 'a 0,
+ v if { if v % 2 == 0 { break 'a 1; }; v % 3 == 0 } => { x += 1; },
+ v if { 'b: { break 'b v == 5; } } => { x = 41; },
+ _ => 'b: {
+ break 'b ();
+ },
+ }
+ x += 1;
+ -1
+ };
+
+ assert_eq!(x, xe);
+ assert_eq!(y, ye);
+}
+
+#[allow(unused_labels)]
+fn label_break_macro() {
+ macro_rules! mac1 {
+ ($target:lifetime, $val:expr) => {
+ break $target $val;
+ };
+ }
+ let x: u8 = 'a: {
+ 'b: {
+ mac1!('b, 1);
+ };
+ 0
+ };
+ assert_eq!(x, 0);
+ let x: u8 = 'a: {
+ 'b: {
+ if true {
+ mac1!('a, 1);
+ }
+ };
+ 0
+ };
+ assert_eq!(x, 1);
+}
+
+pub fn main() {
+ assert_eq!(label_break(true, false), 1);
+ assert_eq!(label_break(false, true), 2);
+ assert_eq!(label_break(false, false), 3);
+
+ assert_eq!(break_value(true, false), 1);
+ assert_eq!(break_value(false, true), 2);
+ assert_eq!(break_value(false, false), 3);
+
+ assert_eq!(label_break_mixed(0), 0);
+ assert_eq!(label_break_mixed(1), 1);
+ assert_eq!(label_break_mixed(2), 2);
+ assert_eq!(label_break_mixed(3), 3);
+ assert_eq!(label_break_mixed(4), 4);
+ assert_eq!(label_break_mixed(5), 5);
+ assert_eq!(label_break_mixed(6), 6);
+
+ label_break_match(0, 0, 0);
+ label_break_match(1, 1, -1);
+ label_break_match(2, 0, 1);
+ label_break_match(3, 2, -1);
+ label_break_match(5, 42, -1);
+ label_break_match(7, 1, -1);
+
+ label_break_macro();
+}
diff --git a/src/test/ui/for-loop-while/label_break_value_invalid.rs b/src/test/ui/for-loop-while/label_break_value_invalid.rs
new file mode 100644
index 000000000..149bf17b8
--- /dev/null
+++ b/src/test/ui/for-loop-while/label_break_value_invalid.rs
@@ -0,0 +1,36 @@
+#![crate_type = "lib"]
+#![feature(label_break_value)]
+
+fn lbv_macro_test_hygiene_respected() {
+ macro_rules! mac2 {
+ ($val:expr) => {
+ break 'a $val; //~ ERROR undeclared label `'a` [E0426]
+ };
+ }
+ let x: u8 = 'a: {
+ 'b: {
+ if true {
+ mac2!(2);
+ }
+ };
+ 0
+ };
+ assert_eq!(x, 2);
+
+ macro_rules! mac3 {
+ ($val:expr) => {
+ 'a: {
+ $val
+ }
+ };
+ }
+ let x: u8 = mac3!('b: {
+ if true {
+ break 'a 3; //~ ERROR undeclared label `'a` [E0426]
+ }
+ 0
+ });
+ assert_eq!(x, 3);
+ let x: u8 = mac3!(break 'a 4); //~ ERROR undeclared label `'a` [E0426]
+ assert_eq!(x, 4);
+}
diff --git a/src/test/ui/for-loop-while/label_break_value_invalid.stderr b/src/test/ui/for-loop-while/label_break_value_invalid.stderr
new file mode 100644
index 000000000..7182b8f59
--- /dev/null
+++ b/src/test/ui/for-loop-while/label_break_value_invalid.stderr
@@ -0,0 +1,32 @@
+error[E0426]: use of undeclared label `'a`
+ --> $DIR/label_break_value_invalid.rs:7:19
+ |
+LL | break 'a $val;
+ | ^^ undeclared label `'a`
+...
+LL | mac2!(2);
+ | -------- in this macro invocation
+ |
+ = note: this error originates in the macro `mac2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0426]: use of undeclared label `'a`
+ --> $DIR/label_break_value_invalid.rs:29:19
+ |
+LL | let x: u8 = mac3!('b: {
+ | -- a label with a similar name is reachable
+LL | if true {
+LL | break 'a 3;
+ | ^^
+ | |
+ | undeclared label `'a`
+ | help: try using similarly named label: `'b`
+
+error[E0426]: use of undeclared label `'a`
+ --> $DIR/label_break_value_invalid.rs:34:29
+ |
+LL | let x: u8 = mac3!(break 'a 4);
+ | ^^ undeclared label `'a`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0426`.
diff --git a/src/test/ui/for-loop-while/labeled-break.rs b/src/test/ui/for-loop-while/labeled-break.rs
new file mode 100644
index 000000000..4dacc5757
--- /dev/null
+++ b/src/test/ui/for-loop-while/labeled-break.rs
@@ -0,0 +1,22 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+pub fn main() {
+ 'foo: loop {
+ loop {
+ break 'foo;
+ }
+ }
+
+ 'bar: for _ in 0..100 {
+ loop {
+ break 'bar;
+ }
+ }
+
+ 'foobar: while 1 + 1 == 2 {
+ loop {
+ break 'foobar;
+ }
+ }
+}
diff --git a/src/test/ui/for-loop-while/linear-for-loop.rs b/src/test/ui/for-loop-while/linear-for-loop.rs
new file mode 100644
index 000000000..3c573db1d
--- /dev/null
+++ b/src/test/ui/for-loop-while/linear-for-loop.rs
@@ -0,0 +1,23 @@
+// run-pass
+pub fn main() {
+ let x = vec![1, 2, 3];
+ let mut y = 0;
+ for i in &x { println!("{}", *i); y += *i; }
+ println!("{}", y);
+ assert_eq!(y, 6);
+ let s = "hello there".to_string();
+ let mut i: isize = 0;
+ for c in s.bytes() {
+ if i == 0 { assert_eq!(c, 'h' as u8); }
+ if i == 1 { assert_eq!(c, 'e' as u8); }
+ if i == 2 { assert_eq!(c, 'l' as u8); }
+ if i == 3 { assert_eq!(c, 'l' as u8); }
+ if i == 4 { assert_eq!(c, 'o' as u8); }
+ // ...
+
+ i += 1;
+ println!("{}", i);
+ println!("{}", c);
+ }
+ assert_eq!(i, 11);
+}
diff --git a/src/test/ui/for-loop-while/liveness-assign-imm-local-after-loop.rs b/src/test/ui/for-loop-while/liveness-assign-imm-local-after-loop.rs
new file mode 100644
index 000000000..11b697165
--- /dev/null
+++ b/src/test/ui/for-loop-while/liveness-assign-imm-local-after-loop.rs
@@ -0,0 +1,18 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_assignments)]
+// pretty-expanded FIXME #23616
+
+#![allow(unreachable_code)]
+#![allow(unused_variables)]
+
+fn test(_cond: bool) {
+ let v: isize;
+ v = 1;
+ loop { } // loop never terminates, so no error is reported
+ v = 2;
+}
+
+pub fn main() {
+ // note: don't call test()... :)
+}
diff --git a/src/test/ui/for-loop-while/liveness-loop-break.rs b/src/test/ui/for-loop-while/liveness-loop-break.rs
new file mode 100644
index 000000000..60a63bccb
--- /dev/null
+++ b/src/test/ui/for-loop-while/liveness-loop-break.rs
@@ -0,0 +1,13 @@
+// run-pass
+fn test() {
+ let v;
+ loop {
+ v = 3;
+ break;
+ }
+ println!("{}", v);
+}
+
+pub fn main() {
+ test();
+}
diff --git a/src/test/ui/for-loop-while/liveness-move-in-loop.rs b/src/test/ui/for-loop-while/liveness-move-in-loop.rs
new file mode 100644
index 000000000..ce73d6335
--- /dev/null
+++ b/src/test/ui/for-loop-while/liveness-move-in-loop.rs
@@ -0,0 +1,20 @@
+// run-pass
+#![allow(dead_code)]
+
+// pretty-expanded FIXME #23616
+
+fn take(x: isize) -> isize {x}
+
+fn the_loop() {
+ let mut list = Vec::new();
+ loop {
+ let x = 5;
+ if x > 3 {
+ list.push(take(x));
+ } else {
+ break;
+ }
+ }
+}
+
+pub fn main() {}
diff --git a/src/test/ui/for-loop-while/long-while.rs b/src/test/ui/for-loop-while/long-while.rs
new file mode 100644
index 000000000..529cca7b7
--- /dev/null
+++ b/src/test/ui/for-loop-while/long-while.rs
@@ -0,0 +1,12 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![allow(unused_variables)]
+
+pub fn main() {
+ let mut i: isize = 0;
+ while i < 1000000 {
+ i += 1;
+ let x = 3;
+ }
+}
diff --git a/src/test/ui/for-loop-while/loop-break-cont-1.rs b/src/test/ui/for-loop-while/loop-break-cont-1.rs
new file mode 100644
index 000000000..f207746f0
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-break-cont-1.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+pub fn main() {
+ let _i = 0_usize;
+ loop {
+ break;
+ }
+ assert!(true);
+}
diff --git a/src/test/ui/for-loop-while/loop-break-cont.rs b/src/test/ui/for-loop-while/loop-break-cont.rs
new file mode 100644
index 000000000..92d5a32c6
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-break-cont.rs
@@ -0,0 +1,39 @@
+// run-pass
+pub fn main() {
+ let mut i = 0_usize;
+ loop {
+ println!("a");
+ i += 1_usize;
+ if i == 10_usize {
+ break;
+ }
+ }
+ assert_eq!(i, 10_usize);
+ let mut is_even = false;
+ loop {
+ if i == 21_usize {
+ break;
+ }
+ println!("b");
+ is_even = false;
+ i += 1_usize;
+ if i % 2_usize != 0_usize {
+ continue;
+ }
+ is_even = true;
+ }
+ assert!(!is_even);
+ loop {
+ println!("c");
+ if i == 22_usize {
+ break;
+ }
+ is_even = false;
+ i += 1_usize;
+ if i % 2_usize != 0_usize {
+ continue;
+ }
+ is_even = true;
+ }
+ assert!(is_even);
+}
diff --git a/src/test/ui/for-loop-while/loop-break-value.rs b/src/test/ui/for-loop-while/loop-break-value.rs
new file mode 100644
index 000000000..d7209fc4d
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-break-value.rs
@@ -0,0 +1,139 @@
+// run-pass
+
+#![allow(unreachable_code)]
+#![feature(never_type)]
+
+#[allow(unused)]
+fn never_returns() {
+ loop {
+ break loop {};
+ }
+}
+
+pub fn main() {
+ let value = 'outer: loop {
+ if 1 == 1 {
+ break 13;
+ } else {
+ let _never: ! = loop {
+ break loop {
+ break 'outer panic!();
+ }
+ };
+ }
+ };
+ assert_eq!(value, 13);
+
+ let x = [1, 3u32, 5];
+ let y = [17];
+ let z = [];
+ let coerced: &[_] = loop {
+ match 2 {
+ 1 => break &x,
+ 2 => break &y,
+ 3 => break &z,
+ _ => (),
+ }
+ };
+ assert_eq!(coerced, &[17u32]);
+
+ let trait_unified = loop {
+ break if true {
+ break Default::default()
+ } else {
+ break [13, 14]
+ };
+ };
+ assert_eq!(trait_unified, [0, 0]);
+
+ let trait_unified_2 = loop {
+ if false {
+ break [String::from("Hello")]
+ } else {
+ break Default::default()
+ };
+ };
+ assert_eq!(trait_unified_2, [""]);
+
+ let trait_unified_3 = loop {
+ break if false {
+ break [String::from("Hello")]
+ } else {
+ ["Yes".into()]
+ };
+ };
+ assert_eq!(trait_unified_3, ["Yes"]);
+
+ let regular_break = loop {
+ if true {
+ break;
+ } else {
+ break break Default::default();
+ }
+ };
+ assert_eq!(regular_break, ());
+
+ let regular_break_2 = loop {
+ if true {
+ break Default::default();
+ } else {
+ break;
+ }
+ };
+ assert_eq!(regular_break_2, ());
+
+ let regular_break_3 = loop {
+ break if true {
+ Default::default()
+ } else {
+ break;
+ }
+ };
+ assert_eq!(regular_break_3, ());
+
+ let regular_break_4 = loop {
+ break ();
+ break;
+ };
+ assert_eq!(regular_break_4, ());
+
+ let regular_break_5 = loop {
+ break;
+ break ();
+ };
+ assert_eq!(regular_break_5, ());
+
+ let nested_break_value = 'outer2: loop {
+ let _a: u32 = 'inner: loop {
+ if true {
+ break 'outer2 "hello";
+ } else {
+ break 'inner 17;
+ }
+ };
+ panic!();
+ };
+ assert_eq!(nested_break_value, "hello");
+
+ let break_from_while_cond = loop {
+ 'inner_loop: while break 'inner_loop {
+ panic!();
+ }
+ break 123;
+ };
+ assert_eq!(break_from_while_cond, 123);
+
+ let break_from_while_to_outer = 'outer_loop: loop {
+ while break 'outer_loop 567 {
+ panic!("from_inner");
+ }
+ panic!("from outer");
+ };
+ assert_eq!(break_from_while_to_outer, 567);
+
+ let rust = true;
+ let value = loop {
+ break rust;
+ };
+ assert!(value);
+}
diff --git a/src/test/ui/for-loop-while/loop-diverges.rs b/src/test/ui/for-loop-while/loop-diverges.rs
new file mode 100644
index 000000000..f657bf9e0
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-diverges.rs
@@ -0,0 +1,14 @@
+// run-pass
+#![allow(unused_parens)]
+// pretty-expanded FIXME #23616
+
+/* Make sure a loop{} can be the tailexpr in the body
+of a diverging function */
+
+fn forever() -> ! {
+ loop{}
+}
+
+pub fn main() {
+ if (1 == 2) { forever(); }
+}
diff --git a/src/test/ui/for-loop-while/loop-label-shadowing.rs b/src/test/ui/for-loop-while/loop-label-shadowing.rs
new file mode 100644
index 000000000..9bedde67b
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-label-shadowing.rs
@@ -0,0 +1,12 @@
+// run-pass
+// Issue #12512.
+
+// pretty-expanded FIXME #23616
+
+fn main() {
+ let mut foo = Vec::new();
+ #[allow(unused_labels)]
+ 'foo: for i in &[1, 2, 3] {
+ foo.push(*i);
+ }
+}
diff --git a/src/test/ui/for-loop-while/loop-labeled-break-value.rs b/src/test/ui/for-loop-while/loop-labeled-break-value.rs
new file mode 100644
index 000000000..cc8f82698
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-labeled-break-value.rs
@@ -0,0 +1,11 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+fn main() {
+ 'outer: loop {
+ let _: i32 = loop { break 'outer };
+ }
+ 'outer2: loop {
+ let _: i32 = loop { loop { break 'outer2 } };
+ }
+}
diff --git a/src/test/ui/for-loop-while/loop-no-reinit-needed-post-bot.rs b/src/test/ui/for-loop-while/loop-no-reinit-needed-post-bot.rs
new file mode 100644
index 000000000..1b5db2012
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-no-reinit-needed-post-bot.rs
@@ -0,0 +1,34 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+struct S;
+// Ensure S is moved, not copied, on assignment.
+impl Drop for S { fn drop(&mut self) { } }
+
+// user-defined function "returning" bottom (i.e., no return at all).
+fn my_panic() -> ! { loop {} }
+
+pub fn step(f: bool) {
+ let mut g = S;
+ let mut i = 0;
+ loop
+ {
+ if i > 10 { break; } else { i += 1; }
+
+ let _g = g;
+
+ if f {
+ // re-initialize g, but only before restarting loop.
+ g = S;
+ continue;
+ }
+
+ my_panic();
+
+ // we never get here, so we do not need to re-initialize g.
+ }
+}
+
+pub fn main() {
+ step(true);
+}
diff --git a/src/test/ui/for-loop-while/loop-scope.rs b/src/test/ui/for-loop-while/loop-scope.rs
new file mode 100644
index 000000000..73324a3e1
--- /dev/null
+++ b/src/test/ui/for-loop-while/loop-scope.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+pub fn main() {
+ let x = vec![10, 20, 30];
+ let mut sum = 0;
+ for x in &x { sum += *x; }
+ assert_eq!(sum, 60);
+}
diff --git a/src/test/ui/for-loop-while/while-cont.rs b/src/test/ui/for-loop-while/while-cont.rs
new file mode 100644
index 000000000..a864e8ef7
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-cont.rs
@@ -0,0 +1,11 @@
+// run-pass
+// Issue #825: Should recheck the loop condition after continuing
+pub fn main() {
+ let mut i = 1;
+ while i > 0 {
+ assert!((i > 0));
+ println!("{}", i);
+ i -= 1;
+ continue;
+ }
+}
diff --git a/src/test/ui/for-loop-while/while-flow-graph.rs b/src/test/ui/for-loop-while/while-flow-graph.rs
new file mode 100644
index 000000000..1748964a7
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-flow-graph.rs
@@ -0,0 +1,6 @@
+// run-pass
+
+
+// pretty-expanded FIXME #23616
+
+pub fn main() { let x: isize = 10; while x == 10 && x == 11 { let _y = 0xf00_usize; } }
diff --git a/src/test/ui/for-loop-while/while-label.rs b/src/test/ui/for-loop-while/while-label.rs
new file mode 100644
index 000000000..5abc41daf
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-label.rs
@@ -0,0 +1,15 @@
+// run-pass
+#![allow(unreachable_code)]
+
+
+pub fn main() {
+ let mut i = 100;
+ 'w: while 1 + 1 == 2 {
+ i -= 1;
+ if i == 95 {
+ break 'w;
+ panic!("Should have broken out of loop");
+ }
+ }
+ assert_eq!(i, 95);
+}
diff --git a/src/test/ui/for-loop-while/while-let-2.rs b/src/test/ui/for-loop-while/while-let-2.rs
new file mode 100644
index 000000000..b9a49b47c
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-let-2.rs
@@ -0,0 +1,31 @@
+// run-pass
+
+#[allow(dead_code)]
+fn macros() {
+ macro_rules! foo{
+ ($p:pat, $e:expr, $b:block) => {{
+ while let $p = $e $b
+ //~^ WARN irrefutable `while let`
+ //~| WARN irrefutable `while let`
+ }}
+ }
+ macro_rules! bar{
+ ($p:pat, $e:expr, $b:block) => {{
+ foo!($p, $e, $b)
+ }}
+ }
+
+ foo!(_a, 1, {
+ println!("irrefutable pattern");
+ });
+ bar!(_a, 1, {
+ println!("irrefutable pattern");
+ });
+}
+
+pub fn main() {
+ while let _a = 1 { //~ WARN irrefutable `while let`
+ println!("irrefutable pattern");
+ break;
+ }
+}
diff --git a/src/test/ui/for-loop-while/while-let-2.stderr b/src/test/ui/for-loop-while/while-let-2.stderr
new file mode 100644
index 000000000..2d23a6373
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-let-2.stderr
@@ -0,0 +1,42 @@
+warning: irrefutable `while let` pattern
+ --> $DIR/while-let-2.rs:7:19
+ |
+LL | while let $p = $e $b
+ | ^^^
+...
+LL | / foo!(_a, 1, {
+LL | | println!("irrefutable pattern");
+LL | | });
+ | |______- in this macro invocation
+ |
+ = note: `#[warn(irrefutable_let_patterns)]` on by default
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
+ = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: irrefutable `while let` pattern
+ --> $DIR/while-let-2.rs:7:19
+ |
+LL | while let $p = $e $b
+ | ^^^
+...
+LL | / bar!(_a, 1, {
+LL | | println!("irrefutable pattern");
+LL | | });
+ | |______- in this macro invocation
+ |
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
+ = note: this warning originates in the macro `foo` which comes from the expansion of the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: irrefutable `while let` pattern
+ --> $DIR/while-let-2.rs:27:11
+ |
+LL | while let _a = 1 {
+ | ^^^^^^^^^^
+ |
+ = note: this pattern will always match, so the loop will never exit
+ = help: consider instead using a `loop { ... }` with a `let` inside it
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/for-loop-while/while-let.rs b/src/test/ui/for-loop-while/while-let.rs
new file mode 100644
index 000000000..b9d70ff0b
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-let.rs
@@ -0,0 +1,46 @@
+// run-pass
+
+use std::collections::BinaryHeap;
+
+fn make_pq() -> BinaryHeap<isize> {
+ BinaryHeap::from(vec![1,2,3])
+}
+
+pub fn main() {
+ let mut pq = make_pq();
+ let mut sum = 0;
+ while let Some(x) = pq.pop() {
+ sum += x;
+ }
+ assert_eq!(sum, 6);
+
+ pq = make_pq();
+ sum = 0;
+ 'a: while let Some(x) = pq.pop() {
+ sum += x;
+ if x == 2 {
+ break 'a;
+ }
+ }
+ assert_eq!(sum, 5);
+
+ pq = make_pq();
+ sum = 0;
+ 'a2: while let Some(x) = pq.pop() {
+ if x == 3 {
+ continue 'a2;
+ }
+ sum += x;
+ }
+ assert_eq!(sum, 3);
+
+ let mut pq1 = make_pq();
+ sum = 0;
+ while let Some(x) = pq1.pop() {
+ let mut pq2 = make_pq();
+ while let Some(y) = pq2.pop() {
+ sum += x * y;
+ }
+ }
+ assert_eq!(sum, 6 + 12 + 18);
+}
diff --git a/src/test/ui/for-loop-while/while-loop-constraints-2.rs b/src/test/ui/for-loop-while/while-loop-constraints-2.rs
new file mode 100644
index 000000000..3c5cdf06c
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-loop-constraints-2.rs
@@ -0,0 +1,15 @@
+// run-pass
+#![allow(unused_assignments)]
+#![allow(unused_variables)]
+
+pub fn main() {
+ let mut y: isize = 42;
+ let mut z: isize = 42;
+ let mut x: isize;
+ while z < 50 {
+ z += 1;
+ while false { x = y; y = z; }
+ println!("{}", y);
+ }
+ assert!((y == 42 && z == 50));
+}
diff --git a/src/test/ui/for-loop-while/while-prelude-drop.rs b/src/test/ui/for-loop-while/while-prelude-drop.rs
new file mode 100644
index 000000000..196b9daf6
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-prelude-drop.rs
@@ -0,0 +1,24 @@
+// run-pass
+#![allow(non_camel_case_types)]
+
+use std::string::String;
+
+#[derive(PartialEq)]
+enum t { a, b(String), }
+
+fn make(i: isize) -> t {
+ if i > 10 { return t::a; }
+ let mut s = String::from("hello");
+ // Ensure s is non-const.
+
+ s.push_str("there");
+ return t::b(s);
+}
+
+pub fn main() {
+ let mut i = 0;
+
+
+ // The auto slot for the result of make(i) should not leak.
+ while make(i) != t::a { i += 1; }
+}
diff --git a/src/test/ui/for-loop-while/while-with-break.rs b/src/test/ui/for-loop-while/while-with-break.rs
new file mode 100644
index 000000000..a9d52dda5
--- /dev/null
+++ b/src/test/ui/for-loop-while/while-with-break.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+pub fn main() {
+ let mut i: isize = 90;
+ while i < 100 {
+ println!("{}", i);
+ i = i + 1;
+ if i == 95 {
+ let _v: Vec<isize> =
+ vec![1, 2, 3, 4, 5]; // we check that it is freed by break
+
+ println!("breaking");
+ break;
+ }
+ }
+ assert_eq!(i, 95);
+}
diff --git a/src/test/ui/for-loop-while/while.rs b/src/test/ui/for-loop-while/while.rs
new file mode 100644
index 000000000..90f718a34
--- /dev/null
+++ b/src/test/ui/for-loop-while/while.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+
+pub fn main() {
+ let mut x: isize = 10;
+ let mut y: isize = 0;
+ while y < x { println!("{}", y); println!("hello"); y = y + 1; }
+ while x > 0 {
+ println!("goodbye");
+ x = x - 1;
+ println!("{}", x);
+ }
+}