diff options
Diffstat (limited to 'tests/ui/for-loop-while')
57 files changed, 1434 insertions, 0 deletions
diff --git a/tests/ui/for-loop-while/auto-loop.rs b/tests/ui/for-loop-while/auto-loop.rs new file mode 100644 index 000000000..f02ac43c7 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/break-outside-loop.rs b/tests/ui/for-loop-while/break-outside-loop.rs new file mode 100644 index 000000000..26769b30d --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/break-outside-loop.stderr b/tests/ui/for-loop-while/break-outside-loop.stderr new file mode 100644 index 000000000..9092f34df --- /dev/null +++ b/tests/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 or labeled block + --> $DIR/break-outside-loop.rs:10:15 + | +LL | let pth = break; + | ^^^^^ cannot `break` outside of a loop or labeled block + +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 or labeled block + --> $DIR/break-outside-loop.rs:24:25 + | +LL | let unconstrained = break; + | ^^^^^ cannot `break` outside of a loop or labeled block + +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/tests/ui/for-loop-while/break-value.rs b/tests/ui/for-loop-while/break-value.rs new file mode 100644 index 000000000..9fc49fa81 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/break-while-condition.rs b/tests/ui/for-loop-while/break-while-condition.rs new file mode 100644 index 000000000..6064e6ab0 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/break-while-condition.stderr b/tests/ui/for-loop-while/break-while-condition.stderr new file mode 100644 index 000000000..e79f6a75f --- /dev/null +++ b/tests/ui/for-loop-while/break-while-condition.stderr @@ -0,0 +1,45 @@ +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 `()` +note: the function expects a value to always be returned, but loops might run zero times + --> $DIR/break-while-condition.rs:24:13 + | +LL | while false { + | ^^^^^^^^^^^ this might have zero elements to iterate on +LL | return + | ------ if the loop doesn't execute, this value would never get returned + = help: return a value for the case when the loop has zero elements to iterate on, or consider changing the return type to account for that possibility + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/for-loop-while/break.rs b/tests/ui/for-loop-while/break.rs new file mode 100644 index 000000000..427b1b7a0 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs b/tests/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs new file mode 100644 index 000000000..afc77355a --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-destruct.rs b/tests/ui/for-loop-while/for-destruct.rs new file mode 100644 index 000000000..7ca8d4ded --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-goofiness.rs b/tests/ui/for-loop-while/for-loop-goofiness.rs new file mode 100644 index 000000000..872ab168b --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-has-unit-body.rs b/tests/ui/for-loop-while/for-loop-has-unit-body.rs new file mode 100644 index 000000000..eba385461 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-into-iterator.rs b/tests/ui/for-loop-while/for-loop-into-iterator.rs new file mode 100644 index 000000000..199d4ddb2 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-lifetime-of-unbound-values.rs b/tests/ui/for-loop-while/for-loop-lifetime-of-unbound-values.rs new file mode 100644 index 000000000..6a38764a1 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-macro.rs b/tests/ui/for-loop-while/for-loop-macro.rs new file mode 100644 index 000000000..5abccd2a1 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-mut-ref-element.rs b/tests/ui/for-loop-while/for-loop-mut-ref-element.rs new file mode 100644 index 000000000..a3d82ace9 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-no-std.rs b/tests/ui/for-loop-while/for-loop-no-std.rs new file mode 100644 index 000000000..65a33c5f1 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-panic.rs b/tests/ui/for-loop-while/for-loop-panic.rs new file mode 100644 index 000000000..ac607d6d7 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/for-loop-unconstrained-element-type-i32-fallback.rs b/tests/ui/for-loop-while/for-loop-unconstrained-element-type-i32-fallback.rs new file mode 100644 index 000000000..a1e9b1ed8 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-external-iterators-break.rs b/tests/ui/for-loop-while/foreach-external-iterators-break.rs new file mode 100644 index 000000000..7de6a4f8a --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-external-iterators-hashmap-break-restart.rs b/tests/ui/for-loop-while/foreach-external-iterators-hashmap-break-restart.rs new file mode 100644 index 000000000..5d690807e --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-external-iterators-hashmap.rs b/tests/ui/for-loop-while/foreach-external-iterators-hashmap.rs new file mode 100644 index 000000000..9f2ca05cd --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-external-iterators-loop.rs b/tests/ui/for-loop-while/foreach-external-iterators-loop.rs new file mode 100644 index 000000000..78af195bc --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-external-iterators-nested.rs b/tests/ui/for-loop-while/foreach-external-iterators-nested.rs new file mode 100644 index 000000000..8a95f160a --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-external-iterators.rs b/tests/ui/for-loop-while/foreach-external-iterators.rs new file mode 100644 index 000000000..24ecfe9b6 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-nested.rs b/tests/ui/for-loop-while/foreach-nested.rs new file mode 100644 index 000000000..bb6edbc07 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-put-structured.rs b/tests/ui/for-loop-while/foreach-put-structured.rs new file mode 100644 index 000000000..3a47fcf34 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/foreach-simple-outer-slot.rs b/tests/ui/for-loop-while/foreach-simple-outer-slot.rs new file mode 100644 index 000000000..a8d42a789 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/issue-2216.rs b/tests/ui/for-loop-while/issue-2216.rs new file mode 100644 index 000000000..ad5410742 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/issue-51345.rs b/tests/ui/for-loop-while/issue-51345.rs new file mode 100644 index 000000000..15571e8bf --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/issue-69841.rs b/tests/ui/for-loop-while/issue-69841.rs new file mode 100644 index 000000000..1aca16ca8 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/label_break_value.rs b/tests/ui/for-loop-while/label_break_value.rs new file mode 100644 index 000000000..10992c505 --- /dev/null +++ b/tests/ui/for-loop-while/label_break_value.rs @@ -0,0 +1,166 @@ +// run-pass +#![allow(dead_code)] +#![allow(unused_assignments)] + +// 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/tests/ui/for-loop-while/label_break_value_invalid.rs b/tests/ui/for-loop-while/label_break_value_invalid.rs new file mode 100644 index 000000000..fcf2e0f29 --- /dev/null +++ b/tests/ui/for-loop-while/label_break_value_invalid.rs @@ -0,0 +1,35 @@ +#![crate_type = "lib"] + +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/tests/ui/for-loop-while/label_break_value_invalid.stderr b/tests/ui/for-loop-while/label_break_value_invalid.stderr new file mode 100644 index 000000000..f6999c4ab --- /dev/null +++ b/tests/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:6: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:28: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:33: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/tests/ui/for-loop-while/labeled-break.rs b/tests/ui/for-loop-while/labeled-break.rs new file mode 100644 index 000000000..4dacc5757 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/linear-for-loop.rs b/tests/ui/for-loop-while/linear-for-loop.rs new file mode 100644 index 000000000..3c573db1d --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/liveness-assign-imm-local-after-loop.rs b/tests/ui/for-loop-while/liveness-assign-imm-local-after-loop.rs new file mode 100644 index 000000000..11b697165 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/liveness-loop-break.rs b/tests/ui/for-loop-while/liveness-loop-break.rs new file mode 100644 index 000000000..60a63bccb --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/liveness-move-in-loop.rs b/tests/ui/for-loop-while/liveness-move-in-loop.rs new file mode 100644 index 000000000..ce73d6335 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/long-while.rs b/tests/ui/for-loop-while/long-while.rs new file mode 100644 index 000000000..529cca7b7 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-break-cont-1.rs b/tests/ui/for-loop-while/loop-break-cont-1.rs new file mode 100644 index 000000000..f207746f0 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-break-cont.rs b/tests/ui/for-loop-while/loop-break-cont.rs new file mode 100644 index 000000000..92d5a32c6 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-break-value.rs b/tests/ui/for-loop-while/loop-break-value.rs new file mode 100644 index 000000000..d7209fc4d --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-diverges.rs b/tests/ui/for-loop-while/loop-diverges.rs new file mode 100644 index 000000000..f657bf9e0 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-label-shadowing.rs b/tests/ui/for-loop-while/loop-label-shadowing.rs new file mode 100644 index 000000000..9bedde67b --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-labeled-break-value.rs b/tests/ui/for-loop-while/loop-labeled-break-value.rs new file mode 100644 index 000000000..cc8f82698 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-no-reinit-needed-post-bot.rs b/tests/ui/for-loop-while/loop-no-reinit-needed-post-bot.rs new file mode 100644 index 000000000..1b5db2012 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/loop-scope.rs b/tests/ui/for-loop-while/loop-scope.rs new file mode 100644 index 000000000..73324a3e1 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-cont.rs b/tests/ui/for-loop-while/while-cont.rs new file mode 100644 index 000000000..a864e8ef7 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-flow-graph.rs b/tests/ui/for-loop-while/while-flow-graph.rs new file mode 100644 index 000000000..1748964a7 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-label.rs b/tests/ui/for-loop-while/while-label.rs new file mode 100644 index 000000000..5abc41daf --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-let-2.rs b/tests/ui/for-loop-while/while-let-2.rs new file mode 100644 index 000000000..b9a49b47c --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-let-2.stderr b/tests/ui/for-loop-while/while-let-2.stderr new file mode 100644 index 000000000..1b1cf6792 --- /dev/null +++ b/tests/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: this pattern will always match, so the loop will never exit + = help: consider instead using a `loop { ... }` with a `let` inside it + = note: `#[warn(irrefutable_let_patterns)]` on by default + = 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/tests/ui/for-loop-while/while-let.rs b/tests/ui/for-loop-while/while-let.rs new file mode 100644 index 000000000..b9d70ff0b --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-loop-constraints-2.rs b/tests/ui/for-loop-while/while-loop-constraints-2.rs new file mode 100644 index 000000000..3c5cdf06c --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-prelude-drop.rs b/tests/ui/for-loop-while/while-prelude-drop.rs new file mode 100644 index 000000000..196b9daf6 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while-with-break.rs b/tests/ui/for-loop-while/while-with-break.rs new file mode 100644 index 000000000..a9d52dda5 --- /dev/null +++ b/tests/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/tests/ui/for-loop-while/while.rs b/tests/ui/for-loop-while/while.rs new file mode 100644 index 000000000..90f718a34 --- /dev/null +++ b/tests/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); + } +} |