summaryrefslogtreecommitdiffstats
path: root/tests/ui/pattern/move-ref-patterns
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/pattern/move-ref-patterns
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/pattern/move-ref-patterns')
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs29
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs48
-rw-r--r--tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr216
-rw-r--r--tests/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs12
-rw-r--r--tests/ui/pattern/move-ref-patterns/issue-53840.rs20
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs120
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr404
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs28
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs32
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr63
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.fixed12
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.rs12
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes-fixable.stderr17
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs10
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr17
-rw-r--r--tests/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs79
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);
+}