summaryrefslogtreecommitdiffstats
path: root/tests/ui/pattern/bindings-after-at
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:03 +0000
commit64d98f8ee037282c35007b64c2649055c56af1db (patch)
tree5492bcf97fce41ee1c0b1cc2add283f3e66cdab0 /tests/ui/pattern/bindings-after-at
parentAdding debian version 1.67.1+dfsg1-1. (diff)
downloadrustc-64d98f8ee037282c35007b64c2649055c56af1db.tar.xz
rustc-64d98f8ee037282c35007b64c2649055c56af1db.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/pattern/bindings-after-at')
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-copy.rs47
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs37
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr79
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs11
-rw-r--r--tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr13
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs31
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr112
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs84
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs69
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr145
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs49
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs7
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr17
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs80
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr487
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs82
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr375
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs45
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs136
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr445
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs109
-rw-r--r--tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr359
-rw-r--r--tests/ui/pattern/bindings-after-at/box-patterns.rs35
-rw-r--r--tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs14
-rw-r--r--tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr17
-rw-r--r--tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs48
-rw-r--r--tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr68
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs12
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs11
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr25
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs11
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr15
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-patterns.rs14
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs33
-rw-r--r--tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr26
-rw-r--r--tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs43
-rw-r--r--tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs54
-rw-r--r--tests/ui/pattern/bindings-after-at/or-patterns.rs38
-rw-r--r--tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs29
-rw-r--r--tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr64
-rw-r--r--tests/ui/pattern/bindings-after-at/slice-patterns.rs39
-rw-r--r--tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs16
-rw-r--r--tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr43
43 files changed, 3474 insertions, 0 deletions
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-copy.rs b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs
new file mode 100644
index 000000000..2b349f0ed
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-copy.rs
@@ -0,0 +1,47 @@
+// run-pass
+
+// Test copy
+
+struct A { a: i32, b: i32 }
+struct B { a: i32, b: C }
+struct D { a: i32, d: C }
+#[derive(Copy,Clone)]
+struct C { c: i32 }
+
+pub fn main() {
+ match (A {a: 10, b: 20}) {
+ x@A {a, b: 20} => { assert!(x.a == 10); assert!(a == 10); }
+ A {b: _b, ..} => { panic!(); }
+ }
+
+ let mut x@B {b, ..} = B {a: 10, b: C {c: 20}};
+ assert_eq!(x.a, 10);
+ x.b.c = 30;
+ assert_eq!(b.c, 20);
+ let mut y@D {d, ..} = D {a: 10, d: C {c: 20}};
+ assert_eq!(y.a, 10);
+ y.d.c = 30;
+ assert_eq!(d.c, 20);
+
+ let some_b = Some(B { a: 10, b: C { c: 20 } });
+
+ // in irrefutable pattern
+ if let Some(x @ B { b, .. }) = some_b {
+ assert_eq!(x.b.c, 20);
+ assert_eq!(b.c, 20);
+ } else {
+ unreachable!();
+ }
+
+ let some_b = Some(B { a: 10, b: C { c: 20 } });
+
+ if let Some(x @ B { b: mut b @ C { c }, .. }) = some_b {
+ assert_eq!(x.b.c, 20);
+ assert_eq!(b.c, 20);
+ b.c = 30;
+ assert_eq!(b.c, 30);
+ assert_eq!(c, 20);
+ } else {
+ unreachable!();
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
new file mode 100644
index 000000000..9d1f08d6e
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
@@ -0,0 +1,37 @@
+// This test is taken directly from #16053.
+// It checks that you cannot use an AND-pattern (`binding @ pat`)
+// where one side is by-ref and the other is by-move.
+
+struct X {
+ x: (),
+}
+
+fn main() {
+ let x = Some(X { x: () });
+ match x {
+ Some(ref _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ None => panic!(),
+ }
+
+ let x = Some(X { x: () });
+ match x {
+ Some(_z @ ref _y) => {}
+ //~^ ERROR borrow of moved value
+ None => panic!(),
+ }
+
+ let mut x = Some(X { x: () });
+ match x {
+ Some(ref mut _y @ _z) => {} //~ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ None => panic!(),
+ }
+
+ let mut x = Some(X { x: () });
+ match x {
+ Some(_z @ ref mut _y) => {}
+ //~^ ERROR borrow of moved value
+ None => panic!(),
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
new file mode 100644
index 000000000..c8b45fd24
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -0,0 +1,79 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
+ |
+LL | Some(ref _y @ _z) => {}
+ | ------^^^--
+ | | |
+ | | value moved into `_z` here
+ | value borrowed, by `_y`, here
+
+error: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:19:14
+ |
+LL | Some(_z @ ref _y) => {}
+ | --^^^------
+ | | |
+ | | value borrowed here after move
+ | value moved into `_z` here
+ | move occurs because `_z` has type `X` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref _z @ ref _y) => {}
+ | +++
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
+ |
+LL | Some(ref mut _y @ _z) => {}
+ | ----------^^^--
+ | | |
+ | | value moved into `_z` here
+ | value borrowed, by `_y`, here
+
+error: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:33:14
+ |
+LL | Some(_z @ ref mut _y) => {}
+ | --^^^----------
+ | | |
+ | | value borrowed here after move
+ | value moved into `_z` here
+ | move occurs because `_z` has type `X` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref _z @ ref mut _y) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
+ |
+LL | Some(ref _y @ _z) => {}
+ | ^^^^^^ -- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref _y @ ref _z) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
+ |
+LL | Some(ref mut _y @ _z) => {}
+ | ^^^^^^^^^^ -- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `X`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Some(ref mut _y @ ref _z) => {}
+ | +++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
new file mode 100644
index 000000000..1816a74a0
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
@@ -0,0 +1,11 @@
+// See issue #12534.
+
+fn main() {}
+
+struct A(Box<u8>);
+
+fn f(a @ A(u): A) -> Box<u8> {
+ //~^ ERROR use of partially moved value
+ drop(a);
+ u
+}
diff --git a/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
new file mode 100644
index 000000000..a481ca468
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
@@ -0,0 +1,13 @@
+error[E0382]: use of partially moved value
+ --> $DIR/bind-by-move-no-subbindings-fun-param.rs:7:6
+ |
+LL | fn f(a @ A(u): A) -> Box<u8> {
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `Box<u8>`, which does not implement the `Copy` trait
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
new file mode 100644
index 000000000..a61d68215
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
@@ -0,0 +1,31 @@
+// Test that moving on both sides of an `@` pattern is not allowed.
+
+fn main() {
+ struct U; // Not copy!
+
+ // Prevent promotion:
+ fn u() -> U {
+ U
+ }
+
+ let a @ b = U; //~ ERROR use of moved value
+
+ let a @ (b, c) = (U, U); //~ ERROR use of partially moved value
+
+ let a @ (b, c) = (u(), u()); //~ ERROR use of partially moved value
+
+ match Ok(U) {
+ a @ Ok(b) | a @ Err(b) => {} //~ ERROR use of moved value
+ //~^ ERROR use of moved value
+ }
+
+ fn fun(a @ b: U) {} //~ ERROR use of moved value
+
+ match [u(), u(), u(), u()] {
+ xs @ [a, .., b] => {} //~ ERROR use of partially moved value
+ }
+
+ match [u(), u(), u(), u()] {
+ xs @ [_, ys @ .., _] => {} //~ ERROR use of partially moved value
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
new file mode 100644
index 000000000..324897151
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -0,0 +1,112 @@
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:11:9
+ |
+LL | let a @ b = U;
+ | ^ - - move occurs because value has type `U`, which does not implement the `Copy` trait
+ | | |
+ | | value moved here
+ | value used here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ ref b = U;
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:13:9
+ |
+LL | let a @ (b, c) = (U, U);
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value 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 a @ (b, ref c) = (U, U);
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:15:9
+ |
+LL | let a @ (b, c) = (u(), u());
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value 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 a @ (b, ref c) = (u(), u());
+ | +++ +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:18:16
+ |
+LL | match Ok(U) {
+ | ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
+LL | a @ Ok(b) | a @ Err(b) => {}
+ | - ^ value used here after move
+ | |
+ | value moved here
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Ok(b) | a @ Err(b) => {}
+ | +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:18:29
+ |
+LL | match Ok(U) {
+ | ----- move occurs because value has type `Result<U, U>`, which does not implement the `Copy` trait
+LL | a @ Ok(b) | a @ Err(b) => {}
+ | - ^ value used here after move
+ | |
+ | value moved here
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Ok(b) | ref a @ Err(b) => {}
+ | +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:25:9
+ |
+LL | xs @ [a, .., b] => {}
+ | ^^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref xs @ [a, .., ref b] => {}
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-move-and-move.rs:29:9
+ |
+LL | xs @ [_, ys @ .., _] => {}
+ | ^^ -- value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref xs @ [_, ref ys @ .., _] => {}
+ | +++ +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-move-and-move.rs:22:12
+ |
+LL | fn fun(a @ b: U) {}
+ | ^ - value moved here
+ | |
+ | value used here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
new file mode 100644
index 000000000..fbdefd9d3
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs
@@ -0,0 +1,84 @@
+// check-pass
+
+// Test `@` patterns combined with `box` patterns.
+
+#![feature(box_patterns)]
+
+#[derive(Copy, Clone)]
+struct C;
+
+fn c() -> C { C }
+
+struct NC;
+
+fn nc() -> NC { NC }
+
+fn main() {
+ let ref a @ box b = Box::new(C); // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+
+ let ref a @ box b = Box::new(c()); // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+
+ fn f3(ref a @ box b: Box<C>) { // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+ }
+ match Box::new(c()) {
+ ref a @ box b => { // OK; the type is `Copy`.
+ drop(b);
+ drop(b);
+ drop(a);
+ }
+ }
+
+ let ref a @ box ref b = Box::new(NC); // OK.
+ drop(a);
+ drop(b);
+
+ fn f4(ref a @ box ref b: Box<NC>) { // OK.
+ drop(a);
+ drop(b)
+ }
+
+ match Box::new(nc()) {
+ ref a @ box ref b => { // OK.
+ drop(a);
+ drop(b);
+ }
+ }
+
+ match Box::new([Ok(c()), Err(nc()), Ok(c())]) {
+ box [Ok(a), ref xs @ .., Err(ref b)] => {
+ let _: C = a;
+ let _: &[Result<C, NC>; 1] = xs;
+ let _: &NC = b;
+ }
+ _ => {}
+ }
+
+ match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] {
+ [Ok(box a), ref xs @ .., Err(box ref b), Err(box ref c)] => {
+ let _: C = a;
+ let _: &[Result<Box<C>, Box<NC>>; 1] = xs;
+ let _: &NC = b;
+ let _: &NC = c;
+ }
+ _ => {}
+ }
+
+ match Box::new([Ok(c()), Err(nc()), Ok(c())]) {
+ box [Ok(a), ref xs @ .., Err(b)] => {}
+ _ => {}
+ }
+
+ match [Ok(Box::new(c())), Err(Box::new(nc())), Ok(Box::new(c())), Ok(Box::new(c()))] {
+ [Ok(box ref a), ref xs @ .., Err(box b), Err(box ref mut c)] => {}
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
new file mode 100644
index 000000000..45aa65e67
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
@@ -0,0 +1,69 @@
+// Test `@` patterns combined with `box` patterns.
+
+#![feature(box_patterns)]
+
+#[derive(Copy, Clone)]
+struct C;
+
+fn c() -> C {
+ C
+}
+
+struct NC;
+
+fn nc() -> NC {
+ NC
+}
+
+fn main() {
+ let a @ box &b = Box::new(&C);
+
+ let a @ box b = Box::new(C);
+
+ fn f1(a @ box &b: Box<&C>) {}
+
+ fn f2(a @ box b: Box<C>) {}
+
+ match Box::new(C) {
+ a @ box b => {}
+ }
+
+ let ref a @ box b = Box::new(NC); //~ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+
+ let ref a @ box ref mut b = Box::new(nc());
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref a @ box ref mut b = Box::new(NC);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref a @ box ref mut b = Box::new(NC);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = NC;
+ let ref a @ box ref mut b = Box::new(NC);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = NC;
+ drop(a);
+
+ let ref mut a @ box ref b = Box::new(NC);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = Box::new(NC);
+ drop(b);
+
+ fn f5(ref mut a @ box ref b: Box<NC>) {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = Box::new(NC);
+ drop(b);
+ }
+
+ match Box::new(nc()) {
+ ref mut a @ box ref b => {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = Box::new(NC);
+ drop(b);
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
new file mode 100644
index 000000000..f27df32cc
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -0,0 +1,145 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-at-and-box.rs:31:9
+ |
+LL | let ref a @ box b = Box::new(NC);
+ | -----^^^^^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:34:9
+ |
+LL | let ref a @ box ref mut b = Box::new(nc());
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:36:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:38:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:42:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | -----^^^^^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:48:9
+ |
+LL | let ref mut a @ box ref b = Box::new(NC);
+ | ---------^^^^^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:62:9
+ |
+LL | ref mut a @ box ref b => {
+ | ---------^^^^^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:54:11
+ |
+LL | fn f5(ref mut a @ box ref b: Box<NC>) {
+ | ---------^^^^^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-at-and-box.rs:31:9
+ |
+LL | let ref a @ box b = Box::new(NC);
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `NC`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ box ref b = Box::new(NC);
+ | +++
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:38:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = NC;
+ | ------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-at-and-box.rs:42:9
+ |
+LL | let ref a @ box ref mut b = Box::new(NC);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = NC;
+ | ------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:48:9
+ |
+LL | let ref mut a @ box ref b = Box::new(NC);
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:62:9
+ |
+LL | ref mut a @ box ref b => {
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-at-and-box.rs:54:11
+ |
+LL | fn f5(ref mut a @ box ref b: Box<NC>) {
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0382, E0502.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs
new file mode 100644
index 000000000..0108861cf
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs
@@ -0,0 +1,49 @@
+// check-pass
+
+// Test `Copy` bindings in the rhs of `@` patterns.
+
+#[derive(Copy, Clone)]
+struct C;
+
+fn mk_c() -> C { C }
+
+#[derive(Copy, Clone)]
+struct P<A, B>(A, B);
+
+enum E<A, B> { L(A), R(B) }
+
+fn main() {
+ let a @ b @ c @ d = C;
+ let a @ (b, c) = (C, mk_c());
+ let a @ P(b, P(c, d)) = P(mk_c(), P(C, C));
+ let a @ [b, c] = [C, C];
+ let a @ [b, .., c] = [C, mk_c(), C];
+ let a @ [b, mid @ .., c] = [C, mk_c(), C];
+ let a @ &(b, c) = &(C, C);
+ let a @ &(b, &P(c, d)) = &(mk_c(), &P(C, C));
+
+ fn foo(a @ [b, mid @ .., c]: [C; 3]) {}
+
+ use self::E::*;
+ match L(C) {
+ L(a) | R(a) => {
+ let a: C = a;
+ drop(a);
+ drop(a);
+ }
+ }
+ match R(&L(&mk_c())) {
+ L(L(&a)) | L(R(&a)) | R(L(&a)) | R(R(&a)) => {
+ let a: C = a;
+ drop(a);
+ drop(a);
+ }
+ }
+
+ match Ok(mk_c()) {
+ Ok(ref a @ b) | Err(b @ ref a) => {
+ let _: &C = a;
+ let _: C = b;
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
new file mode 100644
index 000000000..82f16fca6
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs
@@ -0,0 +1,7 @@
+// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented even with promotion.
+// Currently this logic exists in THIR match checking as opposed to borrowck.
+
+fn main() {
+ struct U;
+ let a @ ref b = U; //~ ERROR borrow of moved value
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
new file mode 100644
index 000000000..d6474f1b4
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -0,0 +1,17 @@
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:6:9
+ |
+LL | let a @ ref b = U;
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` 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 a @ ref b = U;
+ | +++
+
+error: aborting due to previous error
+
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
new file mode 100644
index 000000000..06dc6e1c4
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs
@@ -0,0 +1,80 @@
+// Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented.
+
+fn main() {
+ struct U;
+
+ // Prevent promotion.
+ fn u() -> U {
+ U
+ }
+
+ fn f1(a @ ref b: U) {}
+ //~^ ERROR borrow of moved value
+
+ fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of partially moved value
+ fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
+ //~^ ERROR borrow of moved value
+
+ let a @ ref b = U;
+ //~^ ERROR borrow of moved value
+ let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of partially moved value
+ let a @ [ref mut b, ref c] = [U, U];
+ //~^ ERROR borrow of moved value
+ let a @ ref b = u();
+ //~^ ERROR borrow of moved value
+ let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of partially moved value
+ let a @ [ref mut b, ref c] = [u(), u()];
+ //~^ ERROR borrow of moved value
+
+ match Some(U) {
+ a @ Some(ref b) => {}
+ //~^ ERROR borrow of moved value
+ None => {}
+ }
+ match Some((U, U)) {
+ a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of moved value
+ None => {}
+ }
+ match Some([U, U]) {
+ mut a @ Some([ref b, ref mut c]) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+ match Some(u()) {
+ a @ Some(ref b) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+ match Some((u(), u())) {
+ a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ //~| ERROR use of moved value
+ None => {}
+ }
+ match Some([u(), u()]) {
+ mut a @ Some([ref b, ref mut c]) => {}
+ //~^ ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
new file mode 100644
index 000000000..389e86e64
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -0,0 +1,487 @@
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:22:9
+ |
+LL | let a @ ref b = U;
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` 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 a @ ref b = U;
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | -^^^^^^^^^^^^---------^^^^^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (ref mut b @ ref mut c, d @ ref e) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
+ |
+LL | let a @ [ref mut b, ref c] = [U, U];
+ | -^^^^---------^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ [ref mut b, ref c] = [U, U];
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
+ |
+LL | let a @ ref b = u();
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` 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 a @ ref b = u();
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | -^^^^^^^^^^^^---------^^^^^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (ref mut b @ ref mut c, d @ ref e) = (u(), u());
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
+ |
+LL | let a @ [ref mut b, ref c] = [u(), u()];
+ | -^^^^---------^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ [ref mut b, ref c] = [u(), u()];
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9
+ |
+LL | a @ Some(ref b) => {}
+ | -^^^^^^^^-----^
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some(ref b) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
+ |
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | -----^^^^^^^^^-----^^---------^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref mut a @ Some([ref b, ref mut c]) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
+ |
+LL | a @ Some(ref b) => {}
+ | -^^^^^^^^-----^
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some(ref b) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -----^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
+ |
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9
+ |
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | -----^^^^^^^^^-----^^---------^^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref mut a @ Some([ref b, ref mut c]) => {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11
+ |
+LL | fn f1(a @ ref b: U) {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f1(ref a @ ref b: U) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | -----^^^^^^^^-----^^^^^^^^^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f2(ref mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f2(mut a @ (ref b @ ref c, mut d @ ref e): (U, U)) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | -----^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `d` here
+ | move occurs because `d` has type `U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f2(mut a @ (b @ ref c, ref mut d @ ref e): (U, U)) {}
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11
+ |
+LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
+ | -^^^^---------^^-----^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | fn f3(ref a @ [ref mut b, ref c]: [U; 2]) {}
+ | +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value 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 a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+ | +++ +++
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
+ |
+LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value 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 a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+ | +++ +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
+ |
+LL | match Some((U, U)) {
+ | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | - value moved here ^ value used here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
+ |
+LL | match Some([U, U]) {
+ | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | ----- ^^^^^^^^^ value borrowed here after move
+ | |
+ | value moved here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:18
+ |
+LL | match Some(u()) {
+ | --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait
+LL | a @ Some(ref b) => {}
+ | - ^^^^^ value borrowed here after move
+ | |
+ | value moved here
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some(ref b) => {}
+ | +++
+
+error[E0382]: use of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
+ |
+LL | match Some((u(), u())) {
+ | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
+LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | - value moved here ^ value used here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
+ |
+LL | match Some([u(), u()]) {
+ | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait
+LL | mut a @ Some([ref b, ref mut c]) => {}
+ | ----- ^^^^^^^^^ value borrowed here after move
+ | |
+ | value moved here
+
+error[E0382]: use of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
+ |
+LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+ | ^^^^^ ----- value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 33 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
new file mode 100644
index 000000000..0b0a78010
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
@@ -0,0 +1,82 @@
+// Test that `ref mut? @ pat_with_by_move_bindings` is prevented.
+
+fn main() {
+ struct U;
+
+ // Prevent promotion.
+ fn u() -> U {
+ U
+ }
+
+ fn f1(ref a @ b: U) {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of partially moved value
+
+ let ref a @ b = U;
+ //~^ ERROR cannot move out of value because it is borrowed
+ let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ let ref mut a @ [b, mut c] = [U, U];
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of partially moved value
+ let ref a @ b = u();
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ let ref mut a @ [b, mut c] = [u(), u()];
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of partially moved value
+
+ match Some(U) {
+ ref a @ Some(b) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some((U, U)) {
+ ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some([U, U]) {
+ ref mut a @ Some([b, mut c]) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some(u()) {
+ ref a @ Some(b) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+ match Some((u(), u())) {
+ ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ //~| ERROR borrow of moved value
+ None => {}
+ }
+ match Some([u(), u()]) {
+ ref mut a @ Some([b, mut c]) => {}
+ //~^ ERROR cannot move out of value because it is borrowed
+ None => {}
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
new file mode 100644
index 000000000..770bb8953
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -0,0 +1,375 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9
+ |
+LL | let ref a @ b = U;
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:9
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ | -----^^^^^^^^^^^^-----^^^^^^^^^^-^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:18
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:26:33
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U);
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
+ |
+LL | let ref mut a @ [b, mut c] = [U, U];
+ | ---------^^^^-^^-----^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
+ |
+LL | let ref a @ b = u();
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | -----^^^^^^^^^^^^-----^^^^^^^^^^-^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
+ |
+LL | let ref mut a @ [b, mut c] = [u(), u()];
+ | ---------^^^^-^^-----^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:47:9
+ |
+LL | ref a @ Some(b) => {}
+ | -----^^^^^^^^-^
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:23
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:52:38
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:59:9
+ |
+LL | ref mut a @ Some([b, mut c]) => {}
+ | ---------^^^^^^^^^-^^-----^^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:64:9
+ |
+LL | ref a @ Some(b) => {}
+ | -----^^^^^^^^-^
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:78:9
+ |
+LL | ref mut a @ Some([b, mut c]) => {}
+ | ---------^^^^^^^^^-^^-----^^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
+ |
+LL | fn f1(ref a @ b: U) {}
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | -----^^^^^^^^^^^^-----^^^^^^^^^^-^
+ | | | |
+ | | | value moved into `e` here
+ | | value moved into `c` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | -----^^^-----
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | -----^^^-
+ | | |
+ | | value moved into `e` here
+ | value borrowed, by `d`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
+ |
+LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
+ | ---------^^^^-^^-----^
+ | | | |
+ | | | value moved into `c` here
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error[E0382]: borrow of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9
+ |
+LL | let ref mut a @ [b, mut c] = [U, U];
+ | ^^^^^^^^^ ----- value partially moved here
+ | |
+ | value borrowed here after partial move
+ |
+ = note: partial move occurs because value 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 mut a @ [b, ref mut c] = [U, U];
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
+ |
+LL | let ref a @ b = u();
+ | ^^^^^ - --- move occurs because value has type `U`, which does not implement the `Copy` trait
+ | | |
+ | | value moved here
+ | value borrowed here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ ref b = u();
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | ^^^^^ ----- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value 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 a @ (ref b @ ref mut c, ref d @ e) = (u(), u());
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
+ |
+LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value 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 a @ (ref b @ mut c, ref d @ ref e) = (u(), u());
+ | +++
+
+error[E0382]: borrow of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
+ |
+LL | let ref mut a @ [b, mut c] = [u(), u()];
+ | ^^^^^^^^^ ----- value partially moved here
+ | |
+ | value borrowed here after partial move
+ |
+ = note: partial move occurs because value 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 mut a @ [b, ref mut c] = [u(), u()];
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | ^^^^^ ----- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((ref b @ ref mut c, ref d @ e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:69:38
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {}
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | ref a @ Some((ref b @ mut c, ref d @ ref e)) => {}
+ | +++
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:11:11
+ |
+LL | fn f1(ref a @ b: U) {}
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:20
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | ^^^^^ ----- value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:14:35
+ |
+LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {}
+ | ^^^^^ - value moved here
+ | |
+ | value borrowed here after move
+ |
+ = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of partially moved value
+ --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11
+ |
+LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {}
+ | ^^^^^^^^^ ----- value partially moved here
+ | |
+ | value borrowed here after partial move
+ |
+ = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 36 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs
new file mode 100644
index 000000000..df213f688
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs
@@ -0,0 +1,45 @@
+// check-pass
+
+// Test that `ref` patterns may be used on both sides
+// of an `@` pattern according to NLL borrowck.
+
+fn main() {
+ struct U; // Not copy!
+
+ // Promotion:
+ let ref a @ ref b = U;
+ let _: &U = a;
+ let _: &U = b;
+
+ // Prevent promotion:
+ fn u() -> U { U }
+
+ let ref a @ ref b = u();
+ let _: &U = a;
+ let _: &U = b;
+
+ let ref a @ (ref b, [ref c, ref d]) = (u(), [u(), u()]);
+ let _: &(U, [U; 2]) = a;
+ let _: &U = b;
+ let _: &U = c;
+ let _: &U = d;
+
+ fn f1(ref a @ (ref b, [ref c, ref mid @ .., ref d]): (U, [U; 4])) {}
+
+ let a @ (b, [c, d]) = &(u(), [u(), u()]);
+ let _: &(U, [U; 2]) = a;
+ let _: &U = b;
+ let _: &U = c;
+ let _: &U = d;
+
+ let ref a @ &ref b = &u();
+ let _: &&U = a;
+ let _: &U = b;
+
+ match Ok(u()) {
+ ref a @ Ok(ref b) | ref a @ Err(ref b) => {
+ let _: &Result<U, U> = a;
+ let _: &U = b;
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
new file mode 100644
index 000000000..6bc0d346c
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
@@ -0,0 +1,136 @@
+enum Option<T> {
+ None,
+ Some(T),
+}
+
+fn main() {
+ match &mut Some(1) {
+ ref mut z @ &mut Some(ref a) => {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ **z = None;
+ println!("{}", *a);
+ }
+ _ => ()
+ }
+
+ struct U;
+
+ // Prevent promotion:
+ fn u() -> U { U }
+
+ fn f1(ref a @ ref mut b: U) {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ fn f2(ref mut a @ ref b: U) {}
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+
+ let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+
+ let ref a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref mut a @ ref b = U;
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ let ref mut a @ (ref b, ref c) = (U, U);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+
+ let ref mut a @ ref b = u();
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *a = u();
+ drop(b);
+ let ref a @ ref mut b = u();
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = u();
+ drop(a);
+
+ let ref mut a @ ref b = U;
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *a = U;
+ drop(b);
+ let ref a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *b = U;
+ drop(a);
+
+ match Ok(U) {
+ ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *a = Err(U);
+ drop(b);
+ }
+ }
+
+ match Ok(U) {
+ ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *b = U;
+ drop(a);
+ }
+ }
+
+ match Ok(U) {
+ ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot assign to `*b`, as it is immutable for the pattern guard
+ _ => {}
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot assign to `*a`, as it is immutable for the pattern guard
+ _ => {}
+ }
+ match Ok(U) {
+ ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot move out of `b` in pattern guard
+ //~| ERROR cannot move out of `b` in pattern guard
+ _ => {}
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ //~| ERROR cannot move out of `a` in pattern guard
+ //~| ERROR cannot move out of `a` in pattern guard
+ _ => {}
+ }
+
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = U;
+ *c = U;
+
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ //~| ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = U;
+ drop(a);
+
+ let ref a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+ *b = U; //~| ERROR cannot borrow value as mutable because it is also borrowed as immutable
+ *c = U;
+ drop(a);
+ let ref mut a @ (ref b, ref c) = (U, U);
+ //~^ ERROR cannot borrow value as immutable because it is also borrowed as mutable
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
new file mode 100644
index 000000000..8546b4bb4
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
@@ -0,0 +1,445 @@
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:9
+ |
+LL | ref mut z @ &mut Some(ref a) => {
+ | ---------^^^^^^^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `a`, occurs here
+ | mutable borrow, by `z`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:9
+ |
+LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
+ | ---------^^^^-----------------^
+ | | | |
+ | | | another mutable borrow, by `c`, occurs here
+ | | also borrowed as immutable, by `b`, here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:33:22
+ |
+LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `c`, occurs here
+ | immutable borrow, by `b`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:37:9
+ |
+LL | let ref a @ ref mut b = U;
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9
+ |
+LL | let ref mut a @ ref b = U;
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9
+ |
+LL | let ref mut a @ (ref b, ref c) = (U, U);
+ | ---------^^^^-----^^-----^
+ | | | |
+ | | | immutable borrow, by `c`, occurs here
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
+ |
+LL | let ref mut a @ ref b = u();
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
+ |
+LL | let ref a @ ref mut b = u();
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:57:9
+ |
+LL | let ref mut a @ ref b = U;
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:61:9
+ |
+LL | let ref a @ ref mut b = U;
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:9
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
+ | ---------^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:67:33
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
+ | ---------^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:9
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | -----^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:33
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | -----^^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:9
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ | -----^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:33
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ | -----^^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:9
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ | ---------^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:33
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ | ---------^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:9
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | -----^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:33
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | -----^^^^^^^---------^
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:9
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ---------^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:33
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ---------^^^^^^^-----^
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | -----^^^^---------^^---------^
+ | | | |
+ | | | mutable borrow, by `c`, occurs here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:134:9
+ |
+LL | let ref mut a @ (ref b, ref c) = (U, U);
+ | ---------^^^^-----^^-----^
+ | | | |
+ | | | immutable borrow, by `c`, occurs here
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:22:11
+ |
+LL | fn f1(ref a @ ref mut b: U) {}
+ | -----^^^---------
+ | | |
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11
+ |
+LL | fn f2(ref mut a @ ref b: U) {}
+ | ---------^^^-----
+ | | |
+ | | immutable borrow, by `b`, occurs here
+ | mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11
+ |
+LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {}
+ | -----^^^^^^^^^^^----------------^^^^^^^^
+ | | |
+ | | mutable borrow, by `mid`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:22
+ |
+LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ | -----^^^-------------
+ | | | |
+ | | | also moved into `c` here
+ | | mutable borrow, by `b`, occurs here
+ | immutable borrow, by `a`, occurs here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
+ |
+LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ | ---------^^^-
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:8:31
+ |
+LL | ref mut z @ &mut Some(ref a) => {
+ | --------- ^^^^^ immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | **z = None;
+ | ---------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:46:9
+ |
+LL | let ref mut a @ ref b = u();
+ | ^^^^^^^^^ ----- immutable borrow occurs here
+ | |
+ | mutable borrow occurs here
+...
+LL | drop(b);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:51:9
+ |
+LL | let ref a @ ref mut b = u();
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = u();
+ | -------- mutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:20
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | ----- ^^^^^^^^^ mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | drop(a);
+ | - immutable borrow later used here
+
+error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:45
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+ | ----- ^^^^^^^^^ mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | drop(a);
+ | - immutable borrow later used here
+
+error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:87:61
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {}
+ | ^^^^^^ cannot assign
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:94:61
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {}
+ | ^^^^^^^^^^^ cannot assign
+ |
+ = note: variables bound in patterns are immutable until the end of the pattern guard
+
+error[E0507]: cannot move out of `b` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `b` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:101:66
+ |
+LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {}
+ | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `a` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ^ move occurs because `a` has type `&mut Result<U, U>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0507]: cannot move out of `a` in pattern guard
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:109:66
+ |
+LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {}
+ | ^ move occurs because `a` has type `&mut Result<U, U>`, which does not implement the `Copy` trait
+ |
+ = note: variables bound in patterns cannot be moved from until after the end of the pattern guard
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:117:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = U;
+ | ------ mutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+...
+LL | *b = U;
+ | ------ mutable borrow later used here
+
+error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:129:9
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | ^^^^^ --------- mutable borrow occurs here
+ | |
+ | immutable borrow occurs here
+LL |
+LL | *b = U;
+ | ------ mutable borrow later used here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:30
+ |
+LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {}
+ | ----- ^^^^^^^^^ - value moved here
+ | | |
+ | | value borrowed here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 47 previous errors
+
+Some errors have detailed explanations: E0382, E0502, E0507, E0594.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
new file mode 100644
index 000000000..99739c7bc
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
@@ -0,0 +1,109 @@
+// Test that `ref mut x @ ref mut y` and varieties of that are not allowed.
+
+fn main() {
+ struct U;
+
+ fn u() -> U { U }
+
+ fn f1(ref mut a @ ref mut b: U) {}
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ fn f2(ref mut a @ ref mut b: U) {}
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ fn f3(
+ ref mut a @ [
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ [ref b @ .., _],
+ [_, ref mut mid @ ..],
+ ..,
+ [..],
+ ] : [[U; 4]; 5]
+ ) {}
+ fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ drop(a);
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ drop(b);
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ *a = U;
+ let ref mut a @ ref mut b = U;
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ *b = U;
+
+ let ref mut a @ (
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ ref mut b,
+ [
+ ref mut c,
+ ref mut d,
+ ref e,
+ ]
+ ) = (U, [U, U, U]);
+
+ let ref mut a @ (
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ ref mut b,
+ [
+ ref mut c,
+ ref mut d,
+ ref e,
+ ]
+ ) = (u(), [u(), u(), u()]);
+
+ let a @ (ref mut b, ref mut c) = (U, U);
+ //~^ ERROR borrow of moved value
+ let mut val = (U, [U, U]);
+ let a @ (b, [c, d]) = &mut val; // Same as ^--
+ //~^ ERROR borrow of moved value
+
+ let a @ &mut ref mut b = &mut U;
+ //~^ ERROR borrow of moved value
+ let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+ //~^ ERROR borrow of moved value
+
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ }
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ *b = U;
+ }
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ *a = Err(U);
+
+ // FIXME: The binding name value used above makes for problematic diagnostics.
+ // Resolve that somehow...
+ }
+ }
+ match Ok(U) {
+ ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ //~^ ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ //~| ERROR cannot borrow value as mutable more than once at a time
+ drop(a);
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
new file mode 100644
index 000000000..ad4ce7952
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -0,0 +1,359 @@
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:26:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:44:9
+ |
+LL | let ref mut a @ (
+ | ^--------
+ | |
+ | _________first mutable borrow, by `a`, occurs here
+ | |
+LL | |
+LL | | ref mut b,
+ | | --------- another mutable borrow, by `b`, occurs here
+LL | | [
+LL | | ref mut c,
+ | | --------- another mutable borrow, by `c`, occurs here
+LL | | ref mut d,
+ | | --------- another mutable borrow, by `d`, occurs here
+LL | | ref e,
+ | | ----- also borrowed as immutable, by `e`, here
+LL | | ]
+LL | | ) = (U, [U, U, U]);
+ | |_____^
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:54:9
+ |
+LL | let ref mut a @ (
+ | ^--------
+ | |
+ | _________first mutable borrow, by `a`, occurs here
+ | |
+LL | |
+LL | | ref mut b,
+ | | --------- another mutable borrow, by `b`, occurs here
+LL | | [
+LL | | ref mut c,
+ | | --------- another mutable borrow, by `c`, occurs here
+LL | | ref mut d,
+ | | --------- another mutable borrow, by `d`, occurs here
+LL | | ref e,
+ | | ----- also borrowed as immutable, by `e`, here
+LL | | ]
+LL | | ) = (u(), [u(), u(), u()]);
+ | |_________^
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:64:9
+ |
+LL | let a @ (ref mut b, ref mut c) = (U, U);
+ | -^^^^---------^^---------^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (ref mut b, ref mut c) = (U, U);
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9
+ |
+LL | let a @ (b, [c, d]) = &mut val; // Same as ^--
+ | -^^^^-^^^-^^-^^
+ | | | | |
+ | | | | value borrowed here after move
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ (b, [c, d]) = &mut val; // Same as ^--
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
+ |
+LL | let a @ &mut ref mut b = &mut U;
+ | -^^^^^^^^---------
+ | | |
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ &mut ref mut b = &mut U;
+ | +++
+
+error: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9
+ |
+LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+ | -^^^^^^^^^---------^^---------^
+ | | | |
+ | | | value borrowed here after move
+ | | value borrowed here after move
+ | value moved into `a` here
+ | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+ | +++
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:76:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:9
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:37
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | ---------^^^^^^^---------^
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:8:11
+ |
+LL | fn f1(ref mut a @ ref mut b: U) {}
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11
+ |
+LL | fn f2(ref mut a @ ref mut b: U) {}
+ | ---------^^^---------
+ | | |
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:13:9
+ |
+LL | ref mut a @ [
+ | ^--------
+ | |
+ | _________first mutable borrow, by `a`, occurs here
+ | |
+LL | |
+LL | | [ref b @ .., _],
+ | | ---------- also borrowed as immutable, by `b`, here
+LL | | [_, ref mut mid @ ..],
+ | | ---------------- another mutable borrow, by `mid`, occurs here
+LL | | ..,
+LL | | [..],
+LL | | ] : [[U; 4]; 5]
+ | |_________^
+
+error: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:22
+ |
+LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ | ---------^^^-------------
+ | | | |
+ | | | also moved into `c` here
+ | | another mutable borrow, by `b`, occurs here
+ | first mutable borrow, by `a`, occurs here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
+ |
+LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ | ---------^^^-
+ | | |
+ | | value moved into `c` here
+ | value borrowed, by `b`, here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ^^^^^^^^^ --------- first mutable borrow occurs here
+ | |
+ | second mutable borrow occurs here
+...
+LL | drop(b);
+ | - first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:39:9
+ |
+LL | let ref mut a @ ref mut b = U;
+ | ^^^^^^^^^ --------- first mutable borrow occurs here
+ | |
+ | second mutable borrow occurs here
+...
+LL | *b = U;
+ | ------ first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:24
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | *a = Err(U);
+ | ----------- first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:89:53
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | *a = Err(U);
+ | ----------- first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:24
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | drop(a);
+ | - first borrow later used here
+
+error[E0499]: cannot borrow value as mutable more than once at a time
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:101:53
+ |
+LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+ | --------- ^^^^^^^^^ second mutable borrow occurs here
+ | |
+ | first mutable borrow occurs here
+...
+LL | drop(a);
+ | - first borrow later used here
+
+error[E0382]: borrow of moved value
+ --> $DIR/borrowck-pat-ref-mut-twice.rs:21:34
+ |
+LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {}
+ | --------- ^^^^^^^^^ - value moved here
+ | | |
+ | | value borrowed here after move
+ | move occurs because value has type `U`, which does not implement the `Copy` trait
+
+error: aborting due to 31 previous errors
+
+Some errors have detailed explanations: E0382, E0499.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/box-patterns.rs b/tests/ui/pattern/bindings-after-at/box-patterns.rs
new file mode 100644
index 000000000..9db37253c
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/box-patterns.rs
@@ -0,0 +1,35 @@
+// Test bindings-after-at with box-patterns
+
+// run-pass
+
+#![feature(box_patterns)]
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+fn test(x: Option<Box<i32>>) -> MatchArm {
+ match x {
+ ref bar @ Some(box n) if n > 0 => {
+ // bar is a &Option<Box<i32>>
+ assert_eq!(bar, &x);
+
+ MatchArm::Arm(0)
+ },
+ Some(ref bar @ box n) if n < 0 => {
+ // bar is a &Box<i32> here
+ assert_eq!(**bar, n);
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ assert_eq!(test(Some(Box::new(2))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(-1))), MatchArm::Arm(1));
+ assert_eq!(test(Some(Box::new(0))), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
new file mode 100644
index 000000000..1e2c2968c
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
@@ -0,0 +1,14 @@
+// Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden.
+
+#[derive(Copy, Clone)]
+struct C;
+
+struct NC<A, B>(A, B);
+
+fn main() {
+ // this compiles
+ let a @ NC(b, c) = NC(C, C);
+
+ let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+ //~^ ERROR use of partially moved value
+}
diff --git a/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
new file mode 100644
index 000000000..e0e623fa5
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -0,0 +1,17 @@
+error[E0382]: use of partially moved value
+ --> $DIR/copy-and-move-mixed.rs:12:9
+ |
+LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+ | ^ - value partially moved here
+ | |
+ | value used here after partial move
+ |
+ = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref a @ NC(b, ref c @ NC(d, e)) = NC(C, NC(C, C));
+ | +++ +++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
new file mode 100644
index 000000000..dfd4d0285
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
@@ -0,0 +1,48 @@
+// Ensures the independence of each side in `binding @ subpat`
+// determine their binding modes independently of each other.
+//
+// That is, `binding` does not influence `subpat`.
+// This is important because we might want to allow `p1 @ p2`,
+// where both `p1` and `p2` are syntactically unrestricted patterns.
+// If `binding` is allowed to influence `subpat`,
+// this would create problems for the generalization aforementioned.
+
+
+fn main() {
+ struct NotCopy;
+
+ fn f1(a @ b: &NotCopy) { // OK
+ let _: &NotCopy = a;
+ }
+ fn f2(ref a @ b: &NotCopy) {
+ let _: &&NotCopy = a; // Ok
+ }
+
+ let a @ b = &NotCopy; // OK
+ let _: &NotCopy = a;
+ let ref a @ b = &NotCopy; // OK
+ let _: &&NotCopy = a;
+
+ let ref a @ b = NotCopy; //~ ERROR cannot move out of value because it is borrowed
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ let ref mut a @ b = NotCopy; //~ ERROR cannot move out of value because it is borrowed
+ //~^ ERROR borrow of moved value
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ match Ok(NotCopy) {
+ Ok(ref a @ b) | Err(b @ ref a) => {
+ //~^ ERROR cannot move out of value because it is borrowed
+ //~| ERROR borrow of moved value
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ }
+ }
+ match NotCopy {
+ ref a @ b => {
+ //~^ ERROR cannot move out of value because it is borrowed
+ let _a: &NotCopy = a;
+ let _b: NotCopy = b;
+ }
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
new file mode 100644
index 000000000..638bdd6db
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -0,0 +1,68 @@
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:26:9
+ |
+LL | let ref a @ b = NotCopy;
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
+ |
+LL | let ref mut a @ b = NotCopy;
+ | ---------^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:34:12
+ |
+LL | Ok(ref a @ b) | Err(b @ ref a) => {
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error: borrow of moved value
+ --> $DIR/default-binding-modes-both-sides-independent.rs:34:29
+ |
+LL | Ok(ref a @ b) | Err(b @ ref a) => {
+ | -^^^-----
+ | | |
+ | | value borrowed here after move
+ | value moved into `b` here
+ | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | Ok(ref a @ b) | Err(ref b @ ref a) => {
+ | +++
+
+error: cannot move out of value because it is borrowed
+ --> $DIR/default-binding-modes-both-sides-independent.rs:42:9
+ |
+LL | ref a @ b => {
+ | -----^^^-
+ | | |
+ | | value moved into `b` here
+ | value borrowed, by `a`, here
+
+error[E0382]: borrow of moved value
+ --> $DIR/default-binding-modes-both-sides-independent.rs:29:9
+ |
+LL | let ref mut a @ b = NotCopy;
+ | ^^^^^^^^^ - ------- move occurs because value has type `NotCopy`, which does not implement the `Copy` trait
+ | | |
+ | | value moved here
+ | value borrowed here after move
+ |
+help: borrow this binding in the pattern to avoid moving the value
+ |
+LL | let ref mut a @ ref b = NotCopy;
+ | +++
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs b/tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs
new file mode 100644
index 000000000..fe7d1eba1
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-mode-lint.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+#![deny(unused_mut)]
+
+fn main() {
+ let mut is_mut @ not_mut = 42;
+ &mut is_mut;
+ &not_mut;
+ let not_mut @ mut is_mut = 42;
+ &mut is_mut;
+ &not_mut;
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs
new file mode 100644
index 000000000..e7d99534d
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.rs
@@ -0,0 +1,11 @@
+fn main() {
+ let mut is_mut @ not_mut = 42;
+ &mut is_mut;
+ &mut not_mut;
+ //~^ ERROR cannot borrow
+
+ let not_mut @ mut is_mut = 42;
+ &mut is_mut;
+ &mut not_mut;
+ //~^ ERROR cannot borrow
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
new file mode 100644
index 000000000..54118dc36
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-mut.stderr
@@ -0,0 +1,25 @@
+error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
+ --> $DIR/nested-binding-modes-mut.rs:4:5
+ |
+LL | &mut not_mut;
+ | ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut is_mut @ mut not_mut = 42;
+ | +++
+
+error[E0596]: cannot borrow `not_mut` as mutable, as it is not declared as mutable
+ --> $DIR/nested-binding-modes-mut.rs:9:5
+ |
+LL | &mut not_mut;
+ | ^^^^^^^^^^^^ cannot borrow as mutable
+ |
+help: consider changing this to be mutable
+ |
+LL | let mut not_mut @ mut is_mut = 42;
+ | +++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs
new file mode 100644
index 000000000..adfb0387f
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.rs
@@ -0,0 +1,11 @@
+fn main() {
+ let ref is_ref @ is_val = 42;
+ *is_ref;
+ *is_val;
+ //~^ ERROR cannot be dereferenced
+
+ let is_val @ ref is_ref = 42;
+ *is_ref;
+ *is_val;
+ //~^ ERROR cannot be dereferenced
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr
new file mode 100644
index 000000000..b378fe356
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-binding-modes-ref.stderr
@@ -0,0 +1,15 @@
+error[E0614]: type `{integer}` cannot be dereferenced
+ --> $DIR/nested-binding-modes-ref.rs:4:5
+ |
+LL | *is_val;
+ | ^^^^^^^
+
+error[E0614]: type `{integer}` cannot be dereferenced
+ --> $DIR/nested-binding-modes-ref.rs:9:5
+ |
+LL | *is_val;
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0614`.
diff --git a/tests/ui/pattern/bindings-after-at/nested-patterns.rs b/tests/ui/pattern/bindings-after-at/nested-patterns.rs
new file mode 100644
index 000000000..f06563d56
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-patterns.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+
+struct A { a: u8, b: u8 }
+
+pub fn main() {
+ match (A { a: 10, b: 20 }) {
+ ref x @ A { ref a, b: 20 } => {
+ assert_eq!(x.a, 10);
+ assert_eq!(*a, 10);
+ }
+ A { b: ref _b, .. } => panic!(),
+ }
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs
new file mode 100644
index 000000000..a709e34b5
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs
@@ -0,0 +1,33 @@
+// Here we check that type ascription is syntactically invalid when
+// not in the top position of an ascribing `let` binding or function parameter.
+
+
+// This has no effect.
+// We include it to demonstrate that this is the case:
+#![feature(type_ascription)]
+
+fn main() {}
+
+fn _ok() {
+ let _a @ _b: u8 = 0; // OK.
+ fn _f(_a @ _b: u8) {} // OK.
+}
+
+#[cfg(FALSE)]
+fn case_1() {
+ let a: u8 @ b = 0;
+ //~^ ERROR expected one of `!`
+}
+
+#[cfg(FALSE)]
+fn case_2() {
+ let a @ (b: u8);
+ //~^ ERROR expected one of `!`
+ //~| ERROR expected one of `)`
+}
+
+#[cfg(FALSE)]
+fn case_3() {
+ let a: T1 @ Outer(b: T2);
+ //~^ ERROR expected one of `!`
+}
diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
new file mode 100644
index 000000000..27660ae40
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
@@ -0,0 +1,26 @@
+error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:18:15
+ |
+LL | let a: u8 @ b = 0;
+ | ^ expected one of 7 possible tokens
+
+error: expected one of `)`, `,`, `@`, or `|`, found `:`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:15
+ |
+LL | let a @ (b: u8);
+ | ^ expected one of `)`, `,`, `@`, or `|`
+
+error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `)`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:24:19
+ |
+LL | let a @ (b: u8);
+ | ^ expected one of 7 possible tokens
+
+error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@`
+ --> $DIR/nested-type-ascription-syntactically-invalid.rs:31:15
+ |
+LL | let a: T1 @ Outer(b: T2);
+ | ^ expected one of 7 possible tokens
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs b/tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs
new file mode 100644
index 000000000..383e377a5
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/or-patterns-box-patterns.rs
@@ -0,0 +1,43 @@
+// Test bindings-after-at with or-patterns and box-patterns
+
+// run-pass
+
+#![feature(box_patterns)]
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug, PartialEq)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(foo: Option<Box<Test>>) -> MatchArm {
+ match foo {
+ ref bar @ Some(box Test::Foo | box Test::Bar) => {
+ assert_eq!(bar, &foo);
+
+ MatchArm::Arm(0)
+ },
+ Some(ref bar @ box Test::Baz | ref bar @ box Test::Qux) => {
+ assert!(**bar == Test::Baz || **bar == Test::Qux);
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ assert_eq!(test(Some(Box::new(Test::Foo))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(Test::Bar))), MatchArm::Arm(0));
+ assert_eq!(test(Some(Box::new(Test::Baz))), MatchArm::Arm(1));
+ assert_eq!(test(Some(Box::new(Test::Qux))), MatchArm::Arm(1));
+ assert_eq!(test(None), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs b/tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs
new file mode 100644
index 000000000..d315f7ee3
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/or-patterns-slice-patterns.rs
@@ -0,0 +1,54 @@
+// Test bindings-after-at with or-patterns and slice-patterns
+
+// run-pass
+
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug, PartialEq)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(foo: &[Option<Test>]) -> MatchArm {
+ match foo {
+ bar @ [Some(Test::Foo), .., Some(Test::Qux | Test::Foo)] => {
+ assert_eq!(bar, foo);
+
+ MatchArm::Arm(0)
+ },
+ [.., bar @ Some(Test::Bar | Test::Qux), _] => {
+ assert!(bar == &Some(Test::Bar) || bar == &Some(Test::Qux));
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ let foo = vec![
+ Some(Test::Foo),
+ Some(Test::Bar),
+ Some(Test::Baz),
+ Some(Test::Qux),
+ ];
+
+ // path 1a
+ assert_eq!(test(&foo), MatchArm::Arm(0));
+ // path 1b
+ assert_eq!(test(&[Some(Test::Foo), Some(Test::Bar), Some(Test::Foo)]), MatchArm::Arm(0));
+ // path 2a
+ assert_eq!(test(&foo[..3]), MatchArm::Arm(1));
+ // path 2b
+ assert_eq!(test(&[Some(Test::Bar), Some(Test::Qux), Some(Test::Baz)]), MatchArm::Arm(1));
+ // path 3
+ assert_eq!(test(&foo[1..2]), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/or-patterns.rs b/tests/ui/pattern/bindings-after-at/or-patterns.rs
new file mode 100644
index 000000000..fcc361489
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/or-patterns.rs
@@ -0,0 +1,38 @@
+// Test bindings-after-at with or-patterns
+
+// run-pass
+
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+enum Test {
+ Foo,
+ Bar,
+ Baz,
+ Qux,
+}
+
+fn test(foo: Option<Test>) -> MatchArm {
+ match foo {
+ bar @ Some(Test::Foo | Test::Bar) => {
+ assert!(bar == Some(Test::Foo) || bar == Some(Test::Bar));
+
+ MatchArm::Arm(0)
+ },
+ Some(_) => MatchArm::Arm(1),
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ assert_eq!(test(Some(Test::Foo)), MatchArm::Arm(0));
+ assert_eq!(test(Some(Test::Bar)), MatchArm::Arm(0));
+ assert_eq!(test(Some(Test::Baz)), MatchArm::Arm(1));
+ assert_eq!(test(Some(Test::Qux)), MatchArm::Arm(1));
+ assert_eq!(test(None), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs
new file mode 100644
index 000000000..f167a3952
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.rs
@@ -0,0 +1,29 @@
+// Test that `binding @ subpat` acts as a product context with respect to duplicate binding names.
+// The code that is tested here lives in resolve (see `resolve_pattern_inner`).
+
+
+fn main() {
+ fn f(a @ a @ a: ()) {}
+ //~^ ERROR identifier `a` is bound more than once in this parameter list
+ //~| ERROR identifier `a` is bound more than once in this parameter list
+
+ match Ok(0) {
+ Ok(a @ b @ a)
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ | Err(a @ b @ a)
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ => {}
+ }
+
+ let a @ a @ a = ();
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+ let ref a @ ref a = ();
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ let ref mut a @ ref mut a = ();
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+
+ let a @ (Ok(a) | Err(a)) = Ok(());
+ //~^ ERROR identifier `a` is bound more than once in the same pattern
+ //~| ERROR identifier `a` is bound more than once in the same pattern
+}
diff --git a/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
new file mode 100644
index 000000000..a165549f6
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
@@ -0,0 +1,64 @@
+error[E0415]: identifier `a` is bound more than once in this parameter list
+ --> $DIR/pat-at-same-name-both.rs:6:14
+ |
+LL | fn f(a @ a @ a: ()) {}
+ | ^ used as parameter more than once
+
+error[E0415]: identifier `a` is bound more than once in this parameter list
+ --> $DIR/pat-at-same-name-both.rs:6:18
+ |
+LL | fn f(a @ a @ a: ()) {}
+ | ^ used as parameter more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:11:20
+ |
+LL | Ok(a @ b @ a)
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:13:23
+ |
+LL | | Err(a @ b @ a)
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:18:13
+ |
+LL | let a @ a @ a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:18:17
+ |
+LL | let a @ a @ a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:21:21
+ |
+LL | let ref a @ ref a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:23:29
+ |
+LL | let ref mut a @ ref mut a = ();
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:26:17
+ |
+LL | let a @ (Ok(a) | Err(a)) = Ok(());
+ | ^ used in a pattern more than once
+
+error[E0416]: identifier `a` is bound more than once in the same pattern
+ --> $DIR/pat-at-same-name-both.rs:26:26
+ |
+LL | let a @ (Ok(a) | Err(a)) = Ok(());
+ | ^ used in a pattern more than once
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0415, E0416.
+For more information about an error, try `rustc --explain E0415`.
diff --git a/tests/ui/pattern/bindings-after-at/slice-patterns.rs b/tests/ui/pattern/bindings-after-at/slice-patterns.rs
new file mode 100644
index 000000000..4f4c96e45
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/slice-patterns.rs
@@ -0,0 +1,39 @@
+// Test bindings-after-at with slice-patterns
+
+// run-pass
+
+
+#[derive(Debug, PartialEq)]
+enum MatchArm {
+ Arm(usize),
+ Wild,
+}
+
+fn test(foo: &[i32]) -> MatchArm {
+ match foo {
+ [bar @ .., n] if n == &5 => {
+ for i in bar {
+ assert!(i < &5);
+ }
+
+ MatchArm::Arm(0)
+ },
+ bar @ [x0, .., xn] => {
+ assert_eq!(x0, &1);
+ assert_eq!(x0, &1);
+ assert_eq!(xn, &4);
+ assert_eq!(bar, &[1, 2, 3, 4]);
+
+ MatchArm::Arm(1)
+ },
+ _ => MatchArm::Wild,
+ }
+}
+
+fn main() {
+ let foo = vec![1, 2, 3, 4, 5];
+
+ assert_eq!(test(&foo), MatchArm::Arm(0));
+ assert_eq!(test(&foo[..4]), MatchArm::Arm(1));
+ assert_eq!(test(&foo[0..1]), MatchArm::Wild);
+}
diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs
new file mode 100644
index 000000000..50ac0ef27
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs
@@ -0,0 +1,16 @@
+// Here we check that `_ @ sub` is syntactically invalid
+// and comes with a nice actionable suggestion.
+
+fn main() {}
+
+#[cfg(FALSE)]
+fn wild_before_at_is_bad_syntax() {
+ let _ @ a = 0;
+ //~^ ERROR pattern on wrong side of `@`
+ let _ @ ref a = 0;
+ //~^ ERROR pattern on wrong side of `@`
+ let _ @ ref mut a = 0;
+ //~^ ERROR pattern on wrong side of `@`
+ let _ @ (a, .., b) = (0, 1, 2, 3);
+ //~^ ERROR left-hand side of `@` must be a binding
+}
diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr
new file mode 100644
index 000000000..2f4541584
--- /dev/null
+++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.stderr
@@ -0,0 +1,43 @@
+error: pattern on wrong side of `@`
+ --> $DIR/wild-before-at-syntactically-rejected.rs:8:9
+ |
+LL | let _ @ a = 0;
+ | -^^^-
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `a @ _`
+
+error: pattern on wrong side of `@`
+ --> $DIR/wild-before-at-syntactically-rejected.rs:10:9
+ |
+LL | let _ @ ref a = 0;
+ | -^^^-----
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `ref a @ _`
+
+error: pattern on wrong side of `@`
+ --> $DIR/wild-before-at-syntactically-rejected.rs:12:9
+ |
+LL | let _ @ ref mut a = 0;
+ | -^^^---------
+ | | |
+ | | binding on the right, should be on the left
+ | pattern on the left, should be on the right
+ | help: switch the order: `ref mut a @ _`
+
+error: left-hand side of `@` must be a binding
+ --> $DIR/wild-before-at-syntactically-rejected.rs:14:9
+ |
+LL | let _ @ (a, .., b) = (0, 1, 2, 3);
+ | -^^^----------
+ | | |
+ | | also a pattern
+ | interpreted as a pattern, not a binding
+ |
+ = note: bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+error: aborting due to 4 previous errors
+