diff options
Diffstat (limited to 'tests/ui/pattern/move-ref-patterns')
16 files changed, 1119 insertions, 0 deletions
diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs new file mode 100644 index 000000000..5445696fd --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs @@ -0,0 +1,29 @@ +// check-pass + +fn main() {} + +struct U; + +fn slice() { + let mut arr = [U, U, U, U, U, U, U, U]; + let [ref _x0, _x1, _, mut _x3, .., ref _x6, _x7] = arr; + _x3 = U; + let [ref mut _x0, _, ref _x2, _, _x4, ref mut _x5, _x6, _] = arr; + *_x5 = U; + let [_, _, _x2, _, _, _x5, _, _] = arr; + *_x0 = U; + let [ref _x0, ..] = arr; + let [_x0, ..] = arr; +} + +fn tuple() { + let mut tup = (U, U, U, U, U); + let (ref _x0, mut _x1, ref _x2, ..) = tup; + _x1 = U; + let (ref mut _x0, _, _, ref _x3, _x4) = tup; + let (_, _, _, _x3, _) = tup; + *_x0 = U; + drop(_x2); + drop(tup.2); + let (_x0, _, _, ..) = tup; +} diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs new file mode 100644 index 000000000..a6144c949 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs @@ -0,0 +1,48 @@ +fn main() {} + +struct U; + +fn slice() { + let mut arr = [U, U, U, U, U]; + let hold_all = &arr; + let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; //~ ERROR cannot move out of `arr[..]` + _x1 = U; //~ ERROR cannot assign twice to immutable variable `_x1` + drop(hold_all); + let [_x0, ..] = arr; //~ ERROR cannot move out of `arr[..]` + drop(_x0_hold); + let [_, _, ref mut _x2, _x3, mut _x4] = arr; + //~^ ERROR cannot borrow `arr[..]` as mutable + //~| ERROR cannot move out of `arr[..]` because it is borrowed + //~| ERROR cannot move out of `arr[..]` because it is borrowed + drop(xs_hold); +} + +fn tuple() { + let mut tup = (U, U, U, U); + let (ref _x0, _x1, ref _x2, ..) = tup; + _x1 = U; //~ ERROR cannot assign twice to immutable variable + let _x0_hold = &mut tup.0; //~ ERROR cannot borrow `tup.0` as mutable because it is also + let (ref mut _x0_hold, ..) = tup; //~ ERROR cannot borrow `tup.0` as mutable because it is also + *_x0 = U; //~ ERROR cannot assign to `*_x0`, which is behind a `&` reference + *_x2 = U; //~ ERROR cannot assign to `*_x2`, which is behind a `&` reference + drop(tup.1); //~ ERROR use of moved value: `tup.1` + let _x1_hold = &tup.1; //~ ERROR borrow of moved value: `tup.1` + let (.., ref mut _x3) = tup; + let _x3_hold = &tup.3; //~ ERROR cannot borrow `tup.3` as immutable + let _x3_hold = &mut tup.3; //~ ERROR cannot borrow `tup.3` as mutable more + let (.., ref mut _x4_hold) = tup; //~ ERROR cannot borrow `tup.3` as mutable more + let (.., ref _x4_hold) = tup; //~ ERROR cannot borrow `tup.3` as immutable + drop(_x3); +} + +fn closure() { + let mut tup = (U, U, U); + let c1 = || { + let (ref _x0, _x1, _) = tup; + }; + let c2 = || { + //~^ ERROR use of moved value + let (ref mut _x0, _, _x2) = tup; + }; + drop(c1); +} diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr new file mode 100644 index 000000000..1b93267b3 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -0,0 +1,216 @@ +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:8:24 + | +LL | let hold_all = &arr; + | ---- borrow of `arr` occurs here +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ^^^ move out of `arr[..]` occurs here +LL | _x1 = U; +LL | drop(hold_all); + | -------- borrow later used here + +error[E0384]: cannot assign twice to immutable variable `_x1` + --> $DIR/borrowck-move-ref-pattern.rs:9:5 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | --- + | | + | first assignment to `_x1` + | help: consider making this binding mutable: `mut _x1` +LL | _x1 = U; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:11:10 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ------------ borrow of `arr[..]` occurs here +... +LL | let [_x0, ..] = arr; + | ^^^ move out of `arr[..]` occurs here +LL | drop(_x0_hold); + | -------- borrow later used here + +error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-move-ref-pattern.rs:13:16 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ----------- immutable borrow occurs here +... +LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; + | ^^^^^^^^^^^ mutable borrow occurs here +... +LL | drop(xs_hold); + | ------- immutable borrow later used here + +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:13:29 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ----------- borrow of `arr[..]` occurs here +... +LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; + | ^^^ move out of `arr[..]` occurs here +... +LL | drop(xs_hold); + | ------- borrow later used here + +error[E0505]: cannot move out of `arr[..]` because it is borrowed + --> $DIR/borrowck-move-ref-pattern.rs:13:34 + | +LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; + | ----------- borrow of `arr[..]` occurs here +... +LL | let [_, _, ref mut _x2, _x3, mut _x4] = arr; + | ^^^^^^^ move out of `arr[..]` occurs here +... +LL | drop(xs_hold); + | ------- borrow later used here + +error[E0384]: cannot assign twice to immutable variable `_x1` + --> $DIR/borrowck-move-ref-pattern.rs:23:5 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | --- + | | + | first assignment to `_x1` + | help: consider making this binding mutable: `mut _x1` +LL | _x1 = U; + | ^^^^^^^ cannot assign twice to immutable variable + +error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-move-ref-pattern.rs:24:20 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | ------- immutable borrow occurs here +LL | _x1 = U; +LL | let _x0_hold = &mut tup.0; + | ^^^^^^^^^^ mutable borrow occurs here +LL | let (ref mut _x0_hold, ..) = tup; +LL | *_x0 = U; + | -------- immutable borrow later used here + +error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-move-ref-pattern.rs:25:10 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | ------- immutable borrow occurs here +... +LL | let (ref mut _x0_hold, ..) = tup; + | ^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | *_x0 = U; + | -------- immutable borrow later used here + +error[E0594]: cannot assign to `*_x0`, which is behind a `&` reference + --> $DIR/borrowck-move-ref-pattern.rs:26:5 + | +LL | *_x0 = U; + | ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | let (ref mut _x0, _x1, ref _x2, ..) = tup; + | ~~~~~~~~~~~ + +error[E0594]: cannot assign to `*_x2`, which is behind a `&` reference + --> $DIR/borrowck-move-ref-pattern.rs:27:5 + | +LL | *_x2 = U; + | ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written + | +help: consider changing this to be a mutable reference + | +LL | let (ref _x0, _x1, ref mut _x2, ..) = tup; + | ~~~~~~~~~~~ + +error[E0382]: use of moved value: `tup.1` + --> $DIR/borrowck-move-ref-pattern.rs:28:10 + | +LL | let (ref _x0, _x1, ref _x2, ..) = tup; + | --- value moved here +... +LL | drop(tup.1); + | ^^^^^ value used here after move + | + = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait +help: borrow this binding in the pattern to avoid moving the value + | +LL | let (ref _x0, ref _x1, ref _x2, ..) = tup; + | +++ + +error[E0382]: borrow of moved value: `tup.1` + --> $DIR/borrowck-move-ref-pattern.rs:29:20 + | +LL | drop(tup.1); + | ----- value moved here +LL | let _x1_hold = &tup.1; + | ^^^^^^ value borrowed here after move + | + = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait + +error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-move-ref-pattern.rs:31:20 + | +LL | let (.., ref mut _x3) = tup; + | ----------- mutable borrow occurs here +LL | let _x3_hold = &tup.3; + | ^^^^^^ immutable borrow occurs here +... +LL | drop(_x3); + | --- mutable borrow later used here + +error[E0499]: cannot borrow `tup.3` as mutable more than once at a time + --> $DIR/borrowck-move-ref-pattern.rs:32:20 + | +LL | let (.., ref mut _x3) = tup; + | ----------- first mutable borrow occurs here +LL | let _x3_hold = &tup.3; +LL | let _x3_hold = &mut tup.3; + | ^^^^^^^^^^ second mutable borrow occurs here +... +LL | drop(_x3); + | --- first borrow later used here + +error[E0499]: cannot borrow `tup.3` as mutable more than once at a time + --> $DIR/borrowck-move-ref-pattern.rs:33:14 + | +LL | let (.., ref mut _x3) = tup; + | ----------- first mutable borrow occurs here +... +LL | let (.., ref mut _x4_hold) = tup; + | ^^^^^^^^^^^^^^^^ second mutable borrow occurs here +LL | let (.., ref _x4_hold) = tup; +LL | drop(_x3); + | --- first borrow later used here + +error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-move-ref-pattern.rs:34:14 + | +LL | let (.., ref mut _x3) = tup; + | ----------- mutable borrow occurs here +... +LL | let (.., ref _x4_hold) = tup; + | ^^^^^^^^^^^^ immutable borrow occurs here +LL | drop(_x3); + | --- mutable borrow later used here + +error[E0382]: use of moved value: `tup` + --> $DIR/borrowck-move-ref-pattern.rs:43:14 + | +LL | let mut tup = (U, U, U); + | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait +LL | let c1 = || { + | -- value moved into closure here +LL | let (ref _x0, _x1, _) = tup; + | --- variable moved due to use in closure +LL | }; +LL | let c2 = || { + | ^^ value used here after move +LL | +LL | let (ref mut _x0, _, _x2) = tup; + | --- use occurs due to use in closure + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0382, E0384, E0499, E0502, E0505, E0594. +For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs new file mode 100644 index 000000000..ff7b625a6 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs @@ -0,0 +1,12 @@ +// When conflicts between by-move bindings in `by_move_1 @ has_by_move` patterns +// happen and that code is unreachable according to borrowck, we accept this code. +// In particular, we want to ensure here that an ICE does not happen, which it did originally. + +// check-pass + +fn main() { + return; + + struct S; + let a @ (b, c) = (S, S); +} diff --git a/tests/ui/pattern/move-ref-patterns/issue-53840.rs b/tests/ui/pattern/move-ref-patterns/issue-53840.rs new file mode 100644 index 000000000..80effc497 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/issue-53840.rs @@ -0,0 +1,20 @@ +// check-pass + +enum E { + Foo(String, String, String), +} + +struct Bar { + a: String, + b: String, +} + +fn main() { + let bar = Bar { a: "1".to_string(), b: "2".to_string() }; + match E::Foo("".into(), "".into(), "".into()) { + E::Foo(a, b, ref c) => {} + } + match bar { + Bar { a, ref b } => {} + } +} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs new file mode 100644 index 000000000..ebb1683af --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs @@ -0,0 +1,120 @@ +fn main() { + struct S; // Not `Copy`. + + let mut tup0 = (S, S); + let mut tup1 = (S, S, S); + let tup2 = (S, S); + let tup3 = (S, S, S); + let tup4 = (S, S); + let mut arr0 = [S, S, S]; + let mut arr1 = [S, S, S, S, S]; + let arr2 = [S, S, S]; + let arr3 = [S, S, S, S, S]; + + // The `mov` bindings require that we capture the scrutinees by-move. + let mut closure = || { + // Tuples... + let (ref mut borrow, mov) = tup0; + let (mov, _, ref mut borrow) = tup1; + let (ref borrow, mov) = tup2; + let (mov, _, ref borrow) = tup3; + let (ref borrow, mov) = tup4; + // Arrays... + let [mov @ .., ref borrow] = arr0; + let [_, ref mut borrow @ .., _, mov] = arr1; + let [mov @ .., ref borrow] = arr2; + let [_, ref borrow @ .., _, mov] = arr3; + }; + + // Now we try to borrow and move the captures, which should result in errors... + // ...for tuples: + drop(&tup0); //~ ERROR borrow of moved value: `tup0` + drop(&tup1); //~ ERROR borrow of moved value: `tup1` + drop(&tup2); //~ ERROR borrow of moved value: `tup2` + drop(&tup3); //~ ERROR borrow of moved value: `tup3` + // Ostensibly this should compile. + // However, because closures don't capture individual fields, which is changed in RFC 2229, + // this won't compile because the entire product is moved into the closure. + // The same applies to the array patterns below. + drop(&tup4.0); //~ ERROR borrow of moved value: `tup4` + // ...for arrays: + drop(&arr0); //~ ERROR borrow of moved value: `arr0` + let [_, mov1, mov2, mov3, _] = &arr1; //~ ERROR borrow of moved value: `arr1` + drop(&arr2); //~ ERROR borrow of moved value: `arr2` + let [_, mov1, mov2, mov3, _] = &arr3; //~ ERROR borrow of moved value: `arr3` + + // Let's redo ^--- with a `match` + sum type: + macro_rules! m { + ($p:pat = $s:expr) => { + match $s { + Some($p) => {} + _ => {} + } + }; + } + let mut tup0: Option<(S, S)> = None; + let mut tup1: Option<(S, S, S)> = None; + let tup2: Option<(S, S)> = None; + let tup3: Option<(S, S, S)> = None; + let tup4: Option<(S, S)> = None; + let mut arr0: Option<[S; 3]> = None; + let mut arr1: Option<[S; 5]> = None; + let arr2: Option<[S; 3]> = None; + let arr3: Option<[S; 5]> = None; + let mut closure = || { + m!((ref mut borrow, mov) = tup0); + m!((mov, _, ref mut borrow) = tup1); + m!((ref borrow, mov) = tup2); + m!((mov, _, ref borrow) = tup3); + m!((ref borrow, mov) = tup4); + m!([mov @ .., ref borrow] = arr0); + m!([_, ref mut borrow @ .., _, mov] = arr1); + m!([mov @ .., ref borrow] = arr2); + m!([_, ref borrow @ .., _, mov] = arr3); + }; + drop(&tup0); //~ ERROR borrow of moved value: `tup0` + drop(&tup1); //~ ERROR borrow of moved value: `tup1` + drop(&tup2); //~ ERROR borrow of moved value: `tup2` + drop(&tup3); //~ ERROR borrow of moved value: `tup3` + m!((ref x, _) = &tup4); //~ ERROR borrow of moved value: `tup4` + drop(&arr0); //~ ERROR borrow of moved value: `arr0` + m!([_, mov1, mov2, mov3, _] = &arr1); //~ ERROR borrow of moved value: `arr1` + drop(&arr2); //~ ERROR borrow of moved value: `arr2` + m!([_, mov1, mov2, mov3, _] = &arr3); //~ ERROR borrow of moved value: `arr3` + + // Let's redo ^--- with `if let` (which may diverge from `match` in the future): + macro_rules! m { + ($p:pat = $s:expr) => { + if let Some($p) = $s {} + }; + } + let mut tup0: Option<(S, S)> = None; + let mut tup1: Option<(S, S, S)> = None; + let tup2: Option<(S, S)> = None; + let tup3: Option<(S, S, S)> = None; + let tup4: Option<(S, S)> = None; + let mut arr0: Option<[S; 3]> = None; + let mut arr1: Option<[S; 5]> = None; + let arr2: Option<[S; 3]> = None; + let arr3: Option<[S; 5]> = None; + let mut closure = || { + m!((ref mut borrow, mov) = tup0); + m!((mov, _, ref mut borrow) = tup1); + m!((ref borrow, mov) = tup2); + m!((mov, _, ref borrow) = tup3); + m!((ref borrow, mov) = tup4); + m!([mov @ .., ref borrow] = arr0); + m!([_, ref mut borrow @ .., _, mov] = arr1); + m!([mov @ .., ref borrow] = arr2); + m!([_, ref borrow @ .., _, mov] = arr3); + }; + drop(&tup0); //~ ERROR borrow of moved value: `tup0` + drop(&tup1); //~ ERROR borrow of moved value: `tup1` + drop(&tup2); //~ ERROR borrow of moved value: `tup2` + drop(&tup3); //~ ERROR borrow of moved value: `tup3` + m!((ref x, _) = &tup4); //~ ERROR borrow of moved value: `tup4` + drop(&arr0); //~ ERROR borrow of moved value: `arr0` + m!([_, mov1, mov2, mov3, _] = &arr1); //~ ERROR borrow of moved value: `arr1` + drop(&arr2); //~ ERROR borrow of moved value: `arr2` + m!([_, mov1, mov2, mov3, _] = &arr3); //~ ERROR borrow of moved value: `arr3` +} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr new file mode 100644 index 000000000..f19fed089 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -0,0 +1,404 @@ +error[E0382]: borrow of moved value: `tup0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10 + | +LL | let mut tup0 = (S, S); + | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | // Tuples... +LL | let (ref mut borrow, mov) = tup0; + | ---- variable moved due to use in closure +... +LL | drop(&tup0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10 + | +LL | let mut tup1 = (S, S, S); + | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (mov, _, ref mut borrow) = tup1; + | ---- variable moved due to use in closure +... +LL | drop(&tup1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 + | +LL | let tup2 = (S, S); + | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (ref borrow, mov) = tup2; + | ---- variable moved due to use in closure +... +LL | drop(&tup2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 + | +LL | let tup3 = (S, S, S); + | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (mov, _, ref borrow) = tup3; + | ---- variable moved due to use in closure +... +LL | drop(&tup3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup4` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10 + | +LL | let tup4 = (S, S); + | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let (ref borrow, mov) = tup4; + | ---- variable moved due to use in closure +... +LL | drop(&tup4.0); + | ^^^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 + | +LL | let mut arr0 = [S, S, S]; + | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [mov @ .., ref borrow] = arr0; + | ---- variable moved due to use in closure +... +LL | drop(&arr0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36 + | +LL | let mut arr1 = [S, S, S, S, S]; + | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [_, ref mut borrow @ .., _, mov] = arr1; + | ---- variable moved due to use in closure +... +LL | let [_, mov1, mov2, mov3, _] = &arr1; + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 + | +LL | let arr2 = [S, S, S]; + | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [mov @ .., ref borrow] = arr2; + | ---- variable moved due to use in closure +... +LL | drop(&arr2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 + | +LL | let arr3 = [S, S, S, S, S]; + | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | let [_, ref borrow @ .., _, mov] = arr3; + | ---- variable moved due to use in closure +... +LL | let [_, mov1, mov2, mov3, _] = &arr3; + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10 + | +LL | let mut tup0: Option<(S, S)> = None; + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); + | ---- variable moved due to use in closure +... +LL | drop(&tup0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10 + | +LL | let mut tup1: Option<(S, S, S)> = None; + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); +LL | m!((mov, _, ref mut borrow) = tup1); + | ---- variable moved due to use in closure +... +LL | drop(&tup1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 + | +LL | let tup2: Option<(S, S)> = None; + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup2); + | ---- variable moved due to use in closure +... +LL | drop(&tup2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 + | +LL | let tup3: Option<(S, S, S)> = None; + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((mov, _, ref borrow) = tup3); + | ---- variable moved due to use in closure +... +LL | drop(&tup3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup4` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21 + | +LL | let tup4: Option<(S, S)> = None; + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup4); + | ---- variable moved due to use in closure +... +LL | m!((ref x, _) = &tup4); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 + | +LL | let mut arr0: Option<[S; 3]> = None; + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr0); + | ---- variable moved due to use in closure +... +LL | drop(&arr0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35 + | +LL | let mut arr1: Option<[S; 5]> = None; + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref mut borrow @ .., _, mov] = arr1); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 + | +LL | let arr2: Option<[S; 3]> = None; + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +LL | let arr3: Option<[S; 5]> = None; +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr2); + | ---- variable moved due to use in closure +... +LL | drop(&arr2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 + | +LL | let arr3: Option<[S; 5]> = None; + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref borrow @ .., _, mov] = arr3); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10 + | +LL | let mut tup0: Option<(S, S)> = None; + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); + | ---- variable moved due to use in closure +... +LL | drop(&tup0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10 + | +LL | let mut tup1: Option<(S, S, S)> = None; + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +LL | m!((ref mut borrow, mov) = tup0); +LL | m!((mov, _, ref mut borrow) = tup1); + | ---- variable moved due to use in closure +... +LL | drop(&tup1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 + | +LL | let tup2: Option<(S, S)> = None; + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup2); + | ---- variable moved due to use in closure +... +LL | drop(&tup2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 + | +LL | let tup3: Option<(S, S, S)> = None; + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((mov, _, ref borrow) = tup3); + | ---- variable moved due to use in closure +... +LL | drop(&tup3); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `tup4` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21 + | +LL | let tup4: Option<(S, S)> = None; + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!((ref borrow, mov) = tup4); + | ---- variable moved due to use in closure +... +LL | m!((ref x, _) = &tup4); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr0` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 + | +LL | let mut arr0: Option<[S; 3]> = None; + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr0); + | ---- variable moved due to use in closure +... +LL | drop(&arr0); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr1` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35 + | +LL | let mut arr1: Option<[S; 5]> = None; + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +... +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref mut borrow @ .., _, mov] = arr1); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr1); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr2` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 + | +LL | let arr2: Option<[S; 3]> = None; + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait +LL | let arr3: Option<[S; 5]> = None; +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([mov @ .., ref borrow] = arr2); + | ---- variable moved due to use in closure +... +LL | drop(&arr2); + | ^^^^^ value borrowed here after move + +error[E0382]: borrow of moved value: `arr3` + --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 + | +LL | let arr3: Option<[S; 5]> = None; + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait +LL | let mut closure = || { + | -- value moved into closure here +... +LL | m!([_, ref borrow @ .., _, mov] = arr3); + | ---- variable moved due to use in closure +... +LL | m!([_, mov1, mov2, mov3, _] = &arr3); + | ^^^^^ value borrowed here after move + +error: aborting due to 27 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs new file mode 100644 index 000000000..583f70f41 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs @@ -0,0 +1,28 @@ +// check-pass + +fn main() { + struct U; + fn accept_fn_once(_: impl FnOnce()) {} + fn accept_fn_mut(_: impl FnMut()) {} + fn accept_fn(_: impl Fn()) {} + + let mut tup = (U, U, U); + let (ref _x0, _x1, ref mut _x2) = tup; + let c1 = || { + drop::<&U>(_x0); + drop::<U>(_x1); + drop::<&mut U>(_x2); + }; + accept_fn_once(c1); + + let c2 = || { + drop::<&U>(_x0); + drop::<&mut U>(_x2); + }; + accept_fn_mut(c2); + + let c3 = || { + drop::<&U>(_x0); + }; + accept_fn(c3); +} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs new file mode 100644 index 000000000..cd619cc41 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs @@ -0,0 +1,32 @@ +fn main() { + struct U; + fn accept_fn_once(_: &impl FnOnce()) {} + fn accept_fn_mut(_: &impl FnMut()) {} + fn accept_fn(_: &impl Fn()) {} + + let mut tup = (U, U, U); + let (ref _x0, _x1, ref mut _x2) = tup; + let c1 = || { + //~^ ERROR expected a closure that implements the `FnMut` + //~| ERROR expected a closure that implements the `Fn` + drop::<&U>(_x0); + drop::<U>(_x1); + drop::<&mut U>(_x2); + }; + accept_fn_once(&c1); + accept_fn_mut(&c1); + accept_fn(&c1); + + let c2 = || { + //~^ ERROR expected a closure that implements the `Fn` + drop::<&U>(_x0); + drop::<&mut U>(_x2); + }; + accept_fn_mut(&c2); + accept_fn(&c2); + + let c3 = || { + drop::<&U>(_x0); + }; + accept_fn(&c3); +} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr new file mode 100644 index 000000000..eba65a618 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr @@ -0,0 +1,63 @@ +error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce` + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 + | +LL | let c1 = || { + | ^^ this closure implements `FnOnce`, not `FnMut` +... +LL | drop::<U>(_x1); + | --- closure is `FnOnce` because it moves the variable `_x1` out of its environment +... +LL | accept_fn_mut(&c1); + | ------------- --- the requirement to implement `FnMut` derives from here + | | + | required by a bound introduced by this call + | +note: required by a bound in `accept_fn_mut` + --> $DIR/move-ref-patterns-closure-captures.rs:4:31 + | +LL | fn accept_fn_mut(_: &impl FnMut()) {} + | ^^^^^^^ required by this bound in `accept_fn_mut` + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 + | +LL | let c1 = || { + | ^^ this closure implements `FnOnce`, not `Fn` +... +LL | drop::<U>(_x1); + | --- closure is `FnOnce` because it moves the variable `_x1` out of its environment +... +LL | accept_fn(&c1); + | --------- --- the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | +note: required by a bound in `accept_fn` + --> $DIR/move-ref-patterns-closure-captures.rs:5:27 + | +LL | fn accept_fn(_: &impl Fn()) {} + | ^^^^ required by this bound in `accept_fn` + +error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` + --> $DIR/move-ref-patterns-closure-captures.rs:20:14 + | +LL | let c2 = || { + | ^^ this closure implements `FnMut`, not `Fn` +... +LL | drop::<&mut U>(_x2); + | --- closure is `FnMut` because it mutates the variable `_x2` here +... +LL | accept_fn(&c2); + | --------- --- the requirement to implement `Fn` derives from here + | | + | required by a bound introduced by this call + | +note: required by a bound in `accept_fn` + --> $DIR/move-ref-patterns-closure-captures.rs:5:27 + | +LL | fn accept_fn(_: &impl Fn()) {} + | ^^^^ required by this bound in `accept_fn` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0525`. diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed new file mode 100644 index 000000000..5f04fc83d --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed @@ -0,0 +1,12 @@ +// run-rustfix +#![allow(unused_variables)] +fn main() { + struct U; + + // A tuple is a "non-reference pattern". + // A `mut` binding pattern resets the binding mode to by-value. + + let mut p = (U, U); + let (a, ref mut b) = &mut p; + //~^ ERROR cannot move out of a mutable reference +} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs new file mode 100644 index 000000000..5dc1ae2fe --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs @@ -0,0 +1,12 @@ +// run-rustfix +#![allow(unused_variables)] +fn main() { + struct U; + + // A tuple is a "non-reference pattern". + // A `mut` binding pattern resets the binding mode to by-value. + + let mut p = (U, U); + let (a, mut b) = &mut p; + //~^ ERROR cannot move out of a mutable reference +} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr new file mode 100644 index 000000000..d3ab533e3 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of a mutable reference + --> $DIR/move-ref-patterns-default-binding-modes-fixable.rs:10:22 + | +LL | let (a, mut b) = &mut p; + | ----- ^^^^^^ + | | + | data moved here + | move occurs because `b` has type `U`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let (a, ref mut b) = &mut p; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs new file mode 100644 index 000000000..6c913c245 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs @@ -0,0 +1,10 @@ +fn main() { + struct U; + + // A tuple is a "non-reference pattern". + // A `mut` binding pattern resets the binding mode to by-value. + + let p = (U, U); + let (a, mut b) = &p; + //~^ ERROR cannot move out of a shared reference +} diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr new file mode 100644 index 000000000..65030b622 --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -0,0 +1,17 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22 + | +LL | let (a, mut b) = &p; + | ----- ^^ + | | + | data moved here + | move occurs because `b` has type `U`, which does not implement the `Copy` trait + | +help: consider borrowing the pattern binding + | +LL | let (a, ref mut b) = &p; + | +++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs new file mode 100644 index 000000000..1d6d9acea --- /dev/null +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs @@ -0,0 +1,79 @@ +// run-pass + +// This test checks the dynamic semantics and drop order of pattern matching +// where a product pattern has both a by-move and by-ref binding. + +use std::cell::RefCell; +use std::rc::Rc; + +struct X { + x: Box<usize>, + d: DropOrderListPtr, +} + +type DropOrderListPtr = Rc<RefCell<Vec<usize>>>; + +impl Drop for X { + fn drop(&mut self) { + self.d.borrow_mut().push(*self.x); + } +} + +enum DoubleOption<T, U> { + Some2(T, U), + _None2, +} + +fn main() { + let d: DropOrderListPtr = <_>::default(); + { + let mk = |v| X { x: Box::new(v), d: d.clone() }; + let check = |a1: &X, a2, b1: &X, b2| { + assert_eq!(*a1.x, a2); + assert_eq!(*b1.x, b2); + }; + + let x = DoubleOption::Some2(mk(1), mk(2)); + match x { + DoubleOption::Some2(ref a, b) => check(a, 1, &b, 2), + DoubleOption::_None2 => panic!(), + } + let x = DoubleOption::Some2(mk(3), mk(4)); + match x { + DoubleOption::Some2(a, ref b) => check(&a, 3, b, 4), + DoubleOption::_None2 => panic!(), + } + match DoubleOption::Some2(mk(5), mk(6)) { + DoubleOption::Some2(ref a, b) => check(a, 5, &b, 6), + DoubleOption::_None2 => panic!(), + } + match DoubleOption::Some2(mk(7), mk(8)) { + DoubleOption::Some2(a, ref b) => check(&a, 7, b, 8), + DoubleOption::_None2 => panic!(), + } + { + let (a, ref b) = (mk(9), mk(10)); + let (ref c, d) = (mk(11), mk(12)); + check(&a, 9, b, 10); + check(c, 11, &d, 12); + } + fn fun([a, ref mut b, ref xs @ .., ref c, d]: [X; 6]) { + assert_eq!(*a.x, 13); + assert_eq!(*b.x, 14); + assert_eq!(&[*xs[0].x, *xs[1].x], &[15, 16]); + assert_eq!(*c.x, 17); + assert_eq!(*d.x, 18); + } + fun([mk(13), mk(14), mk(15), mk(16), mk(17), mk(18)]); + + let lam = |(a, ref b, c, ref mut d): (X, X, X, X)| { + assert_eq!(*a.x, 19); + assert_eq!(*b.x, 20); + assert_eq!(*c.x, 21); + assert_eq!(*d.x, 22); + }; + lam((mk(19), mk(20), mk(21), mk(22))); + } + let expected = [2, 3, 6, 5, 7, 8, 12, 11, 9, 10, 18, 13, 14, 15, 16, 17, 21, 19, 20, 22, 4, 1]; + assert_eq!(&*d.borrow(), &expected); +} |