diff options
Diffstat (limited to '')
93 files changed, 1892 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); + } +} diff --git a/src/test/ui/for/for-c-in-str.rs b/src/test/ui/for/for-c-in-str.rs new file mode 100644 index 000000000..86a1c1a34 --- /dev/null +++ b/src/test/ui/for/for-c-in-str.rs @@ -0,0 +1,14 @@ +// E0277 should point exclusively at line 6, not the entire for loop span + +fn main() { + for c in "asdf" { + //~^ ERROR `&str` is not an iterator + //~| NOTE `&str` is not an iterator + //~| HELP the trait `Iterator` is not implemented for `&str` + //~| NOTE required because of the requirements on the impl of `IntoIterator` for `&str` + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE in this expansion of desugaring of `for` loop + //~| NOTE in this expansion of desugaring of `for` loop + println!(); + } +} diff --git a/src/test/ui/for/for-c-in-str.stderr b/src/test/ui/for/for-c-in-str.stderr new file mode 100644 index 000000000..07ddc8ea7 --- /dev/null +++ b/src/test/ui/for/for-c-in-str.stderr @@ -0,0 +1,12 @@ +error[E0277]: `&str` is not an iterator + --> $DIR/for-c-in-str.rs:4:14 + | +LL | for c in "asdf" { + | ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` + | + = help: the trait `Iterator` is not implemented for `&str` + = note: required because of the requirements on the impl of `IntoIterator` for `&str` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/for/for-expn.rs b/src/test/ui/for/for-expn.rs new file mode 100644 index 000000000..b9c4bbeda --- /dev/null +++ b/src/test/ui/for/for-expn.rs @@ -0,0 +1,9 @@ +// Test that an error on a sub-expresson in a for loop has the correct span. + +fn main() { + // Odd formatting to make sure we get the right span. + for t in & + foo //~ ERROR cannot find value `foo` in this scope + { + } +} diff --git a/src/test/ui/for/for-expn.stderr b/src/test/ui/for/for-expn.stderr new file mode 100644 index 000000000..cdb211555 --- /dev/null +++ b/src/test/ui/for/for-expn.stderr @@ -0,0 +1,9 @@ +error[E0425]: cannot find value `foo` in this scope + --> $DIR/for-expn.rs:6:7 + | +LL | foo + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0425`. diff --git a/src/test/ui/for/for-loop-bogosity.rs b/src/test/ui/for/for-loop-bogosity.rs new file mode 100644 index 000000000..9341dea09 --- /dev/null +++ b/src/test/ui/for/for-loop-bogosity.rs @@ -0,0 +1,21 @@ +struct MyStruct { + x: isize, + y: isize, +} + +impl MyStruct { + fn next(&mut self) -> Option<isize> { + Some(self.x) + } +} + +pub fn main() { + let mut bogus = MyStruct { + x: 1, + y: 2, + }; + for x in bogus { + //~^ ERROR `MyStruct` is not an iterator + drop(x); + } +} diff --git a/src/test/ui/for/for-loop-bogosity.stderr b/src/test/ui/for/for-loop-bogosity.stderr new file mode 100644 index 000000000..0bdd75b35 --- /dev/null +++ b/src/test/ui/for/for-loop-bogosity.stderr @@ -0,0 +1,12 @@ +error[E0277]: `MyStruct` is not an iterator + --> $DIR/for-loop-bogosity.rs:17:14 + | +LL | for x in bogus { + | ^^^^^ `MyStruct` is not an iterator + | + = help: the trait `Iterator` is not implemented for `MyStruct` + = note: required because of the requirements on the impl of `IntoIterator` for `MyStruct` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.rs b/src/test/ui/for/for-loop-refutable-pattern-error-message.rs new file mode 100644 index 000000000..221951c87 --- /dev/null +++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.rs @@ -0,0 +1,3 @@ +fn main() { + for &1 in [1].iter() {} //~ ERROR refutable pattern in `for` loop binding +} diff --git a/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr new file mode 100644 index 000000000..20b689aa5 --- /dev/null +++ b/src/test/ui/for/for-loop-refutable-pattern-error-message.stderr @@ -0,0 +1,11 @@ +error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered + --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9 + | +LL | for &1 in [1].iter() {} + | ^^ patterns `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered + | + = note: the matched value is of type `&i32` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/src/test/ui/for/for-loop-type-error.rs b/src/test/ui/for/for-loop-type-error.rs new file mode 100644 index 000000000..8d9fc20f0 --- /dev/null +++ b/src/test/ui/for/for-loop-type-error.rs @@ -0,0 +1,6 @@ +pub fn main() { + let x = () + (); //~ ERROR cannot add `()` to `()` + + // this shouldn't have a flow-on error: + for _ in x {} +} diff --git a/src/test/ui/for/for-loop-type-error.stderr b/src/test/ui/for/for-loop-type-error.stderr new file mode 100644 index 000000000..c93a3b9b2 --- /dev/null +++ b/src/test/ui/for/for-loop-type-error.stderr @@ -0,0 +1,11 @@ +error[E0369]: cannot add `()` to `()` + --> $DIR/for-loop-type-error.rs:2:16 + | +LL | let x = () + (); + | -- ^ -- () + | | + | () + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0369`. diff --git a/src/test/ui/for/for-loop-unconstrained-element-type.rs b/src/test/ui/for/for-loop-unconstrained-element-type.rs new file mode 100644 index 000000000..0c7a3516a --- /dev/null +++ b/src/test/ui/for/for-loop-unconstrained-element-type.rs @@ -0,0 +1,9 @@ +// Test that `for` loops don't introduce artificial +// constraints on the type of the binding (`i`). +// Subtle changes in the desugaring can cause the +// type of elements in the vector to (incorrectly) +// fallback to `!` or `()`. + +fn main() { + for i in Vec::new() { } //~ ERROR type annotations needed +} diff --git a/src/test/ui/for/for-loop-unconstrained-element-type.stderr b/src/test/ui/for/for-loop-unconstrained-element-type.stderr new file mode 100644 index 000000000..b1b38f6b9 --- /dev/null +++ b/src/test/ui/for/for-loop-unconstrained-element-type.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed + --> $DIR/for-loop-unconstrained-element-type.rs:8:14 + | +LL | for i in Vec::new() { } + | ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Vec` + | +help: consider specifying the generic argument + | +LL | for i in Vec::<T>::new() { } + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/foreign-fn-return-lifetime.fixed b/src/test/ui/foreign-fn-return-lifetime.fixed new file mode 100644 index 000000000..143d6343d --- /dev/null +++ b/src/test/ui/foreign-fn-return-lifetime.fixed @@ -0,0 +1,8 @@ +// run-rustfix + +extern "C" { + pub fn g(_: &u8) -> &u8; // OK + pub fn f() -> &'static u8; //~ ERROR missing lifetime specifier +} + +fn main() {} diff --git a/src/test/ui/foreign-fn-return-lifetime.rs b/src/test/ui/foreign-fn-return-lifetime.rs new file mode 100644 index 000000000..76fe50a34 --- /dev/null +++ b/src/test/ui/foreign-fn-return-lifetime.rs @@ -0,0 +1,8 @@ +// run-rustfix + +extern "C" { + pub fn g(_: &u8) -> &u8; // OK + pub fn f() -> &u8; //~ ERROR missing lifetime specifier +} + +fn main() {} diff --git a/src/test/ui/foreign-fn-return-lifetime.stderr b/src/test/ui/foreign-fn-return-lifetime.stderr new file mode 100644 index 000000000..df1a23a19 --- /dev/null +++ b/src/test/ui/foreign-fn-return-lifetime.stderr @@ -0,0 +1,15 @@ +error[E0106]: missing lifetime specifier + --> $DIR/foreign-fn-return-lifetime.rs:5:19 + | +LL | pub fn f() -> &u8; + | ^ expected named lifetime parameter + | + = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from +help: consider using the `'static` lifetime + | +LL | pub fn f() -> &'static u8; + | +++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0106`. diff --git a/src/test/ui/foreign-unsafe-fn-called.mir.stderr b/src/test/ui/foreign-unsafe-fn-called.mir.stderr new file mode 100644 index 000000000..d3cf5d84f --- /dev/null +++ b/src/test/ui/foreign-unsafe-fn-called.mir.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/foreign-unsafe-fn-called.rs:11:5 + | +LL | test::free(); + | ^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/foreign-unsafe-fn-called.rs b/src/test/ui/foreign-unsafe-fn-called.rs new file mode 100644 index 000000000..67302ea1b --- /dev/null +++ b/src/test/ui/foreign-unsafe-fn-called.rs @@ -0,0 +1,14 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +mod test { + extern "C" { + pub fn free(); + } +} + +fn main() { + test::free(); + //[mir]~^ ERROR call to unsafe function is unsafe + //[thir]~^^ ERROR call to unsafe function `test::free` is unsafe +} diff --git a/src/test/ui/foreign-unsafe-fn-called.thir.stderr b/src/test/ui/foreign-unsafe-fn-called.thir.stderr new file mode 100644 index 000000000..00ba0f7a6 --- /dev/null +++ b/src/test/ui/foreign-unsafe-fn-called.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: call to unsafe function `test::free` is unsafe and requires unsafe function or block + --> $DIR/foreign-unsafe-fn-called.rs:11:5 + | +LL | test::free(); + | ^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/foreign/auxiliary/fn-abi.rs b/src/test/ui/foreign/auxiliary/fn-abi.rs new file mode 100644 index 000000000..25c9e1b4c --- /dev/null +++ b/src/test/ui/foreign/auxiliary/fn-abi.rs @@ -0,0 +1,2 @@ +#[no_mangle] +pub extern fn foo() {} diff --git a/src/test/ui/foreign/foreign-fn-linkname.rs b/src/test/ui/foreign/foreign-fn-linkname.rs new file mode 100644 index 000000000..f6d820594 --- /dev/null +++ b/src/test/ui/foreign/foreign-fn-linkname.rs @@ -0,0 +1,28 @@ +// run-pass +// ignore-wasm32-bare no libc to test ffi with +// ignore-sgx no libc + +#![feature(rustc_private)] + +extern crate libc; +use std::ffi::CString; + +mod mlibc { + use libc::{c_char, size_t}; + + extern "C" { + #[link_name = "strlen"] + pub fn my_strlen(str: *const c_char) -> size_t; + } +} + +fn strlen(str: String) -> usize { + // C string is terminated with a zero + let s = CString::new(str).unwrap(); + unsafe { mlibc::my_strlen(s.as_ptr()) as usize } +} + +pub fn main() { + let len = strlen("Rust".to_string()); + assert_eq!(len, 4); +} diff --git a/src/test/ui/foreign/foreign-int-types.rs b/src/test/ui/foreign/foreign-int-types.rs new file mode 100644 index 000000000..2d01d3204 --- /dev/null +++ b/src/test/ui/foreign/foreign-int-types.rs @@ -0,0 +1,12 @@ +// run-pass +#![forbid(improper_ctypes)] +#![allow(dead_code)] + +mod xx { + extern "C" { + pub fn strlen(str: *const u8) -> usize; + pub fn foo(x: isize, y: usize); + } +} + +fn main() {} diff --git a/src/test/ui/foreign/foreign-mod-src/compiletest-ignore-dir b/src/test/ui/foreign/foreign-mod-src/compiletest-ignore-dir new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/test/ui/foreign/foreign-mod-src/compiletest-ignore-dir diff --git a/src/test/ui/foreign/foreign-mod-src/inner.rs b/src/test/ui/foreign/foreign-mod-src/inner.rs new file mode 100644 index 000000000..cf484878b --- /dev/null +++ b/src/test/ui/foreign/foreign-mod-src/inner.rs @@ -0,0 +1,14 @@ +// run-pass + + + +pub fn main() { + let f = "Makefile"; + let s = rustrt.str_buf(f); + let buf = libc.malloc(1024); + let fd = libc.open(s, 0, 0); + libc.read(fd, buf, 1024); + libc.write(1, buf, 1024); + libc.close(fd); + libc.free(buf); +} diff --git a/src/test/ui/foreign/foreign-mod-unused-const.rs b/src/test/ui/foreign/foreign-mod-unused-const.rs new file mode 100644 index 000000000..7d79c30f4 --- /dev/null +++ b/src/test/ui/foreign/foreign-mod-unused-const.rs @@ -0,0 +1,11 @@ +// run-pass +#![allow(dead_code)] +// pretty-expanded FIXME #23616 + +mod foo { + extern "C" { + pub static errno: u32; + } +} + +pub fn main() {} diff --git a/src/test/ui/foreign/foreign-pub-super.rs b/src/test/ui/foreign/foreign-pub-super.rs new file mode 100644 index 000000000..19f9e4e33 --- /dev/null +++ b/src/test/ui/foreign/foreign-pub-super.rs @@ -0,0 +1,12 @@ +// Test for #79487 +// check-pass + +#![allow(dead_code)] + +mod sha2 { + extern "C" { + pub(super) fn GFp_sha512_block_data_order(); + } +} + +fn main() {} diff --git a/src/test/ui/foreign/foreign-src/compiletest-ignore-dir b/src/test/ui/foreign/foreign-src/compiletest-ignore-dir new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/test/ui/foreign/foreign-src/compiletest-ignore-dir diff --git a/src/test/ui/foreign/foreign-src/foreign.rs b/src/test/ui/foreign/foreign-src/foreign.rs new file mode 100644 index 000000000..47016ad6c --- /dev/null +++ b/src/test/ui/foreign/foreign-src/foreign.rs @@ -0,0 +1,9 @@ +// run-pass + + + +pub fn main() { + libc.puts(rustrt.str_buf("hello, extern world 1")); + libc.puts(rustrt.str_buf("hello, extern world 2")); + libc.puts(rustrt.str_buf("hello, extern world 3")); +} diff --git a/src/test/ui/foreign/foreign-truncated-arguments.rs b/src/test/ui/foreign/foreign-truncated-arguments.rs new file mode 100644 index 000000000..c61c2b587 --- /dev/null +++ b/src/test/ui/foreign/foreign-truncated-arguments.rs @@ -0,0 +1,20 @@ +// run-pass +// compile-flags: -O +// Regression test for https://github.com/rust-lang/rust/issues/33868 + +#[repr(C)] +pub struct S { + a: u32, + b: f32, + c: u32 +} + +#[no_mangle] +#[inline(never)] +pub extern "C" fn test(s: S) -> u32 { + s.c +} + +fn main() { + assert_eq!(test(S{a: 0, b: 0.0, c: 42}), 42); +} diff --git a/src/test/ui/foreign/foreign2.rs b/src/test/ui/foreign/foreign2.rs new file mode 100644 index 000000000..df431f299 --- /dev/null +++ b/src/test/ui/foreign/foreign2.rs @@ -0,0 +1,29 @@ +// run-pass +#![allow(dead_code)] +// ignore-wasm32-bare no libc to test ffi with +// pretty-expanded FIXME #23616 +#![feature(rustc_private)] + +extern crate libc; + +mod bar { + extern "C" {} +} + +mod zed { + extern "C" {} +} + +mod mlibc { + use libc::{c_int, c_void, size_t, ssize_t}; + + extern "C" { + pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t; + } +} + +mod baz { + extern "C" {} +} + +pub fn main() {} diff --git a/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs new file mode 100644 index 000000000..a84065e02 --- /dev/null +++ b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.rs @@ -0,0 +1,11 @@ +// Previously this ICE'd because `fn g()` would be lowered, but the block associated with `fn f()` +// wasn't. + +// compile-flags: --crate-type=lib + +extern "C" { + fn f() { + //~^ incorrect function inside `extern` block + fn g() {} + } +} diff --git a/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr new file mode 100644 index 000000000..d4a9ca3e7 --- /dev/null +++ b/src/test/ui/foreign/issue-74120-lowering-of-ffi-block-bodies.stderr @@ -0,0 +1,19 @@ +error: incorrect function inside `extern` block + --> $DIR/issue-74120-lowering-of-ffi-block-bodies.rs:7:8 + | +LL | extern "C" { + | ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | fn f() { + | ________^___- + | | | + | | cannot have a body +LL | | +LL | | fn g() {} +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to previous error + diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs new file mode 100644 index 000000000..2ac3ca293 --- /dev/null +++ b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.rs @@ -0,0 +1,12 @@ +// Regression test for issue #91370. + +extern { + //~^ `extern` blocks define existing foreign functions + fn f() { + //~^ incorrect function inside `extern` block + //~| cannot have a body + impl Copy for u8 {} + } +} + +fn main() {} diff --git a/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr new file mode 100644 index 000000000..4fb2f8c65 --- /dev/null +++ b/src/test/ui/foreign/issue-91370-foreign-fn-block-impl.stderr @@ -0,0 +1,21 @@ +error: incorrect function inside `extern` block + --> $DIR/issue-91370-foreign-fn-block-impl.rs:5:8 + | +LL | extern { + | ------ `extern` blocks define existing foreign functions and functions inside of them cannot have a body +LL | +LL | fn f() { + | ________^___- + | | | + | | cannot have a body +LL | | +LL | | +LL | | impl Copy for u8 {} +LL | | } + | |_____- help: remove the invalid body: `;` + | + = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block + = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html + +error: aborting due to previous error + diff --git a/src/test/ui/foreign/issue-99276-same-type-lifetimes.rs b/src/test/ui/foreign/issue-99276-same-type-lifetimes.rs new file mode 100644 index 000000000..fce603c80 --- /dev/null +++ b/src/test/ui/foreign/issue-99276-same-type-lifetimes.rs @@ -0,0 +1,24 @@ +// Check that we do not ICE when structurally comparing types with lifetimes present. +// check-pass + +pub struct Record<'a> { + pub args: &'a [(usize, &'a str)], +} + +mod a { + extern "Rust" { + fn foo<'a, 'b>(record: &'a super::Record<'b>); + + fn bar<'a, 'b>(record: &'a super::Record<'b>); + } +} + +mod b { + extern "Rust" { + fn foo<'a, 'b>(record: &'a super::Record<'b>); + + fn bar<'a, 'b>(record: &'a super::Record<'b>); + } +} + +fn main() {} diff --git a/src/test/ui/foreign/nil-decl-in-foreign.rs b/src/test/ui/foreign/nil-decl-in-foreign.rs new file mode 100644 index 000000000..f3be94878 --- /dev/null +++ b/src/test/ui/foreign/nil-decl-in-foreign.rs @@ -0,0 +1,14 @@ +// run-pass + +#![allow(improper_ctypes)] +#![allow(dead_code)] +// Issue #901 +// pretty-expanded FIXME #23616 + +mod libc { + extern "C" { + pub fn printf(x: ()); + } +} + +pub fn main() {} diff --git a/src/test/ui/format-no-std.rs b/src/test/ui/format-no-std.rs new file mode 100644 index 000000000..c9b7651bf --- /dev/null +++ b/src/test/ui/format-no-std.rs @@ -0,0 +1,28 @@ +// run-pass +// ignore-emscripten no no_std executables + +#![feature(lang_items, start)] +#![no_std] + +extern crate std as other; + +#[macro_use] extern crate alloc; + +use alloc::string::ToString; + +#[start] +fn start(_argc: isize, _argv: *const *const u8) -> isize { + let s = format!("{}", 1_isize); + assert_eq!(s, "1".to_string()); + + let s = format!("test"); + assert_eq!(s, "test".to_string()); + + let s = format!("{test}", test=3_isize); + assert_eq!(s, "3".to_string()); + + let s = format!("hello {}", "world"); + assert_eq!(s, "hello world".to_string()); + + 0 +} |