diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:02:58 +0000 |
commit | 698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch) | |
tree | 173a775858bd501c378080a10dca74132f05bc50 /src/test/ui/moves | |
parent | Initial commit. (diff) | |
download | rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip |
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
76 files changed, 2252 insertions, 0 deletions
diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.rs b/src/test/ui/moves/borrow-closures-instead-of-move.rs new file mode 100644 index 000000000..51771ced7 --- /dev/null +++ b/src/test/ui/moves/borrow-closures-instead-of-move.rs @@ -0,0 +1,36 @@ +fn takes_fn(f: impl Fn()) { + loop { + takes_fnonce(f); + //~^ ERROR use of moved value + //~| HELP consider borrowing + } +} + +fn takes_fn_mut(m: impl FnMut()) { + if maybe() { + takes_fnonce(m); + //~^ HELP consider mutably borrowing + } + takes_fnonce(m); + //~^ ERROR use of moved value +} + +fn has_closure() { + let mut x = 0; + let mut closure = || { + x += 1; + }; + takes_fnonce(closure); + //~^ HELP consider mutably borrowing + closure(); + //~^ ERROR borrow of moved value +} + +fn maybe() -> bool { + false +} + +// Could also be Fn[Mut], here it doesn't matter +fn takes_fnonce(_: impl FnOnce()) {} + +fn main() {} diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr new file mode 100644 index 000000000..3146b6959 --- /dev/null +++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr @@ -0,0 +1,53 @@ +error[E0382]: use of moved value: `f` + --> $DIR/borrow-closures-instead-of-move.rs:3:22 + | +LL | fn takes_fn(f: impl Fn()) { + | - move occurs because `f` has type `impl Fn()`, which does not implement the `Copy` trait +LL | loop { +LL | takes_fnonce(f); + | ^ value moved here, in previous iteration of loop + | +help: consider borrowing `f` + | +LL | takes_fnonce(&f); + | + + +error[E0382]: use of moved value: `m` + --> $DIR/borrow-closures-instead-of-move.rs:14:18 + | +LL | fn takes_fn_mut(m: impl FnMut()) { + | - move occurs because `m` has type `impl FnMut()`, which does not implement the `Copy` trait +LL | if maybe() { +LL | takes_fnonce(m); + | - value moved here +... +LL | takes_fnonce(m); + | ^ value used here after move + | +help: consider mutably borrowing `m` + | +LL | takes_fnonce(&mut m); + | ++++ + +error[E0382]: borrow of moved value: `closure` + --> $DIR/borrow-closures-instead-of-move.rs:25:5 + | +LL | takes_fnonce(closure); + | ------- value moved here +LL | +LL | closure(); + | ^^^^^^^ value borrowed here after move + | +note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `x` out of its environment + --> $DIR/borrow-closures-instead-of-move.rs:21:9 + | +LL | x += 1; + | ^ +help: consider mutably borrowing `closure` + | +LL | takes_fnonce(&mut closure); + | ++++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/issue-46099-move-in-macro.rs b/src/test/ui/moves/issue-46099-move-in-macro.rs new file mode 100644 index 000000000..576fe1f4c --- /dev/null +++ b/src/test/ui/moves/issue-46099-move-in-macro.rs @@ -0,0 +1,15 @@ +// Regression test for issue #46099 +// Tests that we don't emit spurious +// 'value moved in previous iteration of loop' message + +macro_rules! test { + ($v:expr) => {{ + drop(&$v); + $v + }} +} + +fn main() { + let b = Box::new(true); + test!({b}); //~ ERROR use of moved value +} diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr new file mode 100644 index 000000000..baa87e3e9 --- /dev/null +++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr @@ -0,0 +1,11 @@ +error[E0382]: use of moved value: `b` + --> $DIR/issue-46099-move-in-macro.rs:14:12 + | +LL | let b = Box::new(true); + | - move occurs because `b` has type `Box<bool>`, which does not implement the `Copy` trait +LL | test!({b}); + | ^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.rs b/src/test/ui/moves/issue-72649-uninit-in-loop.rs new file mode 100644 index 000000000..d76b69ecd --- /dev/null +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.rs @@ -0,0 +1,74 @@ +// Regression test for issue #72649 +// Tests that we don't emit spurious +// 'value moved in previous iteration of loop' message + +struct NonCopy; + +fn good() { + loop { + let value = NonCopy{}; + let _used = value; + } +} + +fn moved_here_1() { + loop { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + let _used = value; + //~^ NOTE value moved here + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value used here after move + } +} + +fn moved_here_2() { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + loop { + let _used = value; + //~^ NOTE value moved here + loop { + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value used here after move + } + } +} + +fn moved_loop_1() { + let value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + loop { + let _used = value; //~ ERROR use of moved value: `value` + //~^ NOTE value moved here, in previous iteration of loop + } +} + +fn moved_loop_2() { + let mut value = NonCopy{}; + //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait + let _used = value; + value = NonCopy{}; + loop { + let _used2 = value; //~ ERROR use of moved value: `value` + //~^ NOTE value moved here, in previous iteration of loop + } +} + +fn uninit_1() { + loop { + let value: NonCopy; //~ NOTE declared here + let _used = value; //~ ERROR binding `value` isn't initialized + //~^ NOTE `value` used here but it isn't initialized + } +} + +fn uninit_2() { + let mut value: NonCopy; //~ NOTE declared here + loop { + let _used = value; //~ ERROR binding `value` isn't initialized + //~^ NOTE `value` used here but it isn't initialized + } +} + +fn main() {} diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr new file mode 100644 index 000000000..c7373b5be --- /dev/null +++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr @@ -0,0 +1,63 @@ +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:20:22 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +LL | +LL | let _used = value; + | ----- value moved here +LL | +LL | let _used2 = value; + | ^^^^^ value used here after move + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:32:26 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used = value; + | ----- value moved here +... +LL | let _used2 = value; + | ^^^^^ value used here after move + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:42:21 + | +LL | let value = NonCopy{}; + | ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used = value; + | ^^^^^ value moved here, in previous iteration of loop + +error[E0382]: use of moved value: `value` + --> $DIR/issue-72649-uninit-in-loop.rs:53:22 + | +LL | let mut value = NonCopy{}; + | --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait +... +LL | let _used2 = value; + | ^^^^^ value moved here, in previous iteration of loop + +error[E0381]: used binding `value` isn't initialized + --> $DIR/issue-72649-uninit-in-loop.rs:61:21 + | +LL | let value: NonCopy; + | ----- binding declared here but left uninitialized +LL | let _used = value; + | ^^^^^ `value` used here but it isn't initialized + +error[E0381]: used binding `value` isn't initialized + --> $DIR/issue-72649-uninit-in-loop.rs:69:21 + | +LL | let mut value: NonCopy; + | --------- binding declared here but left uninitialized +LL | loop { +LL | let _used = value; + | ^^^^^ `value` used here but it isn't initialized + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0381, E0382. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/moves/issue-75904-move-closure-loop.rs b/src/test/ui/moves/issue-75904-move-closure-loop.rs new file mode 100644 index 000000000..6641a0376 --- /dev/null +++ b/src/test/ui/moves/issue-75904-move-closure-loop.rs @@ -0,0 +1,15 @@ +// Regression test for issue #75904 +// Tests that we point at an expression +// that required the upvar to be moved, rather than just borrowed. + +struct NotCopy; + +fn main() { + let mut a = NotCopy; + loop { + || { //~ ERROR use of moved value + &mut a; + a; + }; + } +} diff --git a/src/test/ui/moves/issue-75904-move-closure-loop.stderr b/src/test/ui/moves/issue-75904-move-closure-loop.stderr new file mode 100644 index 000000000..5e427a1fc --- /dev/null +++ b/src/test/ui/moves/issue-75904-move-closure-loop.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value: `a` + --> $DIR/issue-75904-move-closure-loop.rs:10:9 + | +LL | let mut a = NotCopy; + | ----- move occurs because `a` has type `NotCopy`, which does not implement the `Copy` trait +LL | loop { +LL | || { + | ^^ value moved into closure here, in previous iteration of loop +LL | &mut a; +LL | a; + | - use occurs due to use in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/issue-99470-move-out-of-some.rs b/src/test/ui/moves/issue-99470-move-out-of-some.rs new file mode 100644 index 000000000..f404cd3cd --- /dev/null +++ b/src/test/ui/moves/issue-99470-move-out-of-some.rs @@ -0,0 +1,9 @@ +fn main() { + let x: &Option<Box<i32>> = &Some(Box::new(0)); + + match x { + //~^ ERROR cannot move out of `x` as enum variant `Some` which is behind a shared reference + &Some(_y) => (), + &None => (), + } +} diff --git a/src/test/ui/moves/issue-99470-move-out-of-some.stderr b/src/test/ui/moves/issue-99470-move-out-of-some.stderr new file mode 100644 index 000000000..6e4a4e5ba --- /dev/null +++ b/src/test/ui/moves/issue-99470-move-out-of-some.stderr @@ -0,0 +1,16 @@ +error[E0507]: cannot move out of `x` as enum variant `Some` which is behind a shared reference + --> $DIR/issue-99470-move-out-of-some.rs:4:11 + | +LL | match x { + | ^ +LL | +LL | &Some(_y) => (), + | --------- + | | | + | | data moved here + | | move occurs because `_y` has type `Box<i32>`, which does not implement the `Copy` trait + | help: consider removing the `&`: `Some(_y)` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/moves/move-1-unique.rs b/src/test/ui/moves/move-1-unique.rs new file mode 100644 index 000000000..f98d075d1 --- /dev/null +++ b/src/test/ui/moves/move-1-unique.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(unused_mut)] +#![allow(dead_code)] + +#[derive(Clone)] +struct Triple { + x: isize, + y: isize, + z: isize, +} + +fn test(x: bool, foo: Box<Triple>) -> isize { + let bar = foo; + let mut y: Box<Triple>; + if x { y = bar; } else { y = Box::new(Triple{x: 4, y: 5, z: 6}); } + return y.y; +} + +pub fn main() { + let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); + assert_eq!(test(true, x.clone()), 2); + assert_eq!(test(true, x.clone()), 2); + assert_eq!(test(true, x.clone()), 2); + assert_eq!(test(false, x), 5); +} diff --git a/src/test/ui/moves/move-2-unique.rs b/src/test/ui/moves/move-2-unique.rs new file mode 100644 index 000000000..8fda3c1c8 --- /dev/null +++ b/src/test/ui/moves/move-2-unique.rs @@ -0,0 +1,10 @@ +// run-pass +#![allow(dead_code)] + +struct X { x: isize, y: isize, z: isize } + +pub fn main() { + let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); + let y = x; + assert_eq!(y.y, 2); +} diff --git a/src/test/ui/moves/move-2.rs b/src/test/ui/moves/move-2.rs new file mode 100644 index 000000000..5e0100874 --- /dev/null +++ b/src/test/ui/moves/move-2.rs @@ -0,0 +1,6 @@ +// run-pass +#![allow(dead_code)] + +struct X { x: isize, y: isize, z: isize } + +pub fn main() { let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); let y = x; assert_eq!(y.y, 2); } diff --git a/src/test/ui/moves/move-3-unique.rs b/src/test/ui/moves/move-3-unique.rs new file mode 100644 index 000000000..8e5df2c3f --- /dev/null +++ b/src/test/ui/moves/move-3-unique.rs @@ -0,0 +1,25 @@ +// run-pass +#![allow(unused_mut)] +#![allow(dead_code)] + +#[derive(Clone)] +struct Triple { + x: isize, + y: isize, + z: isize, +} + +fn test(x: bool, foo: Box<Triple>) -> isize { + let bar = foo; + let mut y: Box<Triple>; + if x { y = bar; } else { y = Box::new(Triple {x: 4, y: 5, z: 6}); } + return y.y; +} + +pub fn main() { + let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3}); + for _ in 0_usize..10000_usize { + assert_eq!(test(true, x.clone()), 2); + } + assert_eq!(test(false, x), 5); +} diff --git a/src/test/ui/moves/move-4-unique.rs b/src/test/ui/moves/move-4-unique.rs new file mode 100644 index 000000000..24aec7ea6 --- /dev/null +++ b/src/test/ui/moves/move-4-unique.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] + +struct Triple {a: isize, b: isize, c: isize} + +fn test(foo: Box<Triple>) -> Box<Triple> { + let foo = foo; + let bar = foo; + let baz = bar; + let quux = baz; + return quux; +} + +pub fn main() { + let x = Box::new(Triple{a: 1, b: 2, c: 3}); + let y = test(x); + assert_eq!(y.c, 3); +} diff --git a/src/test/ui/moves/move-4.rs b/src/test/ui/moves/move-4.rs new file mode 100644 index 000000000..63aa031a6 --- /dev/null +++ b/src/test/ui/moves/move-4.rs @@ -0,0 +1,18 @@ +// run-pass +#![allow(dead_code)] + +struct Triple { a: isize, b: isize, c: isize } + +fn test(foo: Box<Triple>) -> Box<Triple> { + let foo = foo; + let bar = foo; + let baz = bar; + let quux = baz; + return quux; +} + +pub fn main() { + let x = Box::new(Triple{ a: 1, b: 2, c: 3 }); + let y = test(x); + assert_eq!(y.c, 3); +} diff --git a/src/test/ui/moves/move-arg-2-unique.rs b/src/test/ui/moves/move-arg-2-unique.rs new file mode 100644 index 000000000..9622c8375 --- /dev/null +++ b/src/test/ui/moves/move-arg-2-unique.rs @@ -0,0 +1,12 @@ +// run-pass + +fn test(foo: Box<Vec<isize>> ) { assert_eq!((*foo)[0], 10); } + +pub fn main() { + let x = Box::new(vec![10]); + // Test forgetting a local by move-in + test(x); + + // Test forgetting a temporary by move-in. + test(Box::new(vec![10])); +} diff --git a/src/test/ui/moves/move-arg-2.rs b/src/test/ui/moves/move-arg-2.rs new file mode 100644 index 000000000..77ee06e19 --- /dev/null +++ b/src/test/ui/moves/move-arg-2.rs @@ -0,0 +1,12 @@ +// run-pass + +fn test(foo: Box<Vec<isize>>) { assert_eq!((*foo)[0], 10); } + +pub fn main() { + let x = Box::new(vec![10]); + // Test forgetting a local by move-in + test(x); + + // Test forgetting a temporary by move-in. + test(Box::new(vec![10])); +} diff --git a/src/test/ui/moves/move-arg.rs b/src/test/ui/moves/move-arg.rs new file mode 100644 index 000000000..5942cd89f --- /dev/null +++ b/src/test/ui/moves/move-arg.rs @@ -0,0 +1,5 @@ +// run-pass + +fn test(foo: isize) { assert_eq!(foo, 10); } + +pub fn main() { let x = 10; test(x); } diff --git a/src/test/ui/moves/move-deref-coercion.rs b/src/test/ui/moves/move-deref-coercion.rs new file mode 100644 index 000000000..41154388f --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.rs @@ -0,0 +1,33 @@ +use std::ops::Deref; + +struct NotCopy { + inner: bool +} + +impl NotCopy { + fn inner_method(&self) {} +} + +struct Foo { + first: NotCopy, + second: NotCopy +} + +impl Deref for Foo { + type Target = NotCopy; + fn deref(&self) -> &NotCopy { + &self.second + } +} + +fn use_field(val: Foo) { + let _val = val.first; + val.inner; //~ ERROR borrow of +} + +fn use_method(val: Foo) { + let _val = val.first; + val.inner_method(); //~ ERROR borrow of +} + +fn main() {} diff --git a/src/test/ui/moves/move-deref-coercion.stderr b/src/test/ui/moves/move-deref-coercion.stderr new file mode 100644 index 000000000..5760f4a7f --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.stderr @@ -0,0 +1,35 @@ +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:25:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner; + | ^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^ + +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:30:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner_method(); + | ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-fn-self-receiver.rs b/src/test/ui/moves/move-fn-self-receiver.rs new file mode 100644 index 000000000..946642ef6 --- /dev/null +++ b/src/test/ui/moves/move-fn-self-receiver.rs @@ -0,0 +1,79 @@ +use std::pin::Pin; +use std::rc::Rc; +use std::ops::Add; + +struct Foo; + +impl Add for Foo { + type Output = (); + fn add(self, _rhs: Self) -> () {} +} + +impl Foo { + fn use_self(self) {} + fn use_box_self(self: Box<Self>) {} + fn use_pin_box_self(self: Pin<Box<Self>>) {} + fn use_rc_self(self: Rc<Self>) {} + fn use_mut_self(&mut self) -> &mut Self { self } +} + +struct Container(Vec<bool>); + +impl Container { + fn custom_into_iter(self) -> impl Iterator<Item = bool> { + self.0.into_iter() + } +} + +fn move_out(val: Container) { + val.0.into_iter().next(); + val.0; //~ ERROR use of moved + + let foo = Foo; + foo.use_self(); + foo; //~ ERROR use of moved + + let second_foo = Foo; + second_foo.use_self(); + second_foo; //~ ERROR use of moved + + let boxed_foo = Box::new(Foo); + boxed_foo.use_box_self(); + boxed_foo; //~ ERROR use of moved + + let pin_box_foo = Box::pin(Foo); + pin_box_foo.use_pin_box_self(); + pin_box_foo; //~ ERROR use of moved + + let mut mut_foo = Foo; + let ret = mut_foo.use_mut_self(); + mut_foo; //~ ERROR cannot move out + ret; + + let rc_foo = Rc::new(Foo); + rc_foo.use_rc_self(); + rc_foo; //~ ERROR use of moved + + let foo_add = Foo; + foo_add + Foo; + foo_add; //~ ERROR use of moved + + let implicit_into_iter = vec![true]; + for _val in implicit_into_iter {} + implicit_into_iter; //~ ERROR use of moved + + let explicit_into_iter = vec![true]; + for _val in explicit_into_iter.into_iter() {} + explicit_into_iter; //~ ERROR use of moved + + let container = Container(vec![]); + for _val in container.custom_into_iter() {} + container; //~ ERROR use of moved + + let foo2 = Foo; + loop { + foo2.use_self(); //~ ERROR use of moved + } +} + +fn main() {} diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr new file mode 100644 index 000000000..3a686121a --- /dev/null +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -0,0 +1,169 @@ +error[E0382]: use of moved value: `val.0` + --> $DIR/move-fn-self-receiver.rs:30:5 + | +LL | val.0.into_iter().next(); + | ----------- `val.0` moved due to this method call +LL | val.0; + | ^^^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `val.0` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ + = note: move occurs because `val.0` has type `Vec<bool>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `foo` + --> $DIR/move-fn-self-receiver.rs:34:5 + | +LL | let foo = Foo; + | --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait +LL | foo.use_self(); + | ---------- `foo` moved due to this method call +LL | foo; + | ^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `foo` + --> $DIR/move-fn-self-receiver.rs:13:17 + | +LL | fn use_self(self) {} + | ^^^^ + +error[E0382]: use of moved value: `second_foo` + --> $DIR/move-fn-self-receiver.rs:38:5 + | +LL | let second_foo = Foo; + | ---------- move occurs because `second_foo` has type `Foo`, which does not implement the `Copy` trait +LL | second_foo.use_self(); + | ---------- `second_foo` moved due to this method call +LL | second_foo; + | ^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `boxed_foo` + --> $DIR/move-fn-self-receiver.rs:42:5 + | +LL | let boxed_foo = Box::new(Foo); + | --------- move occurs because `boxed_foo` has type `Box<Foo>`, which does not implement the `Copy` trait +LL | boxed_foo.use_box_self(); + | -------------- `boxed_foo` moved due to this method call +LL | boxed_foo; + | ^^^^^^^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `boxed_foo` + --> $DIR/move-fn-self-receiver.rs:14:21 + | +LL | fn use_box_self(self: Box<Self>) {} + | ^^^^ + +error[E0382]: use of moved value: `pin_box_foo` + --> $DIR/move-fn-self-receiver.rs:46:5 + | +LL | let pin_box_foo = Box::pin(Foo); + | ----------- move occurs because `pin_box_foo` has type `Pin<Box<Foo>>`, which does not implement the `Copy` trait +LL | pin_box_foo.use_pin_box_self(); + | ------------------ `pin_box_foo` moved due to this method call +LL | pin_box_foo; + | ^^^^^^^^^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `pin_box_foo` + --> $DIR/move-fn-self-receiver.rs:15:25 + | +LL | fn use_pin_box_self(self: Pin<Box<Self>>) {} + | ^^^^ + +error[E0505]: cannot move out of `mut_foo` because it is borrowed + --> $DIR/move-fn-self-receiver.rs:50:5 + | +LL | let ret = mut_foo.use_mut_self(); + | ---------------------- borrow of `mut_foo` occurs here +LL | mut_foo; + | ^^^^^^^ move out of `mut_foo` occurs here +LL | ret; + | --- borrow later used here + +error[E0382]: use of moved value: `rc_foo` + --> $DIR/move-fn-self-receiver.rs:55:5 + | +LL | let rc_foo = Rc::new(Foo); + | ------ move occurs because `rc_foo` has type `Rc<Foo>`, which does not implement the `Copy` trait +LL | rc_foo.use_rc_self(); + | ------------- `rc_foo` moved due to this method call +LL | rc_foo; + | ^^^^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `rc_foo` + --> $DIR/move-fn-self-receiver.rs:16:20 + | +LL | fn use_rc_self(self: Rc<Self>) {} + | ^^^^ + +error[E0382]: use of moved value: `foo_add` + --> $DIR/move-fn-self-receiver.rs:59:5 + | +LL | let foo_add = Foo; + | ------- move occurs because `foo_add` has type `Foo`, which does not implement the `Copy` trait +LL | foo_add + Foo; + | ------------- `foo_add` moved due to usage in operator +LL | foo_add; + | ^^^^^^^ value used here after move + | +note: calling this operator moves the left-hand side + --> $SRC_DIR/core/src/ops/arith.rs:LL:COL + | +LL | fn add(self, rhs: Rhs) -> Self::Output; + | ^^^^ + +error[E0382]: use of moved value: `implicit_into_iter` + --> $DIR/move-fn-self-receiver.rs:63:5 + | +LL | let implicit_into_iter = vec![true]; + | ------------------ move occurs because `implicit_into_iter` has type `Vec<bool>`, which does not implement the `Copy` trait +LL | for _val in implicit_into_iter {} + | ------------------ `implicit_into_iter` moved due to this implicit call to `.into_iter()` +LL | implicit_into_iter; + | ^^^^^^^^^^^^^^^^^^ value used here after move + | +help: consider iterating over a slice of the `Vec<bool>`'s content to avoid moving into the `for` loop + | +LL | for _val in &implicit_into_iter {} + | + + +error[E0382]: use of moved value: `explicit_into_iter` + --> $DIR/move-fn-self-receiver.rs:67:5 + | +LL | let explicit_into_iter = vec![true]; + | ------------------ move occurs because `explicit_into_iter` has type `Vec<bool>`, which does not implement the `Copy` trait +LL | for _val in explicit_into_iter.into_iter() {} + | ----------- `explicit_into_iter` moved due to this method call +LL | explicit_into_iter; + | ^^^^^^^^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `container` + --> $DIR/move-fn-self-receiver.rs:71:5 + | +LL | let container = Container(vec![]); + | --------- move occurs because `container` has type `Container`, which does not implement the `Copy` trait +LL | for _val in container.custom_into_iter() {} + | ------------------ `container` moved due to this method call +LL | container; + | ^^^^^^^^^ value used here after move + | +note: this function takes ownership of the receiver `self`, which moves `container` + --> $DIR/move-fn-self-receiver.rs:23:25 + | +LL | fn custom_into_iter(self) -> impl Iterator<Item = bool> { + | ^^^^ + +error[E0382]: use of moved value: `foo2` + --> $DIR/move-fn-self-receiver.rs:75:9 + | +LL | let foo2 = Foo; + | ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait +LL | loop { +LL | foo2.use_self(); + | ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop + +error: aborting due to 12 previous errors + +Some errors have detailed explanations: E0382, E0505. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-guard-same-consts.rs b/src/test/ui/moves/move-guard-same-consts.rs new file mode 100644 index 000000000..b96ef8e19 --- /dev/null +++ b/src/test/ui/moves/move-guard-same-consts.rs @@ -0,0 +1,25 @@ +// #47295: We used to have a hack of special-casing adjacent amtch +// arms whose patterns were composed solely of constants to not have +// them linked in the cfg. +// +// This was broken for various reasons. In particular, that hack was +// originally authored under the assunption that other checks +// elsewhere would ensure that the two patterns did not overlap. But +// that assumption did not hold, at least not in the long run (namely, +// overlapping patterns were turned into warnings rather than errors). + + + +fn main() { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, 2) if take(x) => (), + (1, 2) if take(x) => (), //~ ERROR use of moved value: `x` + _ => (), + } +} + +fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr new file mode 100644 index 000000000..2048fefef --- /dev/null +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of moved value: `x` + --> $DIR/move-guard-same-consts.rs:20:24 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (1, 2) if take(x) => (), + | - value moved here +LL | (1, 2) if take(x) => (), + | ^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-in-guard-1.rs b/src/test/ui/moves/move-in-guard-1.rs new file mode 100644 index 000000000..36e39fea6 --- /dev/null +++ b/src/test/ui/moves/move-in-guard-1.rs @@ -0,0 +1,15 @@ +pub fn main() { + + + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, _) if take(x) => (), + (_, 2) if take(x) => (), //~ ERROR use of moved value: `x` + _ => (), + } +} + +fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr new file mode 100644 index 000000000..5e9aa66b9 --- /dev/null +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of moved value: `x` + --> $DIR/move-in-guard-1.rs:10:24 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (1, _) if take(x) => (), + | - value moved here +LL | (_, 2) if take(x) => (), + | ^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-in-guard-2.rs b/src/test/ui/moves/move-in-guard-2.rs new file mode 100644 index 000000000..085b7ec6e --- /dev/null +++ b/src/test/ui/moves/move-in-guard-2.rs @@ -0,0 +1,13 @@ +pub fn main() { + let x: Box<_> = Box::new(1); + + let v = (1, 2); + + match v { + (1, _) | + (_, 2) if take(x) => (), //~ ERROR use of moved value: `x` + _ => (), + } +} + +fn take<T>(_: T) -> bool { false } diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr new file mode 100644 index 000000000..8d636c11b --- /dev/null +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -0,0 +1,12 @@ +error[E0382]: use of moved value: `x` + --> $DIR/move-in-guard-2.rs:8:24 + | +LL | let x: Box<_> = Box::new(1); + | - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait +... +LL | (_, 2) if take(x) => (), + | ^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-into-dead-array-1.rs b/src/test/ui/moves/move-into-dead-array-1.rs new file mode 100644 index 000000000..0b8d76def --- /dev/null +++ b/src/test/ui/moves/move-into-dead-array-1.rs @@ -0,0 +1,15 @@ +// Ensure that we cannot move into an uninitialized fixed-size array. + +struct D { _x: u8 } + +fn d() -> D { D { _x: 0 } } + +fn main() { + foo(1); + foo(3); +} + +fn foo(i: usize) { + let mut a: [D; 4]; + a[i] = d(); //~ ERROR E0381 +} diff --git a/src/test/ui/moves/move-into-dead-array-1.stderr b/src/test/ui/moves/move-into-dead-array-1.stderr new file mode 100644 index 000000000..344a6bbf0 --- /dev/null +++ b/src/test/ui/moves/move-into-dead-array-1.stderr @@ -0,0 +1,11 @@ +error[E0381]: used binding `a` isn't initialized + --> $DIR/move-into-dead-array-1.rs:14:5 + | +LL | let mut a: [D; 4]; + | ----- binding declared here but left uninitialized +LL | a[i] = d(); + | ^^^^ `a` used here but it isn't initialized + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/moves/move-into-dead-array-2.rs b/src/test/ui/moves/move-into-dead-array-2.rs new file mode 100644 index 000000000..9b66ea35f --- /dev/null +++ b/src/test/ui/moves/move-into-dead-array-2.rs @@ -0,0 +1,15 @@ +// Ensure that we cannot move into an uninitialized fixed-size array. + +struct D { _x: u8 } + +fn d() -> D { D { _x: 0 } } + +fn main() { + foo([d(), d(), d(), d()], 1); + foo([d(), d(), d(), d()], 3); +} + +fn foo(mut a: [D; 4], i: usize) { + drop(a); + a[i] = d(); //~ ERROR use of moved value: `a` +} diff --git a/src/test/ui/moves/move-into-dead-array-2.stderr b/src/test/ui/moves/move-into-dead-array-2.stderr new file mode 100644 index 000000000..19e476c04 --- /dev/null +++ b/src/test/ui/moves/move-into-dead-array-2.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of moved value: `a` + --> $DIR/move-into-dead-array-2.rs:14:5 + | +LL | fn foo(mut a: [D; 4], i: usize) { + | ----- move occurs because `a` has type `[D; 4]`, which does not implement the `Copy` trait +LL | drop(a); + | - value moved here +LL | a[i] = d(); + | ^^^^ value used here after move + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-nullary-fn.rs b/src/test/ui/moves/move-nullary-fn.rs new file mode 100644 index 000000000..14c9262c7 --- /dev/null +++ b/src/test/ui/moves/move-nullary-fn.rs @@ -0,0 +1,13 @@ +// run-pass +// Issue #922 +// pretty-expanded FIXME #23616 + +fn f2<F>(_thing: F) where F: FnOnce() { } + +fn f<F>(thing: F) where F: FnOnce() { + f2(thing); +} + +pub fn main() { + f(|| {}); +} diff --git a/src/test/ui/moves/move-of-addr-of-mut.rs b/src/test/ui/moves/move-of-addr-of-mut.rs new file mode 100644 index 000000000..19fd70286 --- /dev/null +++ b/src/test/ui/moves/move-of-addr-of-mut.rs @@ -0,0 +1,12 @@ +// Ensure that taking a mutable raw ptr to an uninitialized variable does not change its +// initializedness. + +struct S; + +fn main() { + let mut x: S; + std::ptr::addr_of_mut!(x); //~ ERROR E0381 + + let y = x; // Should error here if `addr_of_mut` is ever allowed on uninitialized variables + drop(y); +} diff --git a/src/test/ui/moves/move-of-addr-of-mut.stderr b/src/test/ui/moves/move-of-addr-of-mut.stderr new file mode 100644 index 000000000..e75f2b1c0 --- /dev/null +++ b/src/test/ui/moves/move-of-addr-of-mut.stderr @@ -0,0 +1,13 @@ +error[E0381]: used binding `x` isn't initialized + --> $DIR/move-of-addr-of-mut.rs:8:5 + | +LL | let mut x: S; + | ----- binding declared here but left uninitialized +LL | std::ptr::addr_of_mut!(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `x` used here but it isn't initialized + | + = note: this error originates in the macro `std::ptr::addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0381`. diff --git a/src/test/ui/moves/move-out-of-array-1.rs b/src/test/ui/moves/move-out-of-array-1.rs new file mode 100644 index 000000000..77cb73e47 --- /dev/null +++ b/src/test/ui/moves/move-out-of-array-1.rs @@ -0,0 +1,18 @@ +// Ensure that we cannot move out of a fixed-size array (especially +// when the element type has a destructor). + + +struct D { _x: u8 } + +impl Drop for D { fn drop(&mut self) { } } + +fn main() { + fn d() -> D { D { _x: 0 } } + + let _d1 = foo([d(), d(), d(), d()], 1); + let _d3 = foo([d(), d(), d(), d()], 3); +} + +fn foo(a: [D; 4], i: usize) -> D { + a[i] //~ ERROR cannot move out of type `[D; 4]`, a non-copy array +} diff --git a/src/test/ui/moves/move-out-of-array-1.stderr b/src/test/ui/moves/move-out-of-array-1.stderr new file mode 100644 index 000000000..0af083e5b --- /dev/null +++ b/src/test/ui/moves/move-out-of-array-1.stderr @@ -0,0 +1,12 @@ +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-1.rs:17:5 + | +LL | a[i] + | ^^^^ + | | + | cannot move out of here + | move occurs because `a[_]` has type `D`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/moves/move-out-of-array-ref.rs b/src/test/ui/moves/move-out-of-array-ref.rs new file mode 100644 index 000000000..343f00ff2 --- /dev/null +++ b/src/test/ui/moves/move-out-of-array-ref.rs @@ -0,0 +1,34 @@ +// Ensure that we cannot move out of a reference to a fixed-size array + +struct D { _x: u8 } + +impl Drop for D { fn drop(&mut self) { } } + +fn move_elem(a: &[D; 4]) -> D { + let [_, e, _, _] = *a; //~ ERROR cannot move + e +} + +fn move_subarr(a: &[D; 4]) -> [D; 2] { + let [_, s @ .. , _] = *a; //~ ERROR cannot move + s +} + +fn move_elem_mut(a: &mut [D; 4]) -> D { + let [_, e, _, _] = *a; //~ ERROR cannot move + e +} + +fn move_subarr_mut(a: &mut [D; 4]) -> [D; 2] { + let [_, s @ .. , _] = *a; //~ ERROR cannot move + s +} + +fn main() { + fn d() -> D { D { _x: 0 } } + + move_elem(&[d(), d(), d(), d()]); + move_subarr(&[d(), d(), d(), d()]); + move_elem_mut(&mut [d(), d(), d(), d()]); + move_subarr_mut(&mut [d(), d(), d(), d()]); +} diff --git a/src/test/ui/moves/move-out-of-array-ref.stderr b/src/test/ui/moves/move-out-of-array-ref.stderr new file mode 100644 index 000000000..fd682e56a --- /dev/null +++ b/src/test/ui/moves/move-out-of-array-ref.stderr @@ -0,0 +1,47 @@ +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:8:24 + | +LL | let [_, e, _, _] = *a; + | - ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `e` has type `D`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:13:27 + | +LL | let [_, s @ .. , _] = *a; + | ------ ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:18:24 + | +LL | let [_, e, _, _] = *a; + | - ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `e` has type `D`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:23:27 + | +LL | let [_, s @ .. , _] = *a; + | ------ ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/moves/move-out-of-field.rs b/src/test/ui/moves/move-out-of-field.rs new file mode 100644 index 000000000..9f697db4f --- /dev/null +++ b/src/test/ui/moves/move-out-of-field.rs @@ -0,0 +1,27 @@ +// run-pass + +use std::string::String; + +struct StringBuffer { + s: String, +} + +impl StringBuffer { + pub fn append(&mut self, v: &str) { + self.s.push_str(v); + } +} + +fn to_string(sb: StringBuffer) -> String { + sb.s +} + +pub fn main() { + let mut sb = StringBuffer { + s: String::new(), + }; + sb.append("Hello, "); + sb.append("World!"); + let str = to_string(sb); + assert_eq!(str, "Hello, World!"); +} diff --git a/src/test/ui/moves/move-out-of-slice-1.rs b/src/test/ui/moves/move-out-of-slice-1.rs new file mode 100644 index 000000000..982648f5b --- /dev/null +++ b/src/test/ui/moves/move-out-of-slice-1.rs @@ -0,0 +1,11 @@ +#![feature(box_patterns)] + +struct A; + +fn main() { + let a: Box<[A]> = Box::new([A]); + match a { //~ ERROR cannot move out of type `[A]`, a non-copy slice + box [a] => {}, + _ => {} + } +} diff --git a/src/test/ui/moves/move-out-of-slice-1.stderr b/src/test/ui/moves/move-out-of-slice-1.stderr new file mode 100644 index 000000000..ce5ddb3e1 --- /dev/null +++ b/src/test/ui/moves/move-out-of-slice-1.stderr @@ -0,0 +1,14 @@ +error[E0508]: cannot move out of type `[A]`, a non-copy slice + --> $DIR/move-out-of-slice-1.rs:7:11 + | +LL | match a { + | ^ cannot move out of here +LL | box [a] => {}, + | - + | | + | data moved here + | move occurs because `a` has type `A`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/moves/move-out-of-slice-2.rs b/src/test/ui/moves/move-out-of-slice-2.rs new file mode 100644 index 000000000..59c02d42b --- /dev/null +++ b/src/test/ui/moves/move-out-of-slice-2.rs @@ -0,0 +1,35 @@ +#![feature(unsized_locals)] +//~^ WARN the feature `unsized_locals` is incomplete + +struct A; +#[derive(Clone, Copy)] +struct C; + +fn main() { + let a: Box<[A]> = Box::new([A]); + match *a { + //~^ ERROR cannot move out of type `[A]`, a non-copy slice + [a @ ..] => {} + _ => {} + } + let b: Box<[A]> = Box::new([A, A, A]); + match *b { + //~^ ERROR cannot move out of type `[A]`, a non-copy slice + [_, _, b @ .., _] => {} + _ => {} + } + + // `[C]` isn't `Copy`, even if `C` is. + let c: Box<[C]> = Box::new([C]); + match *c { + //~^ ERROR cannot move out of type `[C]`, a non-copy slice + [c @ ..] => {} + _ => {} + } + let d: Box<[C]> = Box::new([C, C, C]); + match *d { + //~^ ERROR cannot move out of type `[C]`, a non-copy slice + [_, _, d @ .., _] => {} + _ => {} + } +} diff --git a/src/test/ui/moves/move-out-of-slice-2.stderr b/src/test/ui/moves/move-out-of-slice-2.stderr new file mode 100644 index 000000000..9a863bf31 --- /dev/null +++ b/src/test/ui/moves/move-out-of-slice-2.stderr @@ -0,0 +1,60 @@ +warning: the feature `unsized_locals` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/move-out-of-slice-2.rs:1:12 + | +LL | #![feature(unsized_locals)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #48055 <https://github.com/rust-lang/rust/issues/48055> for more information + +error[E0508]: cannot move out of type `[A]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:10:11 + | +LL | match *a { + | ^^ cannot move out of here +LL | +LL | [a @ ..] => {} + | ------ + | | + | data moved here + | move occurs because `a` has type `[A]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[A]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:16:11 + | +LL | match *b { + | ^^ cannot move out of here +LL | +LL | [_, _, b @ .., _] => {} + | ------ + | | + | data moved here + | move occurs because `b` has type `[A]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[C]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:24:11 + | +LL | match *c { + | ^^ cannot move out of here +LL | +LL | [c @ ..] => {} + | ------ + | | + | data moved here + | move occurs because `c` has type `[C]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[C]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:30:11 + | +LL | match *d { + | ^^ cannot move out of here +LL | +LL | [_, _, d @ .., _] => {} + | ------ + | | + | data moved here + | move occurs because `d` has type `[C]`, which does not implement the `Copy` trait + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/moves/move-out-of-tuple-field.rs b/src/test/ui/moves/move-out-of-tuple-field.rs new file mode 100644 index 000000000..66912fa4d --- /dev/null +++ b/src/test/ui/moves/move-out-of-tuple-field.rs @@ -0,0 +1,13 @@ +struct Foo(Box<isize>); + + + +fn main() { + let x: (Box<_>,) = (Box::new(1),); + let y = x.0; + let z = x.0; //~ ERROR use of moved value: `x.0` + + let x = Foo(Box::new(1)); + let y = x.0; + let z = x.0; //~ ERROR use of moved value: `x.0` +} diff --git a/src/test/ui/moves/move-out-of-tuple-field.stderr b/src/test/ui/moves/move-out-of-tuple-field.stderr new file mode 100644 index 000000000..bb4eb7677 --- /dev/null +++ b/src/test/ui/moves/move-out-of-tuple-field.stderr @@ -0,0 +1,23 @@ +error[E0382]: use of moved value: `x.0` + --> $DIR/move-out-of-tuple-field.rs:8:13 + | +LL | let y = x.0; + | --- value moved here +LL | let z = x.0; + | ^^^ value used here after move + | + = note: move occurs because `x.0` has type `Box<i32>`, which does not implement the `Copy` trait + +error[E0382]: use of moved value: `x.0` + --> $DIR/move-out-of-tuple-field.rs:12:13 + | +LL | let y = x.0; + | --- value moved here +LL | let z = x.0; + | ^^^ value used here after move + | + = note: move occurs because `x.0` has type `Box<isize>`, which does not implement the `Copy` trait + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-scalar.rs b/src/test/ui/moves/move-scalar.rs new file mode 100644 index 000000000..98bfeb1bc --- /dev/null +++ b/src/test/ui/moves/move-scalar.rs @@ -0,0 +1,10 @@ +// run-pass +#![allow(unused_mut)] + +pub fn main() { + + let y: isize = 42; + let mut x: isize; + x = y; + assert_eq!(x, 42); +} diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.rs b/src/test/ui/moves/moves-based-on-type-access-to-field.rs new file mode 100644 index 000000000..e2003ed6e --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.rs @@ -0,0 +1,14 @@ +// Tests that if you move from `x.f` or `x[0]`, `x` is inaccessible. +// Also tests that we give a more specific error message. + +struct Foo { f: String, y: isize } +fn consume(_s: String) {} +fn touch<A>(_a: &A) {} + +fn f20() { + let x = vec!["hi".to_string()]; + consume(x.into_iter().next().unwrap()); + touch(&x[0]); //~ ERROR borrow of moved value: `x` +} + +fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr new file mode 100644 index 000000000..3cc8ca291 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -0,0 +1,19 @@ +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-access-to-field.rs:11:12 + | +LL | let x = vec!["hi".to_string()]; + | - move occurs because `x` has type `Vec<String>`, which does not implement the `Copy` trait +LL | consume(x.into_iter().next().unwrap()); + | ----------- `x` moved due to this method call +LL | touch(&x[0]); + | ^ value borrowed here after move + | +note: this function takes ownership of the receiver `self`, which moves `x` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.rs b/src/test/ui/moves/moves-based-on-type-block-bad.rs new file mode 100644 index 000000000..eca33167f --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-block-bad.rs @@ -0,0 +1,29 @@ +#![feature(box_patterns)] + + +struct S { + x: Box<E> +} + +enum E { + Foo(Box<S>), + Bar(Box<isize>), + Baz +} + +fn f<G>(s: &S, g: G) where G: FnOnce(&S) { + g(s) +} + +fn main() { + let s = S { x: Box::new(E::Bar(Box::new(42))) }; + loop { + f(&s, |hellothere| { + match hellothere.x { //~ ERROR cannot move out + box E::Foo(_) => {} + box E::Bar(x) => println!("{}", x.to_string()), + box E::Baz => {} + } + }) + } +} diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.stderr b/src/test/ui/moves/moves-based-on-type-block-bad.stderr new file mode 100644 index 000000000..5ed91a0d5 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-block-bad.stderr @@ -0,0 +1,15 @@ +error[E0507]: cannot move out of `hellothere.x` as enum variant `Bar` which is behind a shared reference + --> $DIR/moves-based-on-type-block-bad.rs:22:19 + | +LL | match hellothere.x { + | ^^^^^^^^^^^^ help: consider borrowing here: `&hellothere.x` +LL | box E::Foo(_) => {} +LL | box E::Bar(x) => println!("{}", x.to_string()), + | - + | | + | data moved here + | move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.rs b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.rs new file mode 100644 index 000000000..b2f68352f --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.rs @@ -0,0 +1,9 @@ +use std::thread; + +fn main() { + let x = "Hello world!".to_string(); + thread::spawn(move|| { + println!("{}", x); + }); + println!("{}", x); //~ ERROR borrow of moved value +} diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr new file mode 100644 index 000000000..34b7ea658 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr @@ -0,0 +1,18 @@ +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-capture-clause-bad.rs:8:20 + | +LL | let x = "Hello world!".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | thread::spawn(move|| { + | ------ value moved into closure here +LL | println!("{}", x); + | - variable moved due to use in closure +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) + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause.rs b/src/test/ui/moves/moves-based-on-type-capture-clause.rs new file mode 100644 index 000000000..4a6a4ed28 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-capture-clause.rs @@ -0,0 +1,12 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten no threads support + +use std::thread; + +pub fn main() { + let x = "Hello world!".to_string(); + thread::spawn(move|| { + println!("{}", x); + }).join(); +} diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs new file mode 100644 index 000000000..4417fb926 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs @@ -0,0 +1,20 @@ +// Test for a subtle failure computing kinds of cyclic types, in which +// temporary kinds wound up being stored in a cache and used later. +// See rustc::ty::type_contents() for more information. + + +struct List { key: isize, next: Option<Box<List>> } + +fn foo(node: Box<List>) -> isize { + let r = match node.next { + Some(right) => consume(right), + None => 0 + }; + consume(node) + r //~ ERROR use of partially moved value: `node` +} + +fn consume(v: Box<List>) -> isize { + v.key +} + +fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr new file mode 100644 index 000000000..a315bbaab --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr @@ -0,0 +1,18 @@ +error[E0382]: use of partially moved value: `node` + --> $DIR/moves-based-on-type-cyclic-types-issue-4821.rs:13:13 + | +LL | Some(right) => consume(right), + | ----- value partially moved here +... +LL | consume(node) + r + | ^^^^ value used here after partial move + | + = note: partial move occurs because value has type `Box<List>`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `node.next.0` + | +LL | Some(ref right) => consume(right), + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs new file mode 100644 index 000000000..d256e18b6 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs @@ -0,0 +1,49 @@ +// Tests that references to move-by-default values trigger moves when +// they occur as part of various kinds of expressions. + +struct Foo<A> { f: A } +fn touch<A>(_a: &A) {} + +fn f00() { + let x = "hi".to_string(); + //~^ NOTE move occurs because `x` has type `String` + let _y = Foo { f:x }; + //~^ NOTE value moved here + touch(&x); //~ ERROR borrow of moved value: `x` + //~^ NOTE value borrowed here after move +} + +fn f05() { + let x = "hi".to_string(); + //~^ NOTE move occurs because `x` has type `String` + let _y = Foo { f:(((x))) }; + //~^ NOTE value moved here + touch(&x); //~ ERROR borrow of moved value: `x` + //~^ NOTE value borrowed here after move +} + +fn f10() { + let x = "hi".to_string(); + let _y = Foo { f:x.clone() }; + touch(&x); +} + +fn f20() { + let x = "hi".to_string(); + let _y = Foo { f:(x).clone() }; + touch(&x); +} + +fn f30() { + let x = "hi".to_string(); + let _y = Foo { f:((x)).clone() }; + touch(&x); +} + +fn f40() { + let x = "hi".to_string(); + let _y = Foo { f:(((((((x)).clone()))))) }; + touch(&x); +} + +fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr new file mode 100644 index 000000000..ee7971691 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr @@ -0,0 +1,27 @@ +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:12:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | +LL | let _y = Foo { f:x }; + | - value moved here +LL | +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:21:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | +LL | let _y = Foo { f:(((x))) }; + | ------- value moved here +LL | +LL | touch(&x); + | ^^ value borrowed here after move + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-exprs.rs b/src/test/ui/moves/moves-based-on-type-exprs.rs new file mode 100644 index 000000000..4a52d8d32 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-exprs.rs @@ -0,0 +1,93 @@ +// Tests that references to move-by-default values trigger moves when +// they occur as part of various kinds of expressions. + + +struct Foo<A> { f: A } +fn guard(_s: String) -> bool {panic!()} +fn touch<A>(_a: &A) {} + +fn f10() { + let x = "hi".to_string(); + let _y = Foo { f:x }; + touch(&x); //~ ERROR borrow of moved value: `x` +} + +fn f20() { + let x = "hi".to_string(); + let _y = (x, 3); + touch(&x); //~ ERROR borrow of moved value: `x` +} + +fn f21() { + let x = vec![1, 2, 3]; + let _y = (x[0], 3); + touch(&x); +} + +fn f30(cond: bool) { + let x = "hi".to_string(); + let y = "ho".to_string(); + let _y = if cond { + x + } else { + y + }; + touch(&x); //~ ERROR borrow of moved value: `x` + touch(&y); //~ ERROR borrow of moved value: `y` +} + +fn f40(cond: bool) { + let x = "hi".to_string(); + let y = "ho".to_string(); + let _y = match cond { + true => x, + false => y + }; + touch(&x); //~ ERROR borrow of moved value: `x` + touch(&y); //~ ERROR borrow of moved value: `y` +} + +fn f50(cond: bool) { + let x = "hi".to_string(); + let y = "ho".to_string(); + let _y = match cond { + _ if guard(x) => 10, + true => 10, + false => 20, + }; + touch(&x); //~ ERROR borrow of moved value: `x` + touch(&y); +} + +fn f70() { + let x = "hi".to_string(); + let _y = [x]; + touch(&x); //~ ERROR borrow of moved value: `x` +} + +fn f80() { + let x = "hi".to_string(); + let _y = vec![x]; + touch(&x); //~ ERROR borrow of moved value: `x` +} + +fn f100() { + let x = vec!["hi".to_string()]; + let _y = x.into_iter().next().unwrap(); + touch(&x); //~ ERROR borrow of moved value: `x` +} + +fn f110() { + let x = vec!["hi".to_string()]; + let _y = [x.into_iter().next().unwrap(); 1]; + touch(&x); //~ ERROR borrow of moved value: `x` +} + +fn f120() { + let mut x = vec!["hi".to_string(), "ho".to_string()]; + x.swap(0, 1); + touch(&x[0]); + touch(&x[1]); +} + +fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr new file mode 100644 index 000000000..9bcec3674 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -0,0 +1,135 @@ +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:12:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | let _y = Foo { f:x }; + | - value moved here +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:18:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | let _y = (x, 3); + | - value moved here +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:35:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +... +LL | x + | - value moved here +... +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `y` + --> $DIR/moves-based-on-type-exprs.rs:36:11 + | +LL | let y = "ho".to_string(); + | - move occurs because `y` has type `String`, which does not implement the `Copy` trait +... +LL | y + | - value moved here +... +LL | touch(&y); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:46:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +... +LL | true => x, + | - value moved here +... +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `y` + --> $DIR/moves-based-on-type-exprs.rs:47:11 + | +LL | let y = "ho".to_string(); + | - move occurs because `y` has type `String`, which does not implement the `Copy` trait +... +LL | false => y + | - value moved here +... +LL | touch(&y); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:58:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +... +LL | _ if guard(x) => 10, + | - value moved here +... +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:65:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | let _y = [x]; + | - value moved here +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:71:11 + | +LL | let x = "hi".to_string(); + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait +LL | let _y = vec![x]; + | - value moved here +LL | touch(&x); + | ^^ value borrowed here after move + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:77:11 + | +LL | let x = vec!["hi".to_string()]; + | - move occurs because `x` has type `Vec<String>`, which does not implement the `Copy` trait +LL | let _y = x.into_iter().next().unwrap(); + | ----------- `x` moved due to this method call +LL | touch(&x); + | ^^ value borrowed here after move + | +note: this function takes ownership of the receiver `self`, which moves `x` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ + +error[E0382]: borrow of moved value: `x` + --> $DIR/moves-based-on-type-exprs.rs:83:11 + | +LL | let x = vec!["hi".to_string()]; + | - move occurs because `x` has type `Vec<String>`, which does not implement the `Copy` trait +LL | let _y = [x.into_iter().next().unwrap(); 1]; + | ----------- `x` moved due to this method call +LL | touch(&x); + | ^^ value borrowed here after move + | +note: this function takes ownership of the receiver `self`, which moves `x` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + | +LL | fn into_iter(self) -> Self::IntoIter; + | ^^^^ + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.rs b/src/test/ui/moves/moves-based-on-type-match-bindings.rs new file mode 100644 index 000000000..4fb9b40e8 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.rs @@ -0,0 +1,21 @@ +// Tests that bindings to move-by-default values trigger moves of the +// discriminant. Also tests that the compiler explains the move in +// terms of the binding, not the discriminant. + +struct Foo<A> { f: A } +fn guard(_s: String) -> bool {panic!()} +fn touch<A>(_a: &A) {} + +fn f10() { + let x = Foo {f: "hi".to_string()}; + + let y = match x { + Foo {f} => {} + }; + + touch(&x); //~ ERROR borrow of partially moved value: `x` + //~^ value borrowed here after partial move + //~| partial move occurs because `x.f` has type `String` +} + +fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr new file mode 100644 index 000000000..ad1a2db8b --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr @@ -0,0 +1,14 @@ +error[E0382]: borrow of partially moved value: `x` + --> $DIR/moves-based-on-type-match-bindings.rs:16:11 + | +LL | Foo {f} => {} + | - value partially moved here +... +LL | touch(&x); + | ^^ value borrowed here after partial move + | + = note: partial move occurs because `x.f` has type `String`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs new file mode 100644 index 000000000..76b7aab54 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs @@ -0,0 +1,10 @@ +#![feature(unboxed_closures)] + +fn to_fn<A,F:Fn<A>>(f: F) -> F { f } + +fn test(_x: Box<usize>) {} + +fn main() { + let i = Box::new(3); + let _f = to_fn(|| test(i)); //~ ERROR cannot move out +} diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr new file mode 100644 index 000000000..125e446c3 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -0,0 +1,13 @@ +error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure + --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28 + | +LL | let i = Box::new(3); + | - captured outer variable +LL | let _f = to_fn(|| test(i)); + | -- ^ move occurs because `i` has type `Box<usize>`, which does not implement the `Copy` trait + | | + | captured by this `Fn` closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs new file mode 100644 index 000000000..86fd37e78 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.rs @@ -0,0 +1,35 @@ +// Tests correct kind-checking of the reason stack closures without the :Copy +// bound must be noncopyable. For details see +// https://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closure/ + +struct R<'a> { + // This struct is needed to create the + // otherwise infinite type of a fn that + // accepts itself as argument: + c: Box<dyn FnMut(&mut R, bool) + 'a> +} + +fn innocent_looking_victim() { + let mut x = Some("hello".to_string()); + conspirator(|f, writer| { + if writer { + x = None; + } else { + match x { + Some(ref msg) => { + (f.c)(f, true); + //~^ ERROR: cannot borrow `*f` as mutable more than once at a time + println!("{}", msg); + }, + None => panic!("oops"), + } + } + }) +} + +fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) { + let mut r = R {c: Box::new(f)}; + f(&mut r, false) //~ ERROR borrow of moved value +} + +fn main() { innocent_looking_victim() } diff --git a/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr new file mode 100644 index 000000000..4759b4589 --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-no-recursive-stack-closure.stderr @@ -0,0 +1,28 @@ +error[E0499]: cannot borrow `*f` as mutable more than once at a time + --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:20:27 + | +LL | (f.c)(f, true); + | ----- ^ second mutable borrow occurs here + | | + | first mutable borrow occurs here + | first borrow later used by call + +error[E0382]: borrow of moved value: `f` + --> $DIR/moves-based-on-type-no-recursive-stack-closure.rs:32:5 + | +LL | fn conspirator<F>(mut f: F) where F: FnMut(&mut R, bool) { + | ----- move occurs because `f` has type `F`, which does not implement the `Copy` trait +LL | let mut r = R {c: Box::new(f)}; + | - value moved here +LL | f(&mut r, false) + | ^ value borrowed here after move + | +help: consider mutably borrowing `f` + | +LL | let mut r = R {c: Box::new(&mut f)}; + | ++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0382, E0499. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-based-on-type-tuple.rs b/src/test/ui/moves/moves-based-on-type-tuple.rs new file mode 100644 index 000000000..2e67d8f8a --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-tuple.rs @@ -0,0 +1,10 @@ +fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> { + + + Box::new((x, x)) + //~^ use of moved value: `x` [E0382] +} + +fn main() { + dup(Box::new(3)); +} diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr new file mode 100644 index 000000000..eef8ce61f --- /dev/null +++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr @@ -0,0 +1,14 @@ +error[E0382]: use of moved value: `x` + --> $DIR/moves-based-on-type-tuple.rs:4:18 + | +LL | fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> { + | - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait +... +LL | Box::new((x, x)) + | - ^ value used here after move + | | + | value moved here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/moves-sru-moved-field.rs b/src/test/ui/moves/moves-sru-moved-field.rs new file mode 100644 index 000000000..72957c49f --- /dev/null +++ b/src/test/ui/moves/moves-sru-moved-field.rs @@ -0,0 +1,23 @@ +type Noncopyable = Box<isize>; + + + +struct Foo { + copied: isize, + moved: Box<isize>, + noncopyable: Noncopyable +} + +fn test0(f: Foo, g: Noncopyable, h: Noncopyable) { + // just copy implicitly copyable fields from `f`, no moves: + let _b = Foo {moved: Box::new(1), noncopyable: g, ..f}; + let _c = Foo {moved: Box::new(2), noncopyable: h, ..f}; +} + +fn test1(f: Foo, g: Noncopyable, h: Noncopyable) { + // copying move-by-default fields from `f`, so move: + let _b = Foo {noncopyable: g, ..f}; + let _c = Foo {noncopyable: h, ..f}; //~ ERROR use of moved value: `f.moved` +} + +fn main() {} diff --git a/src/test/ui/moves/moves-sru-moved-field.stderr b/src/test/ui/moves/moves-sru-moved-field.stderr new file mode 100644 index 000000000..cf7213637 --- /dev/null +++ b/src/test/ui/moves/moves-sru-moved-field.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of moved value: `f.moved` + --> $DIR/moves-sru-moved-field.rs:20:14 + | +LL | let _b = Foo {noncopyable: g, ..f}; + | ------------------------- value moved here +LL | let _c = Foo {noncopyable: h, ..f}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move + | + = note: move occurs because `f.moved` has type `Box<isize>`, which does not implement the `Copy` trait + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/use_of_moved_value_clone_suggestions.rs b/src/test/ui/moves/use_of_moved_value_clone_suggestions.rs new file mode 100644 index 000000000..d5c8d4e6b --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_clone_suggestions.rs @@ -0,0 +1,6 @@ +// `Rc` is not ever `Copy`, we should not suggest adding `T: Copy` constraint +fn duplicate_rc<T>(t: std::rc::Rc<T>) -> (std::rc::Rc<T>, std::rc::Rc<T>) { + (t, t) //~ use of moved value: `t` +} + +fn main() {} diff --git a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr new file mode 100644 index 000000000..c25981e6f --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr @@ -0,0 +1,13 @@ +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_clone_suggestions.rs:3:9 + | +LL | fn duplicate_rc<T>(t: std::rc::Rc<T>) -> (std::rc::Rc<T>, std::rc::Rc<T>) { + | - move occurs because `t` has type `Rc<T>`, which does not implement the `Copy` trait +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed new file mode 100644 index 000000000..45acf5beb --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.fixed @@ -0,0 +1,86 @@ +// run-rustfix +#![allow(dead_code)] + +fn duplicate_t<T: Copy>(t: T) -> (T, T) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_opt<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup1<T: Copy>(t: (T,)) -> ((T,), (T,)) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup2<A: Copy, B: Copy>(t: (A, B)) -> ((A, B), (A, B)) { + //~^ HELP consider restricting type parameters + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +struct S<T>(T); +trait Trait {} +impl<T: Trait + Clone> Clone for S<T> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl<T: Trait + Copy> Copy for S<T> {} + +trait A {} +trait B {} + +// Test where bounds are added with different bound placements +fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>) +where + T: A + Copy + Trait, + //~^ HELP consider further restricting this bound +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>) +where + T: A + Copy + Trait, + //~^ HELP consider further restricting this bound + T: B, +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>) +//~^ HELP consider further restricting this bound +where + T: B, +{ + (t, t) //~ use of moved value: `t` +} + +#[rustfmt::skip] +fn existing_colon<T: Copy>(t: T) { + //~^ HELP consider restricting type parameter `T` + [t, t]; //~ use of moved value: `t` +} + +fn existing_colon_in_where<T>(t: T) +where + T:, T: Copy + //~^ HELP consider further restricting type parameter `T` +{ + [t, t]; //~ use of moved value: `t` +} + +fn main() {} diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs new file mode 100644 index 000000000..0a43dd1a9 --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.rs @@ -0,0 +1,86 @@ +// run-rustfix +#![allow(dead_code)] + +fn duplicate_t<T>(t: T) -> (T, T) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_opt<T>(t: Option<T>) -> (Option<T>, Option<T>) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup1<T>(t: (T,)) -> ((T,), (T,)) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_tup2<A, B>(t: (A, B)) -> ((A, B), (A, B)) { + //~^ HELP consider restricting type parameters + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom<T>(t: S<T>) -> (S<T>, S<T>) { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +struct S<T>(T); +trait Trait {} +impl<T: Trait + Clone> Clone for S<T> { + fn clone(&self) -> Self { + Self(self.0.clone()) + } +} +impl<T: Trait + Copy> Copy for S<T> {} + +trait A {} +trait B {} + +// Test where bounds are added with different bound placements +fn duplicate_custom_1<T>(t: S<T>) -> (S<T>, S<T>) where { + //~^ HELP consider restricting type parameter `T` + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>) +where + T: A, + //~^ HELP consider further restricting this bound +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>) +where + T: A, + //~^ HELP consider further restricting this bound + T: B, +{ + (t, t) //~ use of moved value: `t` +} + +fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>) +//~^ HELP consider further restricting this bound +where + T: B, +{ + (t, t) //~ use of moved value: `t` +} + +#[rustfmt::skip] +fn existing_colon<T:>(t: T) { + //~^ HELP consider restricting type parameter `T` + [t, t]; //~ use of moved value: `t` +} + +fn existing_colon_in_where<T>(t: T) +where + T:, + //~^ HELP consider further restricting type parameter `T` +{ + [t, t]; //~ use of moved value: `t` +} + +fn main() {} diff --git a/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr new file mode 100644 index 000000000..3e37fcb21 --- /dev/null +++ b/src/test/ui/moves/use_of_moved_value_copy_suggestions.stderr @@ -0,0 +1,179 @@ +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:6:9 + | +LL | fn duplicate_t<T>(t: T) -> (T, T) { + | - move occurs because `t` has type `T`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_t<T: Copy>(t: T) -> (T, T) { + | ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:11:9 + | +LL | fn duplicate_opt<T>(t: Option<T>) -> (Option<T>, Option<T>) { + | - move occurs because `t` has type `Option<T>`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_opt<T: Copy>(t: Option<T>) -> (Option<T>, Option<T>) { + | ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:16:9 + | +LL | fn duplicate_tup1<T>(t: (T,)) -> ((T,), (T,)) { + | - move occurs because `t` has type `(T,)`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_tup1<T: Copy>(t: (T,)) -> ((T,), (T,)) { + | ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:21:9 + | +LL | fn duplicate_tup2<A, B>(t: (A, B)) -> ((A, B), (A, B)) { + | - move occurs because `t` has type `(A, B)`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameters + | +LL | fn duplicate_tup2<A: Copy, B: Copy>(t: (A, B)) -> ((A, B), (A, B)) { + | ++++++ ++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:26:9 + | +LL | fn duplicate_custom<T>(t: S<T>) -> (S<T>, S<T>) { + | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_custom<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) { + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:44:9 + | +LL | fn duplicate_custom_1<T>(t: S<T>) -> (S<T>, S<T>) where { + | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait +LL | +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn duplicate_custom_1<T: Copy + Trait>(t: S<T>) -> (S<T>, S<T>) where { + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:52:9 + | +LL | fn duplicate_custom_2<T>(t: S<T>) -> (S<T>, S<T>) + | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait +... +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider further restricting this bound + | +LL | T: A + Copy + Trait, + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:61:9 + | +LL | fn duplicate_custom_3<T>(t: S<T>) -> (S<T>, S<T>) + | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait +... +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider further restricting this bound + | +LL | T: A + Copy + Trait, + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:69:9 + | +LL | fn duplicate_custom_4<T: A>(t: S<T>) -> (S<T>, S<T>) + | - move occurs because `t` has type `S<T>`, which does not implement the `Copy` trait +... +LL | (t, t) + | - ^ value used here after move + | | + | value moved here + | +help: consider further restricting this bound + | +LL | fn duplicate_custom_4<T: A + Copy + Trait>(t: S<T>) -> (S<T>, S<T>) + | ++++++++++++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:75:9 + | +LL | fn existing_colon<T:>(t: T) { + | - move occurs because `t` has type `T`, which does not implement the `Copy` trait +LL | +LL | [t, t]; + | - ^ value used here after move + | | + | value moved here + | +help: consider restricting type parameter `T` + | +LL | fn existing_colon<T: Copy>(t: T) { + | ++++ + +error[E0382]: use of moved value: `t` + --> $DIR/use_of_moved_value_copy_suggestions.rs:83:9 + | +LL | fn existing_colon_in_where<T>(t: T) + | - move occurs because `t` has type `T`, which does not implement the `Copy` trait +... +LL | [t, t]; + | - ^ value used here after move + | | + | value moved here + | +help: consider further restricting type parameter `T` + | +LL | T:, T: Copy + | ~~~~~~~~~ + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0382`. |