about summary refs log tree commit diff
path: root/src/test/ui/pattern/move-ref-patterns
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-02-09 04:01:28 +0000
committerbors <bors@rust-lang.org>2020-02-09 04:01:28 +0000
commitf8d830b4decaef5a6ae0f27baac14dfb48baa4c5 (patch)
treea5e7a6a7f68e12dbd174c1313b4d0ab0e742dbdc /src/test/ui/pattern/move-ref-patterns
parenta19edd6b161521a4f66716b3b45b8cf4d3f03f3a (diff)
parentd2b88b7050b0e21b136022c4cfe8d352c1425588 (diff)
downloadrust-f8d830b4decaef5a6ae0f27baac14dfb48baa4c5.tar.gz
rust-f8d830b4decaef5a6ae0f27baac14dfb48baa4c5.zip
Auto merge of #68376 - Centril:move-ref-patterns, r=matthewjasper
Initial implementation of `#![feature(move_ref_pattern)]`

Following up on #45600, under the gate `#![feature(move_ref_pattern)]`, `(ref x, mut y)` is allowed subject to restrictions necessary for soundness. The match checking implementation and tests for `#![feature(bindings_after_at)]` is also adjusted as necessary.

Closes #45600.
Tracking issue: #68354.

r? @matthewjasper
Diffstat (limited to 'src/test/ui/pattern/move-ref-patterns')
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs31
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs50
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr208
-rw-r--r--src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs15
-rw-r--r--src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs23
-rw-r--r--src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr66
-rw-r--r--src/test/ui/pattern/move-ref-patterns/issue-53840.rs22
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs122
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr404
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs30
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs34
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr39
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs16
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr21
-rw-r--r--src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs81
15 files changed, 1162 insertions, 0 deletions
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
new file mode 100644
index 00000000000..d2d4e61e049
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs
@@ -0,0 +1,31 @@
+// check-pass
+
+#![feature(move_ref_pattern)]
+
+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/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
new file mode 100644
index 00000000000..3ee008fd84f
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs
@@ -0,0 +1,50 @@
+#![feature(move_ref_pattern)]
+
+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/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
new file mode 100644
index 00000000000..d718ee29cf9
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -0,0 +1,208 @@
+error[E0505]: cannot move out of `arr[..]` because it is borrowed
+  --> $DIR/borrowck-move-ref-pattern.rs:10: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:11:5
+   |
+LL |     let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr;
+   |                        ---
+   |                        |
+   |                        first assignment to `_x1`
+   |                        help: make 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:13: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:15: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:15: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:15: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:25:5
+   |
+LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
+   |                   ---
+   |                   |
+   |                   first assignment to `_x1`
+   |                   help: make 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:26: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:27: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:28:5
+   |
+LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
+   |          ------- help: consider changing this to be a mutable reference: `ref mut _x0`
+...
+LL |     *_x0 = U;
+   |     ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written
+
+error[E0594]: cannot assign to `*_x2` which is behind a `&` reference
+  --> $DIR/borrowck-move-ref-pattern.rs:29:5
+   |
+LL |     let (ref _x0, _x1, ref _x2, ..) = tup;
+   |                        ------- help: consider changing this to be a mutable reference: `ref mut _x2`
+...
+LL |     *_x2 = U;
+   |     ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written
+
+error[E0382]: use of moved value: `tup.1`
+  --> $DIR/borrowck-move-ref-pattern.rs:30: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
+
+error[E0382]: borrow of moved value: `tup.1`
+  --> $DIR/borrowck-move-ref-pattern.rs:31: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:33: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:34: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:35: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:36: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:45: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/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
new file mode 100644
index 00000000000..08fb5cd2e16
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs
@@ -0,0 +1,15 @@
+// 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
+
+#![feature(move_ref_pattern)]
+#![feature(bindings_after_at)]
+
+fn main() {
+    return;
+
+    struct S;
+    let a @ (b, c) = (S, S);
+}
diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs
new file mode 100644
index 00000000000..fb92eb1ba32
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs
@@ -0,0 +1,23 @@
+fn main() {
+    #[derive(Clone)]
+    struct X {
+        x: (),
+    }
+    let mut tup = (X { x: () }, X { x: () });
+    match Some(tup.clone()) {
+        Some((y, ref z)) => {}
+        //~^ ERROR binding by-move and by-ref in the same pattern is unstable
+        None => panic!(),
+    }
+
+    let (ref a, b) = tup.clone();
+    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
+
+    let (a, mut b) = &tup;
+    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
+    //~| ERROR cannot move out of a shared reference
+
+    let (mut a, b) = &mut tup;
+    //~^ ERROR binding by-move and by-ref in the same pattern is unstable
+    //~| ERROR cannot move out of a mutable reference
+}
diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr
new file mode 100644
index 00000000000..8aef220c375
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr
@@ -0,0 +1,66 @@
+error[E0658]: binding by-move and by-ref in the same pattern is unstable
+  --> $DIR/feature-gate-move_ref_pattern.rs:8:15
+   |
+LL |         Some((y, ref z)) => {}
+   |               ^  ----- by-ref pattern here
+   |               |
+   |               by-move pattern here
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/68354
+   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
+
+error[E0658]: binding by-move and by-ref in the same pattern is unstable
+  --> $DIR/feature-gate-move_ref_pattern.rs:13:17
+   |
+LL |     let (ref a, b) = tup.clone();
+   |          -----  ^ by-move pattern here
+   |          |
+   |          by-ref pattern here
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/68354
+   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
+
+error[E0658]: binding by-move and by-ref in the same pattern is unstable
+  --> $DIR/feature-gate-move_ref_pattern.rs:16:13
+   |
+LL |     let (a, mut b) = &tup;
+   |          -  ^^^^^ by-move pattern here
+   |          |
+   |          by-ref pattern here
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/68354
+   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
+
+error[E0658]: binding by-move and by-ref in the same pattern is unstable
+  --> $DIR/feature-gate-move_ref_pattern.rs:20:10
+   |
+LL |     let (mut a, b) = &mut tup;
+   |          ^^^^^  - by-ref pattern here
+   |          |
+   |          by-move pattern here
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/68354
+   = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable
+
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/feature-gate-move_ref_pattern.rs:16:22
+   |
+LL |     let (a, mut b) = &tup;
+   |             -----    ^^^^
+   |             |
+   |             data moved here
+   |             move occurs because `b` has type `main::X`, which does not implement the `Copy` trait
+
+error[E0507]: cannot move out of a mutable reference
+  --> $DIR/feature-gate-move_ref_pattern.rs:20:22
+   |
+LL |     let (mut a, b) = &mut tup;
+   |          -----       ^^^^^^^^
+   |          |
+   |          data moved here
+   |          move occurs because `a` has type `main::X`, which does not implement the `Copy` trait
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0507, E0658.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
new file mode 100644
index 00000000000..ab7d10d9f83
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs
@@ -0,0 +1,22 @@
+// check-pass
+
+#![feature(move_ref_pattern)]
+
+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/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
new file mode 100644
index 00000000000..4c3ca62e165
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs
@@ -0,0 +1,122 @@
+#![feature(move_ref_pattern)]
+
+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/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr
new file mode 100644
index 00000000000..9159e3e2213
--- /dev/null
+++ b/src/test/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:33:10
+   |
+LL |     let mut tup0 = (S, S);
+   |         -------- move occurs because `tup0` has type `(main::S, main::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:34:10
+   |
+LL |     let mut tup1 = (S, S, S);
+   |         -------- move occurs because `tup1` has type `(main::S, main::S, main::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:35:10
+   |
+LL |     let tup2 = (S, S);
+   |         ---- move occurs because `tup2` has type `(main::S, main::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:36:10
+   |
+LL |     let tup3 = (S, S, S);
+   |         ---- move occurs because `tup3` has type `(main::S, main::S, main::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:41:10
+   |
+LL |     let tup4 = (S, S);
+   |         ---- move occurs because `tup4` has type `(main::S, main::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:43:10
+   |
+LL |     let mut arr0 = [S, S, S];
+   |         -------- move occurs because `arr0` has type `[main::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:44:36
+   |
+LL |     let mut arr1 = [S, S, S, S, S];
+   |         -------- move occurs because `arr1` has type `[main::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:45:10
+   |
+LL |     let arr2 = [S, S, S];
+   |         ---- move occurs because `arr2` has type `[main::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:46:36
+   |
+LL |     let arr3 = [S, S, S, S, S];
+   |         ---- move occurs because `arr3` has type `[main::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:77:10
+   |
+LL |     let mut tup0: Option<(S, S)> = None;
+   |         -------- move occurs because `tup0` has type `std::option::Option<(main::S, main::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:78:10
+   |
+LL |     let mut tup1: Option<(S, S, S)> = None;
+   |         -------- move occurs because `tup1` has type `std::option::Option<(main::S, main::S, main::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:79:10
+   |
+LL |     let tup2: Option<(S, S)> = None;
+   |         ---- move occurs because `tup2` has type `std::option::Option<(main::S, main::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:80:10
+   |
+LL |     let tup3: Option<(S, S, S)> = None;
+   |         ---- move occurs because `tup3` has type `std::option::Option<(main::S, main::S, main::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:81:21
+   |
+LL |     let tup4: Option<(S, S)> = None;
+   |         ---- move occurs because `tup4` has type `std::option::Option<(main::S, main::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:82:10
+   |
+LL |     let mut arr0: Option<[S; 3]> = None;
+   |         -------- move occurs because `arr0` has type `std::option::Option<[main::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:83:35
+   |
+LL |     let mut arr1: Option<[S; 5]> = None;
+   |         -------- move occurs because `arr1` has type `std::option::Option<[main::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:84:10
+   |
+LL |     let arr2: Option<[S; 3]> = None;
+   |         ---- move occurs because `arr2` has type `std::option::Option<[main::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:85:35
+   |
+LL |     let arr3: Option<[S; 5]> = None;
+   |         ---- move occurs because `arr3` has type `std::option::Option<[main::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:113:10
+   |
+LL |     let mut tup0: Option<(S, S)> = None;
+   |         -------- move occurs because `tup0` has type `std::option::Option<(main::S, main::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:114:10
+   |
+LL |     let mut tup1: Option<(S, S, S)> = None;
+   |         -------- move occurs because `tup1` has type `std::option::Option<(main::S, main::S, main::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:115:10
+   |
+LL |     let tup2: Option<(S, S)> = None;
+   |         ---- move occurs because `tup2` has type `std::option::Option<(main::S, main::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:116:10
+   |
+LL |     let tup3: Option<(S, S, S)> = None;
+   |         ---- move occurs because `tup3` has type `std::option::Option<(main::S, main::S, main::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:117:21
+   |
+LL |     let tup4: Option<(S, S)> = None;
+   |         ---- move occurs because `tup4` has type `std::option::Option<(main::S, main::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:118:10
+   |
+LL |     let mut arr0: Option<[S; 3]> = None;
+   |         -------- move occurs because `arr0` has type `std::option::Option<[main::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:119:35
+   |
+LL |     let mut arr1: Option<[S; 5]> = None;
+   |         -------- move occurs because `arr1` has type `std::option::Option<[main::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:120:10
+   |
+LL |     let arr2: Option<[S; 3]> = None;
+   |         ---- move occurs because `arr2` has type `std::option::Option<[main::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:121:35
+   |
+LL |     let arr3: Option<[S; 5]> = None;
+   |         ---- move occurs because `arr3` has type `std::option::Option<[main::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/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
new file mode 100644
index 00000000000..e1844d36e4a
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs
@@ -0,0 +1,30 @@
+// check-pass
+
+#![feature(move_ref_pattern)]
+
+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/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
new file mode 100644
index 00000000000..7f1c02c05cb
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs
@@ -0,0 +1,34 @@
+#![feature(move_ref_pattern)]
+
+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/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
new file mode 100644
index 00000000000..ca82353c1c9
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr
@@ -0,0 +1,39 @@
+error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce`
+  --> $DIR/move-ref-patterns-closure-captures.rs:11: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
+
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/move-ref-patterns-closure-captures.rs:11: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
+
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut`
+  --> $DIR/move-ref-patterns-closure-captures.rs:22: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
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
new file mode 100644
index 00000000000..5c51c47d979
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs
@@ -0,0 +1,16 @@
+#![feature(move_ref_pattern)]
+
+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
+
+    let mut p = (U, U);
+    let (a, mut b) = &mut p;
+    //~^ ERROR cannot move out of a mutable reference
+}
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
new file mode 100644
index 00000000000..fe7f71e6c46
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr
@@ -0,0 +1,21 @@
+error[E0507]: cannot move out of a shared reference
+  --> $DIR/move-ref-patterns-default-binding-modes.rs:10:22
+   |
+LL |     let (a, mut b) = &p;
+   |             -----    ^^
+   |             |
+   |             data moved here
+   |             move occurs because `b` has type `main::U`, which does not implement the `Copy` trait
+
+error[E0507]: cannot move out of a mutable reference
+  --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22
+   |
+LL |     let (a, mut b) = &mut p;
+   |             -----    ^^^^^^
+   |             |
+   |             data moved here
+   |             move occurs because `b` has type `main::U`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0507`.
diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
new file mode 100644
index 00000000000..c78695390b5
--- /dev/null
+++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs
@@ -0,0 +1,81 @@
+// 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.
+
+#![feature(move_ref_pattern)]
+
+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);
+}