diff options
Diffstat (limited to 'tests/ui/liveness')
41 files changed, 1378 insertions, 0 deletions
diff --git a/tests/ui/liveness/liveness-asm.rs b/tests/ui/liveness/liveness-asm.rs new file mode 100644 index 000000000..ea5f033cb --- /dev/null +++ b/tests/ui/liveness/liveness-asm.rs @@ -0,0 +1,45 @@ +// Ensure inout asm! operands are marked as used by the liveness pass + +// only-x86_64 +// check-pass + +#![allow(dead_code)] +#![warn(unused_assignments)] +#![warn(unused_variables)] + +use std::arch::asm; + +// Test the single inout case +unsafe fn f1(mut src: *const u8) { + asm!("/*{0}*/", inout(reg) src); //~ WARN value assigned to `src` is never read +} + +unsafe fn f2(mut src: *const u8) -> *const u8 { + asm!("/*{0}*/", inout(reg) src); + src +} + +// Test the split inout case +unsafe fn f3(mut src: *const u8) { + asm!("/*{0}*/", inout(reg) src => src); //~ WARN value assigned to `src` is never read +} + +unsafe fn f4(mut src: *const u8) -> *const u8 { + asm!("/*{0}*/", inout(reg) src => src); + src +} + +// Tests the use of field projections +struct S { + field: *mut u8, +} + +unsafe fn f5(src: &mut S) { + asm!("/*{0}*/", inout(reg) src.field); +} + +unsafe fn f6(src: &mut S) { + asm!("/*{0}*/", inout(reg) src.field => src.field); +} + +fn main() {} diff --git a/tests/ui/liveness/liveness-asm.stderr b/tests/ui/liveness/liveness-asm.stderr new file mode 100644 index 000000000..57d89e44d --- /dev/null +++ b/tests/ui/liveness/liveness-asm.stderr @@ -0,0 +1,23 @@ +warning: value assigned to `src` is never read + --> $DIR/liveness-asm.rs:14:32 + | +LL | asm!("/*{0}*/", inout(reg) src); + | ^^^ + | + = help: maybe it is overwritten before being read? +note: the lint level is defined here + --> $DIR/liveness-asm.rs:7:9 + | +LL | #![warn(unused_assignments)] + | ^^^^^^^^^^^^^^^^^^ + +warning: value assigned to `src` is never read + --> $DIR/liveness-asm.rs:24:39 + | +LL | asm!("/*{0}*/", inout(reg) src => src); + | ^^^ + | + = help: maybe it is overwritten before being read? + +warning: 2 warnings emitted + diff --git a/tests/ui/liveness/liveness-assign-imm-local-after-ret.rs b/tests/ui/liveness/liveness-assign-imm-local-after-ret.rs new file mode 100644 index 000000000..b463f4368 --- /dev/null +++ b/tests/ui/liveness/liveness-assign-imm-local-after-ret.rs @@ -0,0 +1,16 @@ +// run-pass + +#![allow(unreachable_code)] +// pretty-expanded FIXME #23616 + +#![allow(dead_code)] + +fn test() { + let _v: isize; + _v = 1; + return; + _v = 2; +} + +pub fn main() { +} diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs new file mode 100644 index 000000000..08911c5bd --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.rs @@ -0,0 +1,12 @@ +fn test() { + let v: isize; + //~^ HELP consider making this binding mutable + //~| SUGGESTION mut v + loop { + v = 1; //~ ERROR cannot assign twice to immutable variable `v` + //~| NOTE cannot assign twice to immutable variable + } +} + +fn main() { +} diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr new file mode 100644 index 000000000..66cdce7da --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-loop.stderr @@ -0,0 +1,12 @@ +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/liveness-assign-imm-local-in-loop.rs:6:9 + | +LL | let v: isize; + | - help: consider making this binding mutable: `mut v` +... +LL | v = 1; + | ^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs new file mode 100644 index 000000000..1752d9690 --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.rs @@ -0,0 +1,12 @@ +fn test() { + let v: isize; + //~^ HELP consider making this binding mutable + //~| SUGGESTION mut v + v = 2; //~ NOTE first assignment + v += 1; //~ ERROR cannot assign twice to immutable variable `v` + //~| NOTE cannot assign twice to immutable + v.clone(); +} + +fn main() { +} diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr new file mode 100644 index 000000000..5db9539cb --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-in-op-eq.stderr @@ -0,0 +1,14 @@ +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/liveness-assign-imm-local-in-op-eq.rs:6:5 + | +LL | let v: isize; + | - help: consider making this binding mutable: `mut v` +... +LL | v = 2; + | ----- first assignment to `v` +LL | v += 1; + | ^^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs new file mode 100644 index 000000000..c9b16e439 --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.rs @@ -0,0 +1,12 @@ +fn test() { + let b = Box::new(1); //~ NOTE first assignment + //~| HELP consider making this binding mutable + //~| SUGGESTION mut b + drop(b); + b = Box::new(2); //~ ERROR cannot assign twice to immutable variable `b` + //~| NOTE cannot assign twice to immutable + drop(b); +} + +fn main() { +} diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr new file mode 100644 index 000000000..bb7e7e27a --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-drop.stderr @@ -0,0 +1,15 @@ +error[E0384]: cannot assign twice to immutable variable `b` + --> $DIR/liveness-assign-imm-local-with-drop.rs:6:5 + | +LL | let b = Box::new(1); + | - + | | + | first assignment to `b` + | help: consider making this binding mutable: `mut b` +... +LL | b = Box::new(2); + | ^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs new file mode 100644 index 000000000..4bb2db27a --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.rs @@ -0,0 +1,12 @@ +fn test() { + let v: isize = 1; //~ NOTE first assignment + //~| HELP consider making this binding mutable + //~| SUGGESTION mut v + v.clone(); + v = 2; //~ ERROR cannot assign twice to immutable variable `v` + //~| NOTE cannot assign twice to immutable + v.clone(); +} + +fn main() { +} diff --git a/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr new file mode 100644 index 000000000..80458a70a --- /dev/null +++ b/tests/ui/liveness/liveness-assign/liveness-assign-imm-local-with-init.stderr @@ -0,0 +1,15 @@ +error[E0384]: cannot assign twice to immutable variable `v` + --> $DIR/liveness-assign-imm-local-with-init.rs:6:5 + | +LL | let v: isize = 1; + | - + | | + | first assignment to `v` + | help: consider making this binding mutable: `mut v` +... +LL | v = 2; + | ^^^^^ cannot assign twice to immutable variable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0384`. diff --git a/tests/ui/liveness/liveness-closure-require-ret.rs b/tests/ui/liveness/liveness-closure-require-ret.rs new file mode 100644 index 000000000..b86d1fe4a --- /dev/null +++ b/tests/ui/liveness/liveness-closure-require-ret.rs @@ -0,0 +1,2 @@ +fn force<F>(f: F) -> isize where F: FnOnce() -> isize { f() } +fn main() { println!("{}", force(|| {})); } //~ ERROR mismatched types diff --git a/tests/ui/liveness/liveness-closure-require-ret.stderr b/tests/ui/liveness/liveness-closure-require-ret.stderr new file mode 100644 index 000000000..07b2ef6cd --- /dev/null +++ b/tests/ui/liveness/liveness-closure-require-ret.stderr @@ -0,0 +1,9 @@ +error[E0308]: mismatched types + --> $DIR/liveness-closure-require-ret.rs:2:37 + | +LL | fn main() { println!("{}", force(|| {})); } + | ^^ expected `isize`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/liveness/liveness-consts.rs b/tests/ui/liveness/liveness-consts.rs new file mode 100644 index 000000000..8fe2453ca --- /dev/null +++ b/tests/ui/liveness/liveness-consts.rs @@ -0,0 +1,63 @@ +// check-pass +#![warn(unused)] +#![allow(unreachable_code)] + +pub static A: i32 = { + let mut i = 0; + let mut a = 0; //~ WARN variable `a` is assigned to, but never used + while i < 10 { + i += 1; + a += 1; + } + i +}; + +pub const B: u32 = { + let mut b = 1; + b += 1; //~ WARN value assigned to `b` is never read + b = 42; + b +}; + +pub enum E { + V1 = { + let e = 1; //~ WARN unused variable: `e` + 1 + }, + V2 = { + let _f = 10; + 2 + } +} + +pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + //~^ WARN unused variable: `s` + //~| WARN unused variable: `z` + x +} + +pub trait T { + const T: usize = { + let mut t = 10; + t = t + t; //~ WARN value assigned to `t` is never read + 20 + }; +} + +impl T for String { + const T: usize = { + let w = 10; //~ WARN unused variable: `w` + loop { + break; + let _ = w; + } + 44 + }; +} + +fn main() { + let _ = [(); { + let z = 42; //~ WARN unused variable: `z` + 35 + }]; +} diff --git a/tests/ui/liveness/liveness-consts.stderr b/tests/ui/liveness/liveness-consts.stderr new file mode 100644 index 000000000..6199ea96c --- /dev/null +++ b/tests/ui/liveness/liveness-consts.stderr @@ -0,0 +1,63 @@ +warning: variable `a` is assigned to, but never used + --> $DIR/liveness-consts.rs:7:13 + | +LL | let mut a = 0; + | ^ + | + = note: consider using `_a` instead +note: the lint level is defined here + --> $DIR/liveness-consts.rs:2:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: value assigned to `b` is never read + --> $DIR/liveness-consts.rs:17:5 + | +LL | b += 1; + | ^ + | + = help: maybe it is overwritten before being read? + = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` + +warning: unused variable: `e` + --> $DIR/liveness-consts.rs:24:13 + | +LL | let e = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_e` + +warning: unused variable: `s` + --> $DIR/liveness-consts.rs:33:24 + | +LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + | ^ help: if this is intentional, prefix it with an underscore: `_s` + +warning: unused variable: `z` + --> $DIR/liveness-consts.rs:33:55 + | +LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + | ^ help: if this is intentional, prefix it with an underscore: `_z` + +warning: value assigned to `t` is never read + --> $DIR/liveness-consts.rs:42:9 + | +LL | t = t + t; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `w` + --> $DIR/liveness-consts.rs:49:13 + | +LL | let w = 10; + | ^ help: if this is intentional, prefix it with an underscore: `_w` + +warning: unused variable: `z` + --> $DIR/liveness-consts.rs:60:13 + | +LL | let z = 42; + | ^ help: if this is intentional, prefix it with an underscore: `_z` + +warning: 8 warnings emitted + diff --git a/tests/ui/liveness/liveness-dead.rs b/tests/ui/liveness/liveness-dead.rs new file mode 100644 index 000000000..004663c85 --- /dev/null +++ b/tests/ui/liveness/liveness-dead.rs @@ -0,0 +1,39 @@ +#![allow(dead_code)] +#![deny(unused_assignments)] + +fn f1(x: &mut isize) { + *x = 1; // no error +} + +fn f2() { + let mut x: isize = 3; //~ ERROR: value assigned to `x` is never read + x = 4; + x.clone(); +} + +fn f3() { + let mut x: isize = 3; + x.clone(); + x = 4; //~ ERROR: value assigned to `x` is never read +} + +fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read + x = 4; + x.clone(); +} + +fn f5(mut x: i32) { + x.clone(); + x = 4; //~ ERROR: value assigned to `x` is never read +} + +// #22630 +fn f6() { + let mut done = false; + while !done { + done = true; // no error + continue; + } +} + +fn main() {} diff --git a/tests/ui/liveness/liveness-dead.stderr b/tests/ui/liveness/liveness-dead.stderr new file mode 100644 index 000000000..de6d5bd99 --- /dev/null +++ b/tests/ui/liveness/liveness-dead.stderr @@ -0,0 +1,39 @@ +error: value assigned to `x` is never read + --> $DIR/liveness-dead.rs:9:13 + | +LL | let mut x: isize = 3; + | ^ + | + = help: maybe it is overwritten before being read? +note: the lint level is defined here + --> $DIR/liveness-dead.rs:2:9 + | +LL | #![deny(unused_assignments)] + | ^^^^^^^^^^^^^^^^^^ + +error: value assigned to `x` is never read + --> $DIR/liveness-dead.rs:17:5 + | +LL | x = 4; + | ^ + | + = help: maybe it is overwritten before being read? + +error: value passed to `x` is never read + --> $DIR/liveness-dead.rs:20:11 + | +LL | fn f4(mut x: i32) { + | ^ + | + = help: maybe it is overwritten before being read? + +error: value assigned to `x` is never read + --> $DIR/liveness-dead.rs:27:5 + | +LL | x = 4; + | ^ + | + = help: maybe it is overwritten before being read? + +error: aborting due to 4 previous errors + diff --git a/tests/ui/liveness/liveness-derive.rs b/tests/ui/liveness/liveness-derive.rs new file mode 100644 index 000000000..1921d0d72 --- /dev/null +++ b/tests/ui/liveness/liveness-derive.rs @@ -0,0 +1,38 @@ +// Test for interaction between #[automatically_derived] attribute used by +// built-in derives and lints generated by liveness pass. +// +// edition:2018 +// check-pass +#![warn(unused)] + +pub trait T: Sized { + const N: usize; + fn t(&self) -> Self; +} + +impl T for u32 { + const N: usize = { + let a = 0; //~ WARN unused variable: `a` + 4 + }; + + fn t(&self) -> Self { + let b = 16; //~ WARN unused variable: `b` + 0 + } +} + +#[automatically_derived] +impl T for i32 { + const N: usize = { + let c = 0; + 4 + }; + + fn t(&self) -> Self { + let d = 17; + 0 + } +} + +fn main() {} diff --git a/tests/ui/liveness/liveness-derive.stderr b/tests/ui/liveness/liveness-derive.stderr new file mode 100644 index 000000000..c03d90991 --- /dev/null +++ b/tests/ui/liveness/liveness-derive.stderr @@ -0,0 +1,21 @@ +warning: unused variable: `a` + --> $DIR/liveness-derive.rs:15:13 + | +LL | let a = 0; + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/liveness-derive.rs:6:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `b` + --> $DIR/liveness-derive.rs:20:13 + | +LL | let b = 16; + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +warning: 2 warnings emitted + diff --git a/tests/ui/liveness/liveness-forgot-ret.rs b/tests/ui/liveness/liveness-forgot-ret.rs new file mode 100644 index 000000000..b8c2bc734 --- /dev/null +++ b/tests/ui/liveness/liveness-forgot-ret.rs @@ -0,0 +1,6 @@ +fn god_exists(a: isize) -> bool { return god_exists(a); } + +fn f(a: isize) -> isize { if god_exists(a) { return 5; }; } +//~^ ERROR mismatched types + +fn main() { f(12); } diff --git a/tests/ui/liveness/liveness-forgot-ret.stderr b/tests/ui/liveness/liveness-forgot-ret.stderr new file mode 100644 index 000000000..ddbdbdb0f --- /dev/null +++ b/tests/ui/liveness/liveness-forgot-ret.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/liveness-forgot-ret.rs:3:19 + | +LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; } + | - ^^^^^ expected `isize`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | +help: consider returning the local binding `a` + | +LL | fn f(a: isize) -> isize { if god_exists(a) { return 5; }; a } + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/liveness/liveness-issue-2163.rs b/tests/ui/liveness/liveness-issue-2163.rs new file mode 100644 index 000000000..a632b5b9c --- /dev/null +++ b/tests/ui/liveness/liveness-issue-2163.rs @@ -0,0 +1,8 @@ +use std::vec::Vec; + +fn main() { + let a: Vec<isize> = Vec::new(); + a.iter().all(|_| -> bool { + //~^ ERROR mismatched types + }); +} diff --git a/tests/ui/liveness/liveness-issue-2163.stderr b/tests/ui/liveness/liveness-issue-2163.stderr new file mode 100644 index 000000000..2adc2d438 --- /dev/null +++ b/tests/ui/liveness/liveness-issue-2163.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/liveness-issue-2163.rs:5:30 + | +LL | a.iter().all(|_| -> bool { + | ______________________________^ +LL | | +LL | | }); + | |_____^ expected `bool`, found `()` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/liveness/liveness-missing-ret2.rs b/tests/ui/liveness/liveness-missing-ret2.rs new file mode 100644 index 000000000..a18669f72 --- /dev/null +++ b/tests/ui/liveness/liveness-missing-ret2.rs @@ -0,0 +1,7 @@ +fn f() -> isize { //~ ERROR mismatched types + // Make sure typestate doesn't interpret this match expression as + // the function result + match true { true => { } _ => {} }; +} + +fn main() { } diff --git a/tests/ui/liveness/liveness-missing-ret2.stderr b/tests/ui/liveness/liveness-missing-ret2.stderr new file mode 100644 index 000000000..afdb733cd --- /dev/null +++ b/tests/ui/liveness/liveness-missing-ret2.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/liveness-missing-ret2.rs:1:11 + | +LL | fn f() -> isize { + | - ^^^^^ expected `isize`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/liveness/liveness-move-call-arg.rs b/tests/ui/liveness/liveness-move-call-arg.rs new file mode 100644 index 000000000..1bc2ea6b9 --- /dev/null +++ b/tests/ui/liveness/liveness-move-call-arg.rs @@ -0,0 +1,11 @@ +fn take(_x: Box<isize>) {} + + +fn main() { + + let x: Box<isize> = Box::new(25); + + loop { + take(x); //~ ERROR use of moved value: `x` + } +} diff --git a/tests/ui/liveness/liveness-move-call-arg.stderr b/tests/ui/liveness/liveness-move-call-arg.stderr new file mode 100644 index 000000000..d14cd6cb4 --- /dev/null +++ b/tests/ui/liveness/liveness-move-call-arg.stderr @@ -0,0 +1,26 @@ +error[E0382]: use of moved value: `x` + --> $DIR/liveness-move-call-arg.rs:9:14 + | +LL | let x: Box<isize> = Box::new(25); + | - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait +LL | +LL | loop { + | ---- inside of this loop +LL | take(x); + | ^ value moved here, in previous iteration of loop + | +note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary + --> $DIR/liveness-move-call-arg.rs:1:13 + | +LL | fn take(_x: Box<isize>) {} + | ---- ^^^^^^^^^^ this parameter takes ownership of the value + | | + | in this function +help: consider cloning the value if the performance cost is acceptable + | +LL | take(x.clone()); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/liveness/liveness-move-in-loop.rs b/tests/ui/liveness/liveness-move-in-loop.rs new file mode 100644 index 000000000..064be14d6 --- /dev/null +++ b/tests/ui/liveness/liveness-move-in-loop.rs @@ -0,0 +1,17 @@ +fn main() { + + let y: Box<isize> = 42.into(); + let mut x: Box<isize>; + + loop { + println!("{}", y); + loop { + loop { + loop { + x = y; //~ ERROR use of moved value + x.clone(); + } + } + } + } +} diff --git a/tests/ui/liveness/liveness-move-in-loop.stderr b/tests/ui/liveness/liveness-move-in-loop.stderr new file mode 100644 index 000000000..a060914f1 --- /dev/null +++ b/tests/ui/liveness/liveness-move-in-loop.stderr @@ -0,0 +1,26 @@ +error[E0382]: use of moved value: `y` + --> $DIR/liveness-move-in-loop.rs:11:25 + | +LL | let y: Box<isize> = 42.into(); + | - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait +... +LL | loop { + | ---- inside of this loop +LL | println!("{}", y); +LL | loop { + | ---- inside of this loop +LL | loop { + | ---- inside of this loop +LL | loop { + | ---- inside of this loop +LL | x = y; + | ^ value moved here, in previous iteration of loop + | +help: consider cloning the value if the performance cost is acceptable + | +LL | x = y.clone(); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/liveness/liveness-move-in-while.rs b/tests/ui/liveness/liveness-move-in-while.rs new file mode 100644 index 000000000..7c0cd282c --- /dev/null +++ b/tests/ui/liveness/liveness-move-in-while.rs @@ -0,0 +1,13 @@ +fn main() { + + let y: Box<isize> = 42.into(); + let mut x: Box<isize>; + + loop { + println!("{}", y); //~ ERROR borrow of moved value: `y` + while true { while true { while true { x = y; x.clone(); } } } + //~^ WARN denote infinite loops with + //~| WARN denote infinite loops with + //~| WARN denote infinite loops with + } +} diff --git a/tests/ui/liveness/liveness-move-in-while.stderr b/tests/ui/liveness/liveness-move-in-while.stderr new file mode 100644 index 000000000..4dff7447d --- /dev/null +++ b/tests/ui/liveness/liveness-move-in-while.stderr @@ -0,0 +1,46 @@ +warning: denote infinite loops with `loop { ... }` + --> $DIR/liveness-move-in-while.rs:8:9 + | +LL | while true { while true { while true { x = y; x.clone(); } } } + | ^^^^^^^^^^ help: use `loop` + | + = note: `#[warn(while_true)]` on by default + +warning: denote infinite loops with `loop { ... }` + --> $DIR/liveness-move-in-while.rs:8:22 + | +LL | while true { while true { while true { x = y; x.clone(); } } } + | ^^^^^^^^^^ help: use `loop` + +warning: denote infinite loops with `loop { ... }` + --> $DIR/liveness-move-in-while.rs:8:35 + | +LL | while true { while true { while true { x = y; x.clone(); } } } + | ^^^^^^^^^^ help: use `loop` + +error[E0382]: borrow of moved value: `y` + --> $DIR/liveness-move-in-while.rs:7:24 + | +LL | let y: Box<isize> = 42.into(); + | - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait +... +LL | loop { + | ---- inside of this loop +LL | println!("{}", y); + | ^ value borrowed here after move +LL | while true { while true { while true { x = y; x.clone(); } } } + | ---------- ---------- ---------- - value moved here, in previous iteration of loop + | | | | + | | | inside of this loop + | | inside of this loop + | inside of this loop + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | while true { while true { while true { x = y.clone(); x.clone(); } } } + | ++++++++ + +error: aborting due to previous error; 3 warnings emitted + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/liveness/liveness-return-last-stmt-semi.rs b/tests/ui/liveness/liveness-return-last-stmt-semi.rs new file mode 100644 index 000000000..dff859429 --- /dev/null +++ b/tests/ui/liveness/liveness-return-last-stmt-semi.rs @@ -0,0 +1,18 @@ +// regression test for #8005 + +macro_rules! test { () => { fn foo() -> i32 { 1; } } } + //~^ ERROR mismatched types + +fn no_return() -> i32 {} //~ ERROR mismatched types + +fn bar(x: u32) -> u32 { //~ ERROR mismatched types + x * 2; +} + +fn baz(x: u64) -> u32 { //~ ERROR mismatched types + x * 2; +} + +fn main() { + test!(); +} diff --git a/tests/ui/liveness/liveness-return-last-stmt-semi.stderr b/tests/ui/liveness/liveness-return-last-stmt-semi.stderr new file mode 100644 index 000000000..de0843aa6 --- /dev/null +++ b/tests/ui/liveness/liveness-return-last-stmt-semi.stderr @@ -0,0 +1,42 @@ +error[E0308]: mismatched types + --> $DIR/liveness-return-last-stmt-semi.rs:6:19 + | +LL | fn no_return() -> i32 {} + | --------- ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/liveness-return-last-stmt-semi.rs:8:19 + | +LL | fn bar(x: u32) -> u32 { + | --- ^^^ expected `u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +LL | x * 2; + | - help: remove this semicolon to return this value + +error[E0308]: mismatched types + --> $DIR/liveness-return-last-stmt-semi.rs:12:19 + | +LL | fn baz(x: u64) -> u32 { + | --- ^^^ expected `u32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + +error[E0308]: mismatched types + --> $DIR/liveness-return-last-stmt-semi.rs:3:41 + | +LL | macro_rules! test { () => { fn foo() -> i32 { 1; } } } + | --- ^^^ expected `i32`, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression +... +LL | test!(); + | ------- in this macro invocation + | + = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/liveness/liveness-unused.rs b/tests/ui/liveness/liveness-unused.rs new file mode 100644 index 000000000..9c7be15fc --- /dev/null +++ b/tests/ui/liveness/liveness-unused.rs @@ -0,0 +1,141 @@ +#![warn(unused)] +#![deny(unused_variables)] +#![deny(unused_assignments)] +#![allow(dead_code, non_camel_case_types, trivial_numeric_casts)] + +use std::ops::AddAssign; + +fn f1(x: isize) { + //~^ ERROR unused variable: `x` +} + +fn f1b(x: &mut isize) { + //~^ ERROR unused variable: `x` +} + +#[allow(unused_variables)] +fn f1c(x: isize) {} + +fn f1d() { + let x: isize; + //~^ ERROR unused variable: `x` +} + +fn f2() { + let x = 3; + //~^ ERROR unused variable: `x` +} + +fn f3() { + let mut x = 3; + //~^ ERROR variable `x` is assigned to, but never used + x += 4; + //~^ ERROR value assigned to `x` is never read +} + +fn f3b() { + let mut z = 3; + //~^ ERROR variable `z` is assigned to, but never used + loop { + z += 4; + } +} + +#[allow(unused_variables)] +fn f3c() { + let mut z = 3; + loop { z += 4; } +} + +#[allow(unused_variables)] +#[allow(unused_assignments)] +fn f3d() { + let mut x = 3; + x += 4; +} + +fn f4() { + match Some(3) { + Some(i) => { + //~^ ERROR unused variable: `i` + } + None => {} + } +} + +enum tri { + a(isize), b(isize), c(isize) +} + +fn f4b() -> isize { + match tri::a(3) { + tri::a(i) | tri::b(i) | tri::c(i) => { + i + } + } +} + +fn f5a() { + for x in 1..10 { } + //~^ ERROR unused variable: `x` +} + +fn f5b() { + for (x, _) in [1, 2, 3].iter().enumerate() { } + //~^ ERROR unused variable: `x` +} + +fn f5c() { + for (_, x) in [1, 2, 3].iter().enumerate() { + //~^ ERROR unused variable: `x` + continue; + drop(*x as i32); //~ WARNING unreachable statement + } +} + +struct View<'a>(&'a mut [i32]); + +impl<'a> AddAssign<i32> for View<'a> { + fn add_assign(&mut self, rhs: i32) { + for lhs in self.0.iter_mut() { + *lhs += rhs; + } + } +} + +fn f6() { + let mut array = [1, 2, 3]; + let mut v = View(&mut array); + + // ensure an error shows up for x even if lhs of an overloaded add assign + + let x; + //~^ ERROR variable `x` is assigned to, but never used + + *({ + x = 0; //~ ERROR value assigned to `x` is never read + &mut v + }) += 1; +} + + +struct MutRef<'a>(&'a mut i32); + +impl<'a> AddAssign<i32> for MutRef<'a> { + fn add_assign(&mut self, rhs: i32) { + *self.0 += rhs; + } +} + +fn f7() { + let mut a = 1; + { + // `b` does not trigger unused_variables + let mut b = MutRef(&mut a); + b += 1; + } + drop(a); +} + +fn main() { +} diff --git a/tests/ui/liveness/liveness-unused.stderr b/tests/ui/liveness/liveness-unused.stderr new file mode 100644 index 000000000..f6c478ddb --- /dev/null +++ b/tests/ui/liveness/liveness-unused.stderr @@ -0,0 +1,116 @@ +warning: unreachable statement + --> $DIR/liveness-unused.rs:92:9 + | +LL | continue; + | -------- any code following this expression is unreachable +LL | drop(*x as i32); + | ^^^^^^^^^^^^^^^^ unreachable statement + | +note: the lint level is defined here + --> $DIR/liveness-unused.rs:1:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]` + +error: unused variable: `x` + --> $DIR/liveness-unused.rs:8:7 + | +LL | fn f1(x: isize) { + | ^ help: if this is intentional, prefix it with an underscore: `_x` + | +note: the lint level is defined here + --> $DIR/liveness-unused.rs:2:9 + | +LL | #![deny(unused_variables)] + | ^^^^^^^^^^^^^^^^ + +error: unused variable: `x` + --> $DIR/liveness-unused.rs:12:8 + | +LL | fn f1b(x: &mut isize) { + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +error: unused variable: `x` + --> $DIR/liveness-unused.rs:20:9 + | +LL | let x: isize; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +error: unused variable: `x` + --> $DIR/liveness-unused.rs:25:9 + | +LL | let x = 3; + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +error: variable `x` is assigned to, but never used + --> $DIR/liveness-unused.rs:30:13 + | +LL | let mut x = 3; + | ^ + | + = note: consider using `_x` instead + +error: value assigned to `x` is never read + --> $DIR/liveness-unused.rs:32:5 + | +LL | x += 4; + | ^ + | + = help: maybe it is overwritten before being read? +note: the lint level is defined here + --> $DIR/liveness-unused.rs:3:9 + | +LL | #![deny(unused_assignments)] + | ^^^^^^^^^^^^^^^^^^ + +error: variable `z` is assigned to, but never used + --> $DIR/liveness-unused.rs:37:13 + | +LL | let mut z = 3; + | ^ + | + = note: consider using `_z` instead + +error: unused variable: `i` + --> $DIR/liveness-unused.rs:59:12 + | +LL | Some(i) => { + | ^ help: if this is intentional, prefix it with an underscore: `_i` + +error: unused variable: `x` + --> $DIR/liveness-unused.rs:79:9 + | +LL | for x in 1..10 { } + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +error: unused variable: `x` + --> $DIR/liveness-unused.rs:84:10 + | +LL | for (x, _) in [1, 2, 3].iter().enumerate() { } + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +error: unused variable: `x` + --> $DIR/liveness-unused.rs:89:13 + | +LL | for (_, x) in [1, 2, 3].iter().enumerate() { + | ^ help: if this is intentional, prefix it with an underscore: `_x` + +error: variable `x` is assigned to, but never used + --> $DIR/liveness-unused.rs:112:9 + | +LL | let x; + | ^ + | + = note: consider using `_x` instead + +error: value assigned to `x` is never read + --> $DIR/liveness-unused.rs:116:9 + | +LL | x = 0; + | ^ + | + = help: maybe it is overwritten before being read? + +error: aborting due to 13 previous errors; 1 warning emitted + diff --git a/tests/ui/liveness/liveness-upvars.rs b/tests/ui/liveness/liveness-upvars.rs new file mode 100644 index 000000000..d446d57d3 --- /dev/null +++ b/tests/ui/liveness/liveness-upvars.rs @@ -0,0 +1,144 @@ +// edition:2018 +// check-pass +#![feature(generators)] +#![warn(unused)] +#![allow(unreachable_code)] + +pub fn unintentional_copy_one() { + let mut last = None; + let mut f = move |s| { + last = Some(s); //~ WARN value assigned to `last` is never read + //~| WARN unused variable: `last` + }; + f("a"); + f("b"); + f("c"); + dbg!(last.unwrap()); +} + +pub fn unintentional_copy_two() { + let mut sum = 0; + (1..10).for_each(move |x| { + sum += x; //~ WARN unused variable: `sum` + }); + dbg!(sum); +} + +pub fn f() { + let mut c = 0; + + // Captured by value, but variable is dead on entry. + let _ = move || { + c = 1; //~ WARN value captured by `c` is never read + println!("{}", c); + }; + let _ = async move { + c = 1; //~ WARN value captured by `c` is never read + println!("{}", c); + }; + + // Read and written to, but never actually used. + let _ = move || { + c += 1; //~ WARN unused variable: `c` + }; + let _ = async move { + c += 1; //~ WARN value assigned to `c` is never read + //~| WARN unused variable: `c` + }; + + let _ = move || { + println!("{}", c); + // Value is read by closure itself on later invocations. + c += 1; + }; + let b = Box::new(42); + let _ = move || { + println!("{}", c); + // Never read because this is FnOnce closure. + c += 1; //~ WARN value assigned to `c` is never read + drop(b); + }; + let _ = async move { + println!("{}", c); + // Never read because this is a generator. + c += 1; //~ WARN value assigned to `c` is never read + }; +} + +pub fn nested() { + let mut d = None; + let mut e = None; + let _ = || { + let _ = || { + d = Some("d1"); //~ WARN value assigned to `d` is never read + d = Some("d2"); + }; + let _ = move || { + e = Some("e1"); //~ WARN value assigned to `e` is never read + //~| WARN unused variable: `e` + e = Some("e2"); //~ WARN value assigned to `e` is never read + }; + }; +} + +pub fn g<T: Default>(mut v: T) { + let _ = |r| { + if r { + v = T::default(); //~ WARN value assigned to `v` is never read + } else { + drop(v); + } + }; +} + +pub fn h<T: Copy + Default + std::fmt::Debug>() { + let mut z = T::default(); + let _ = move |b| { + loop { + if b { + z = T::default(); //~ WARN value assigned to `z` is never read + //~| WARN unused variable: `z` + } else { + return; + } + } + dbg!(z); + }; +} + +async fn yield_now() { + todo!(); +} + +pub fn async_generator() { + let mut state: u32 = 0; + + let _ = async { + state = 1; + yield_now().await; + state = 2; + yield_now().await; + state = 3; + }; + + let _ = async move { + state = 4; //~ WARN value assigned to `state` is never read + //~| WARN unused variable: `state` + yield_now().await; + state = 5; //~ WARN value assigned to `state` is never read + }; +} + +pub fn generator() { + let mut s: u32 = 0; + let _ = |_| { + s = 0; + yield (); + s = 1; //~ WARN value assigned to `s` is never read + yield (s = 2); + s = yield (); //~ WARN value assigned to `s` is never read + s = 3; + }; +} + +fn main() {} diff --git a/tests/ui/liveness/liveness-upvars.stderr b/tests/ui/liveness/liveness-upvars.stderr new file mode 100644 index 000000000..82f62371e --- /dev/null +++ b/tests/ui/liveness/liveness-upvars.stderr @@ -0,0 +1,185 @@ +warning: value assigned to `last` is never read + --> $DIR/liveness-upvars.rs:10:9 + | +LL | last = Some(s); + | ^^^^ + | + = help: maybe it is overwritten before being read? +note: the lint level is defined here + --> $DIR/liveness-upvars.rs:4:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` + +warning: unused variable: `last` + --> $DIR/liveness-upvars.rs:10:9 + | +LL | last = Some(s); + | ^^^^ + | + = help: did you mean to capture by reference instead? + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `sum` + --> $DIR/liveness-upvars.rs:22:9 + | +LL | sum += x; + | ^^^ + | + = help: did you mean to capture by reference instead? + +warning: value captured by `c` is never read + --> $DIR/liveness-upvars.rs:32:9 + | +LL | c = 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value captured by `c` is never read + --> $DIR/liveness-upvars.rs:36:9 + | +LL | c = 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: unused variable: `c` + --> $DIR/liveness-upvars.rs:42:9 + | +LL | c += 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `c` is never read + --> $DIR/liveness-upvars.rs:45:9 + | +LL | c += 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `c` + --> $DIR/liveness-upvars.rs:45:9 + | +LL | c += 1; + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `c` is never read + --> $DIR/liveness-upvars.rs:58:9 + | +LL | c += 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `c` is never read + --> $DIR/liveness-upvars.rs:64:9 + | +LL | c += 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `d` is never read + --> $DIR/liveness-upvars.rs:73:13 + | +LL | d = Some("d1"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `e` is never read + --> $DIR/liveness-upvars.rs:77:13 + | +LL | e = Some("e1"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `e` is never read + --> $DIR/liveness-upvars.rs:79:13 + | +LL | e = Some("e2"); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `e` + --> $DIR/liveness-upvars.rs:77:13 + | +LL | e = Some("e1"); + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `v` is never read + --> $DIR/liveness-upvars.rs:87:13 + | +LL | v = T::default(); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `z` is never read + --> $DIR/liveness-upvars.rs:99:17 + | +LL | z = T::default(); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `z` + --> $DIR/liveness-upvars.rs:99:17 + | +LL | z = T::default(); + | ^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `state` is never read + --> $DIR/liveness-upvars.rs:125:9 + | +LL | state = 4; + | ^^^^^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `state` is never read + --> $DIR/liveness-upvars.rs:128:9 + | +LL | state = 5; + | ^^^^^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `state` + --> $DIR/liveness-upvars.rs:125:9 + | +LL | state = 4; + | ^^^^^ + | + = help: did you mean to capture by reference instead? + +warning: value assigned to `s` is never read + --> $DIR/liveness-upvars.rs:137:9 + | +LL | s = 1; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: value assigned to `s` is never read + --> $DIR/liveness-upvars.rs:139:9 + | +LL | s = yield (); + | ^ + | + = help: maybe it is overwritten before being read? + +warning: 22 warnings emitted + diff --git a/tests/ui/liveness/liveness-use-after-move.rs b/tests/ui/liveness/liveness-use-after-move.rs new file mode 100644 index 000000000..46102ca1e --- /dev/null +++ b/tests/ui/liveness/liveness-use-after-move.rs @@ -0,0 +1,8 @@ +fn main() { + + let x: Box<_> = 5.into(); + let y = x; + + println!("{}", *x); //~ ERROR borrow of moved value: `x` + y.clone(); +} diff --git a/tests/ui/liveness/liveness-use-after-move.stderr b/tests/ui/liveness/liveness-use-after-move.stderr new file mode 100644 index 000000000..3accba197 --- /dev/null +++ b/tests/ui/liveness/liveness-use-after-move.stderr @@ -0,0 +1,20 @@ +error[E0382]: borrow of moved value: `x` + --> $DIR/liveness-use-after-move.rs:6:20 + | +LL | let x: Box<_> = 5.into(); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +LL | let y = x; + | - value moved here +LL | +LL | println!("{}", *x); + | ^^ value borrowed here after move + | + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | let y = x.clone(); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/liveness/liveness-use-after-send.rs b/tests/ui/liveness/liveness-use-after-send.rs new file mode 100644 index 000000000..6fcd91a9d --- /dev/null +++ b/tests/ui/liveness/liveness-use-after-send.rs @@ -0,0 +1,19 @@ +use std::marker; + +fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) { + println!("{:?}", ch); + println!("{:?}", data); + panic!(); +} + +#[derive(Debug)] +struct Chan<T>(isize, marker::PhantomData<T>); + +// Tests that "log(debug, message);" is flagged as using +// message after the send deinitializes it +fn test00_start(ch: Chan<Box<isize>>, message: Box<isize>, _count: Box<isize>) { + send(ch, message); + println!("{}", message); //~ ERROR borrow of moved value: `message` +} + +fn main() { panic!(); } diff --git a/tests/ui/liveness/liveness-use-after-send.stderr b/tests/ui/liveness/liveness-use-after-send.stderr new file mode 100644 index 000000000..65d55ca8f --- /dev/null +++ b/tests/ui/liveness/liveness-use-after-send.stderr @@ -0,0 +1,24 @@ +error[E0382]: borrow of moved value: `message` + --> $DIR/liveness-use-after-send.rs:16:20 + | +LL | fn test00_start(ch: Chan<Box<isize>>, message: Box<isize>, _count: Box<isize>) { + | ------- move occurs because `message` has type `Box<isize>`, which does not implement the `Copy` trait +LL | send(ch, message); + | ------- value moved here +LL | println!("{}", message); + | ^^^^^^^ value borrowed here after move + | +note: consider changing this parameter type in function `send` to borrow instead if owning the value isn't necessary + --> $DIR/liveness-use-after-send.rs:3:54 + | +LL | fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) { + | ---- in this function ^ this parameter takes ownership of the value + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider cloning the value if the performance cost is acceptable + | +LL | send(ch, message.clone()); + | ++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. |