summaryrefslogtreecommitdiffstats
path: root/src/test/ui/destructuring-assignment
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/destructuring-assignment')
-rw-r--r--src/test/ui/destructuring-assignment/bad-expr-lhs.rs9
-rw-r--r--src/test/ui/destructuring-assignment/bad-expr-lhs.stderr44
-rw-r--r--src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs5
-rw-r--r--src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr14
-rw-r--r--src/test/ui/destructuring-assignment/drop-order.rs43
-rw-r--r--src/test/ui/destructuring-assignment/nested_destructure.rs18
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.rs22
-rw-r--r--src/test/ui/destructuring-assignment/note-unsupported.stderr69
-rw-r--r--src/test/ui/destructuring-assignment/slice_destructure.rs15
-rw-r--r--src/test/ui/destructuring-assignment/slice_destructure_fail.rs6
-rw-r--r--src/test/ui/destructuring-assignment/slice_destructure_fail.stderr23
-rw-r--r--src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs34
-rw-r--r--src/test/ui/destructuring-assignment/struct_destructure.rs20
-rw-r--r--src/test/ui/destructuring-assignment/struct_destructure_fail.rs16
-rw-r--r--src/test/ui/destructuring-assignment/struct_destructure_fail.stderr45
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure.rs37
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure_fail.rs9
-rw-r--r--src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr42
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure.rs34
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs44
-rw-r--r--src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr98
-rw-r--r--src/test/ui/destructuring-assignment/warn-unused-duplication.rs21
-rw-r--r--src/test/ui/destructuring-assignment/warn-unused-duplication.stderr15
23 files changed, 683 insertions, 0 deletions
diff --git a/src/test/ui/destructuring-assignment/bad-expr-lhs.rs b/src/test/ui/destructuring-assignment/bad-expr-lhs.rs
new file mode 100644
index 000000000..53794783a
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/bad-expr-lhs.rs
@@ -0,0 +1,9 @@
+fn main() {
+ 1 = 2; //~ ERROR invalid left-hand side of assignment
+ 1 += 2; //~ ERROR invalid left-hand side of assignment
+ (1, 2) = (3, 4);
+ //~^ ERROR invalid left-hand side of assignment
+ //~| ERROR invalid left-hand side of assignment
+
+ None = Some(3); //~ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/destructuring-assignment/bad-expr-lhs.stderr b/src/test/ui/destructuring-assignment/bad-expr-lhs.stderr
new file mode 100644
index 000000000..d29867474
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/bad-expr-lhs.stderr
@@ -0,0 +1,44 @@
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/bad-expr-lhs.rs:2:7
+ |
+LL | 1 = 2;
+ | - ^
+ | |
+ | cannot assign to this expression
+
+error[E0067]: invalid left-hand side of assignment
+ --> $DIR/bad-expr-lhs.rs:3:7
+ |
+LL | 1 += 2;
+ | - ^^
+ | |
+ | cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/bad-expr-lhs.rs:4:12
+ |
+LL | (1, 2) = (3, 4);
+ | - ^
+ | |
+ | cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/bad-expr-lhs.rs:4:12
+ |
+LL | (1, 2) = (3, 4);
+ | - ^
+ | |
+ | cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/bad-expr-lhs.rs:8:10
+ |
+LL | None = Some(3);
+ | ---- ^
+ | |
+ | cannot assign to this expression
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0067, E0070.
+For more information about an error, try `rustc --explain E0067`.
diff --git a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs
new file mode 100644
index 000000000..ff867c000
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let mut x = &0;
+ let mut y = &0;
+ (x, y) = &(1, 2); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
new file mode 100644
index 000000000..950e0223e
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
@@ -0,0 +1,14 @@
+error[E0308]: mismatched types
+ --> $DIR/default-match-bindings-forbidden.rs:4:5
+ |
+LL | (x, y) = &(1, 2);
+ | ^^^^^^ ------- this expression has type `&({integer}, {integer})`
+ | |
+ | expected reference, found tuple
+ |
+ = note: expected reference `&({integer}, {integer})`
+ found tuple `(_, _)`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/destructuring-assignment/drop-order.rs b/src/test/ui/destructuring-assignment/drop-order.rs
new file mode 100644
index 000000000..79671054c
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/drop-order.rs
@@ -0,0 +1,43 @@
+// run-pass
+
+//! Test that let bindings and destructuring assignments have consistent drop orders
+
+#![allow(unused_variables, unused_assignments)]
+
+use std::cell::RefCell;
+
+thread_local! {
+ static DROP_ORDER: RefCell<Vec<usize>> = RefCell::new(Vec::new());
+}
+
+struct DropRecorder(usize);
+impl Drop for DropRecorder {
+ fn drop(&mut self) {
+ DROP_ORDER.with(|d| d.borrow_mut().push(self.0));
+ }
+}
+
+fn main() {
+ let expected_drop_order = vec![1, 4, 5, 3, 2];
+ // Check the drop order for let bindings:
+ {
+ let _ = DropRecorder(1);
+ let _val = DropRecorder(2);
+ let (x, _) = (DropRecorder(3), DropRecorder(4));
+ drop(DropRecorder(5));
+ }
+ DROP_ORDER.with(|d| {
+ assert_eq!(&*d.borrow(), &expected_drop_order);
+ d.borrow_mut().clear();
+ });
+ // Check that the drop order for destructuring assignment is the same:
+ {
+ let _val;
+ let x;
+ _ = DropRecorder(1);
+ _val = DropRecorder(2);
+ (x, _) = (DropRecorder(3), DropRecorder(4));
+ drop(DropRecorder(5));
+ }
+ DROP_ORDER.with(|d| assert_eq!(&*d.borrow(), &expected_drop_order));
+}
diff --git a/src/test/ui/destructuring-assignment/nested_destructure.rs b/src/test/ui/destructuring-assignment/nested_destructure.rs
new file mode 100644
index 000000000..94b3a5ff9
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/nested_destructure.rs
@@ -0,0 +1,18 @@
+// run-pass
+
+struct Struct<S, T> {
+ a: S,
+ b: T,
+}
+
+struct TupleStruct<S, T>(S, T);
+
+fn main() {
+ let (a, b, c, d);
+ Struct { a: TupleStruct((a, b), c), b: [d] } =
+ Struct { a: TupleStruct((0, 1), 2), b: [3] };
+ assert_eq!((a, b, c, d), (0, 1, 2, 3));
+
+ // unnested underscore: just discard
+ _ = 1;
+}
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.rs b/src/test/ui/destructuring-assignment/note-unsupported.rs
new file mode 100644
index 000000000..c69edd421
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/note-unsupported.rs
@@ -0,0 +1,22 @@
+struct S { x: u8, y: u8 }
+
+fn main() {
+ let (a, b) = (1, 2);
+
+ (a, b) = (3, 4);
+ (a, b) += (3, 4); //~ ERROR invalid left-hand side of assignment
+ //~| ERROR binary assignment operation `+=` cannot be applied
+
+ [a, b] = [3, 4];
+ [a, b] += [3, 4]; //~ ERROR invalid left-hand side of assignment
+ //~| ERROR binary assignment operation `+=` cannot be applied
+
+ let s = S { x: 3, y: 4 };
+
+ S { x: a, y: b } = s;
+ S { x: a, y: b } += s; //~ ERROR invalid left-hand side of assignment
+ //~| ERROR binary assignment operation `+=` cannot be applied
+
+ S { x: a, ..s } = S { x: 3, y: 4 };
+ //~^ ERROR functional record updates are not allowed in destructuring assignments
+}
diff --git a/src/test/ui/destructuring-assignment/note-unsupported.stderr b/src/test/ui/destructuring-assignment/note-unsupported.stderr
new file mode 100644
index 000000000..e45344aa5
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/note-unsupported.stderr
@@ -0,0 +1,69 @@
+error: functional record updates are not allowed in destructuring assignments
+ --> $DIR/note-unsupported.rs:20:17
+ |
+LL | S { x: a, ..s } = S { x: 3, y: 4 };
+ | ^ help: consider removing the trailing pattern
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `({integer}, {integer})`
+ --> $DIR/note-unsupported.rs:7:5
+ |
+LL | (a, b) += (3, 4);
+ | ------^^^^^^^^^^
+ | |
+ | cannot use `+=` on type `({integer}, {integer})`
+
+error[E0067]: invalid left-hand side of assignment
+ --> $DIR/note-unsupported.rs:7:12
+ |
+LL | (a, b) += (3, 4);
+ | ------ ^^
+ | |
+ | cannot assign to this expression
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `[{integer}; 2]`
+ --> $DIR/note-unsupported.rs:11:5
+ |
+LL | [a, b] += [3, 4];
+ | ------^^^^^^^^^^
+ | |
+ | cannot use `+=` on type `[{integer}; 2]`
+
+error[E0067]: invalid left-hand side of assignment
+ --> $DIR/note-unsupported.rs:11:12
+ |
+LL | [a, b] += [3, 4];
+ | ------ ^^
+ | |
+ | cannot assign to this expression
+
+error[E0368]: binary assignment operation `+=` cannot be applied to type `S`
+ --> $DIR/note-unsupported.rs:17:5
+ |
+LL | S { x: a, y: b } += s;
+ | ----------------^^^^^
+ | |
+ | cannot use `+=` on type `S`
+ |
+note: an implementation of `AddAssign<_>` might be missing for `S`
+ --> $DIR/note-unsupported.rs:1:1
+ |
+LL | struct S { x: u8, y: u8 }
+ | ^^^^^^^^ must implement `AddAssign<_>`
+note: the following trait must be implemented
+ --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+ |
+LL | pub trait AddAssign<Rhs = Self> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0067]: invalid left-hand side of assignment
+ --> $DIR/note-unsupported.rs:17:22
+ |
+LL | S { x: a, y: b } += s;
+ | ---------------- ^^
+ | |
+ | cannot assign to this expression
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0067, E0368.
+For more information about an error, try `rustc --explain E0067`.
diff --git a/src/test/ui/destructuring-assignment/slice_destructure.rs b/src/test/ui/destructuring-assignment/slice_destructure.rs
new file mode 100644
index 000000000..762c4b5e8
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/slice_destructure.rs
@@ -0,0 +1,15 @@
+// run-pass
+
+fn main() {
+ let (mut a, mut b);
+ [a, b] = [0, 1];
+ assert_eq!((a, b), (0, 1));
+ let mut c;
+ [a, .., b, c] = [1, 2, 3, 4, 5];
+ assert_eq!((a, b, c), (1, 4, 5));
+ [_, a, _] = [1, 2, 3];
+ assert_eq!((a, b), (2, 4));
+ [..] = [1, 2, 3];
+ [c, ..] = [5, 6, 6];
+ assert_eq!(c, 5);
+}
diff --git a/src/test/ui/destructuring-assignment/slice_destructure_fail.rs b/src/test/ui/destructuring-assignment/slice_destructure_fail.rs
new file mode 100644
index 000000000..33b09eb34
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/slice_destructure_fail.rs
@@ -0,0 +1,6 @@
+fn main() {
+ let (mut a, mut b);
+ [a, .., b, ..] = [0, 1]; //~ ERROR `..` can only be used once per slice pattern
+ [a, a, b] = [1, 2]; //~ ERROR pattern requires 3 elements but array has 2
+ [_] = [1, 2]; //~ ERROR pattern requires 1 element but array has 2
+}
diff --git a/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr b/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr
new file mode 100644
index 000000000..92c86feba
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/slice_destructure_fail.stderr
@@ -0,0 +1,23 @@
+error: `..` can only be used once per slice pattern
+ --> $DIR/slice_destructure_fail.rs:3:14
+ |
+LL | [a, .., b, ..] = [0, 1];
+ | -- ^^ can only be used once per slice pattern
+ | |
+ | previously used here
+
+error[E0527]: pattern requires 3 elements but array has 2
+ --> $DIR/slice_destructure_fail.rs:4:3
+ |
+LL | [a, a, b] = [1, 2];
+ | ^^^^^^^^^ expected 2 elements
+
+error[E0527]: pattern requires 1 element but array has 2
+ --> $DIR/slice_destructure_fail.rs:5:3
+ |
+LL | [_] = [1, 2];
+ | ^^^ expected 2 elements
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0527`.
diff --git a/src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs b/src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs
new file mode 100644
index 000000000..8da7f90c5
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/struct-or-enum-variant-path.rs
@@ -0,0 +1,34 @@
+// check-pass
+
+struct S;
+
+enum E {
+ V,
+}
+
+type A = E;
+
+fn main() {
+ let mut a;
+
+ (S, a) = (S, ());
+
+ (E::V, a) = (E::V, ());
+
+ (<E>::V, a) = (E::V, ());
+ (A::V, a) = (E::V, ());
+}
+
+impl S {
+ fn check() {
+ let a;
+ (Self, a) = (S, ());
+ }
+}
+
+impl E {
+ fn check() {
+ let a;
+ (Self::V, a) = (E::V, ());
+ }
+}
diff --git a/src/test/ui/destructuring-assignment/struct_destructure.rs b/src/test/ui/destructuring-assignment/struct_destructure.rs
new file mode 100644
index 000000000..8cceaadd7
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/struct_destructure.rs
@@ -0,0 +1,20 @@
+// run-pass
+
+struct Struct<S, T> {
+ a: S,
+ b: T,
+}
+
+fn main() {
+ let (mut a, mut b);
+ Struct { a, b } = Struct { a: 0, b: 1 };
+ assert_eq!((a, b), (0, 1));
+ Struct { a: b, b: a } = Struct { a: 1, b: 2 };
+ assert_eq!((a,b), (2, 1));
+ Struct { a: _, b } = Struct { a: 1, b: 2 };
+ assert_eq!((a, b), (2, 2));
+ Struct { a, .. } = Struct { a: 1, b: 3 };
+ assert_eq!((a, b), (1, 2));
+ Struct { .. } = Struct { a: 1, b: 4 };
+ assert_eq!((a, b), (1, 2));
+}
diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.rs b/src/test/ui/destructuring-assignment/struct_destructure_fail.rs
new file mode 100644
index 000000000..c001fccd4
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.rs
@@ -0,0 +1,16 @@
+struct Struct<S, T> {
+ a: S,
+ b: T,
+}
+
+fn main() {
+ let (mut a, b);
+ let mut c;
+ let d = Struct { a: 0, b: 1 };
+ Struct { a, b, c } = Struct { a: 0, b: 1 }; //~ ERROR does not have a field named `c`
+ Struct { a, _ } = Struct { a: 1, b: 2 }; //~ ERROR pattern does not mention field `b`
+ //~| ERROR expected identifier, found reserved identifier `_`
+ Struct { a, ..d } = Struct { a: 1, b: 2 };
+ //~^ ERROR functional record updates are not allowed in destructuring assignments
+ Struct { a, .. }; //~ ERROR base expression required after `..`
+}
diff --git a/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
new file mode 100644
index 000000000..ae7b3d1e5
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/struct_destructure_fail.stderr
@@ -0,0 +1,45 @@
+error: expected identifier, found reserved identifier `_`
+ --> $DIR/struct_destructure_fail.rs:11:17
+ |
+LL | Struct { a, _ } = Struct { a: 1, b: 2 };
+ | ------ ^ expected identifier, found reserved identifier
+ | |
+ | while parsing this struct
+
+error: functional record updates are not allowed in destructuring assignments
+ --> $DIR/struct_destructure_fail.rs:13:19
+ |
+LL | Struct { a, ..d } = Struct { a: 1, b: 2 };
+ | ^ help: consider removing the trailing pattern
+
+error: base expression required after `..`
+ --> $DIR/struct_destructure_fail.rs:15:19
+ |
+LL | Struct { a, .. };
+ | ^ add a base expression here
+
+error[E0026]: struct `Struct` does not have a field named `c`
+ --> $DIR/struct_destructure_fail.rs:10:20
+ |
+LL | Struct { a, b, c } = Struct { a: 0, b: 1 };
+ | ^ struct `Struct` does not have this field
+
+error[E0027]: pattern does not mention field `b`
+ --> $DIR/struct_destructure_fail.rs:11:5
+ |
+LL | Struct { a, _ } = Struct { a: 1, b: 2 };
+ | ^^^^^^^^^^^^^^^ missing field `b`
+ |
+help: include the missing field in the pattern
+ |
+LL | Struct { a, b } = Struct { a: 1, b: 2 };
+ | ~~~~~
+help: if you don't care about this missing field, you can explicitly ignore it
+ |
+LL | Struct { a, .. } = Struct { a: 1, b: 2 };
+ | ~~~~~~
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0026, E0027.
+For more information about an error, try `rustc --explain E0026`.
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure.rs b/src/test/ui/destructuring-assignment/tuple_destructure.rs
new file mode 100644
index 000000000..2a8584029
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_destructure.rs
@@ -0,0 +1,37 @@
+// run-pass
+
+fn main() {
+ let (mut a, mut b);
+ (a, b) = (0, 1);
+ assert_eq!((a, b), (0, 1));
+ (b, a) = (a, b);
+ assert_eq!((a, b), (1, 0));
+ (a, .., b) = (1, 2);
+ assert_eq!((a, b), (1, 2));
+ (.., a) = (1, 2);
+ assert_eq!((a, b), (2, 2));
+ (..) = (3, 4);
+ assert_eq!((a, b), (2, 2));
+ (b, ..) = (5, 6, 7);
+ assert_eq!(b, 5);
+ (a, _) = (8, 9);
+ assert_eq!(a, 8);
+
+ // Test for a non-Copy type (String):
+ let (mut c, mut d);
+ (c, d) = ("c".to_owned(), "d".to_owned());
+ assert_eq!(c, "c");
+ assert_eq!(d, "d");
+ (d, c) = (c, d);
+ assert_eq!(c, "d");
+ assert_eq!(d, "c");
+
+ // Test nesting/parentheses:
+ ((a, b)) = (0, 1);
+ assert_eq!((a, b), (0, 1));
+ (((a, b)), (c)) = ((2, 3), d);
+ assert_eq!((a, b), (2, 3));
+ assert_eq!(c, "c");
+ ((a, .., b), .., (..)) = ((4, 5), ());
+ assert_eq!((a, b), (4, 5));
+}
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs
new file mode 100644
index 000000000..4e3172d19
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.rs
@@ -0,0 +1,9 @@
+const C: i32 = 1;
+
+fn main() {
+ let (mut a, mut b);
+ (a, .., b, ..) = (0, 1); //~ ERROR `..` can only be used once per tuple pattern
+ (a, a, b) = (1, 2); //~ ERROR mismatched types
+ (C, ..) = (0,1); //~ ERROR invalid left-hand side of assignment
+ (_,) = (1, 2); //~ ERROR mismatched types
+}
diff --git a/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
new file mode 100644
index 000000000..a3004cbbe
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_destructure_fail.stderr
@@ -0,0 +1,42 @@
+error: `..` can only be used once per tuple pattern
+ --> $DIR/tuple_destructure_fail.rs:5:16
+ |
+LL | (a, .., b, ..) = (0, 1);
+ | -- ^^ can only be used once per tuple pattern
+ | |
+ | previously used here
+
+error[E0308]: mismatched types
+ --> $DIR/tuple_destructure_fail.rs:6:5
+ |
+LL | (a, a, b) = (1, 2);
+ | ^^^^^^^^^ ------ this expression has type `({integer}, {integer})`
+ | |
+ | expected a tuple with 2 elements, found one with 3 elements
+ |
+ = note: expected tuple `({integer}, {integer})`
+ found tuple `(_, _, _)`
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/tuple_destructure_fail.rs:7:13
+ |
+LL | (C, ..) = (0,1);
+ | - ^
+ | |
+ | cannot assign to this expression
+
+error[E0308]: mismatched types
+ --> $DIR/tuple_destructure_fail.rs:8:5
+ |
+LL | (_,) = (1, 2);
+ | ^^^^ ------ this expression has type `({integer}, {integer})`
+ | |
+ | expected a tuple with 2 elements, found one with 1 element
+ |
+ = note: expected tuple `({integer}, {integer})`
+ found tuple `(_,)`
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0070, E0308.
+For more information about an error, try `rustc --explain E0070`.
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs b/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs
new file mode 100644
index 000000000..07b5f7a31
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure.rs
@@ -0,0 +1,34 @@
+// run-pass
+
+struct TupleStruct<S, T>(S, T);
+
+impl<S, T> TupleStruct<S, T> {
+ fn assign(self, first: &mut S, second: &mut T) {
+ // Test usage of `Self` instead of the struct name:
+ Self(*first, *second) = self
+ }
+}
+
+enum Enum<S, T> {
+ SingleVariant(S, T)
+}
+
+type Alias<S> = Enum<S, isize>;
+
+fn main() {
+ let (mut a, mut b);
+ TupleStruct(a, b) = TupleStruct(0, 1);
+ assert_eq!((a, b), (0, 1));
+ TupleStruct(a, .., b) = TupleStruct(1, 2);
+ assert_eq!((a, b), (1, 2));
+ TupleStruct(_, a) = TupleStruct(2, 2);
+ assert_eq!((a, b), (2, 2));
+ TupleStruct(..) = TupleStruct(3, 4);
+ assert_eq!((a, b), (2, 2));
+ TupleStruct(5,6).assign(&mut a, &mut b);
+ assert_eq!((a, b), (5, 6));
+ Enum::SingleVariant(a, b) = Enum::SingleVariant(7, 8);
+ assert_eq!((a, b), (7, 8));
+ Alias::SingleVariant(a, b) = Alias::SingleVariant(9, 10);
+ assert_eq!((a, b), (9, 10));
+}
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs
new file mode 100644
index 000000000..845f867d7
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.rs
@@ -0,0 +1,44 @@
+struct TupleStruct<S, T>(S, T);
+
+enum Enum<S, T> {
+ SingleVariant(S, T)
+}
+
+type Alias<S> = Enum<S, isize>;
+
+trait Test {
+ fn test() -> TupleStruct<isize, isize> {
+ TupleStruct(0, 0)
+ }
+}
+
+impl Test for Alias<isize> {}
+
+fn test() -> TupleStruct<isize, isize> {
+ TupleStruct(0, 0)
+}
+
+fn main() {
+ let (mut a, mut b);
+ TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
+ //~^ ERROR `..` can only be used once per tuple struct or variant pattern
+ Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
+ //~^ ERROR `..` can only be used once per tuple struct or variant pattern
+
+ TupleStruct(a, a, b) = TupleStruct(1, 2);
+ //~^ ERROR this pattern has 3 fields, but the corresponding tuple struct has 2 fields
+ TupleStruct(_) = TupleStruct(1, 2);
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple struct has 2 fields
+ Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
+ //~^ ERROR this pattern has 3 fields, but the corresponding tuple variant has 2 fields
+ Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
+ //~^ ERROR this pattern has 1 field, but the corresponding tuple variant has 2 fields
+
+ // Check if `test` is recognized as not a tuple struct but a function call:
+ test() = TupleStruct(0, 0);
+ //~^ ERROR invalid left-hand side of assignment
+ (test)() = TupleStruct(0, 0);
+ //~^ ERROR invalid left-hand side of assignment
+ <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
+ //~^ ERROR invalid left-hand side of assignment
+}
diff --git a/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
new file mode 100644
index 000000000..5cc7acba3
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
@@ -0,0 +1,98 @@
+error: `..` can only be used once per tuple struct or variant pattern
+ --> $DIR/tuple_struct_destructure_fail.rs:23:27
+ |
+LL | TupleStruct(a, .., b, ..) = TupleStruct(0, 1);
+ | -- ^^ can only be used once per tuple struct or variant pattern
+ | |
+ | previously used here
+
+error: `..` can only be used once per tuple struct or variant pattern
+ --> $DIR/tuple_struct_destructure_fail.rs:25:35
+ |
+LL | Enum::SingleVariant(a, .., b, ..) = Enum::SingleVariant(0, 1);
+ | -- ^^ can only be used once per tuple struct or variant pattern
+ | |
+ | previously used here
+
+error[E0023]: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
+ --> $DIR/tuple_struct_destructure_fail.rs:28:17
+ |
+LL | struct TupleStruct<S, T>(S, T);
+ | - - tuple struct has 2 fields
+...
+LL | TupleStruct(a, a, b) = TupleStruct(1, 2);
+ | ^ ^ ^ expected 2 fields, found 3
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple struct has 2 fields
+ --> $DIR/tuple_struct_destructure_fail.rs:30:17
+ |
+LL | struct TupleStruct<S, T>(S, T);
+ | - - tuple struct has 2 fields
+...
+LL | TupleStruct(_) = TupleStruct(1, 2);
+ | ^ expected 2 fields, found 1
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | TupleStruct(_, _) = TupleStruct(1, 2);
+ | +++
+help: use `..` to ignore all fields
+ |
+LL | TupleStruct(..) = TupleStruct(1, 2);
+ | ~~
+
+error[E0023]: this pattern has 3 fields, but the corresponding tuple variant has 2 fields
+ --> $DIR/tuple_struct_destructure_fail.rs:32:25
+ |
+LL | SingleVariant(S, T)
+ | - - tuple variant has 2 fields
+...
+LL | Enum::SingleVariant(a, a, b) = Enum::SingleVariant(1, 2);
+ | ^ ^ ^ expected 2 fields, found 3
+
+error[E0023]: this pattern has 1 field, but the corresponding tuple variant has 2 fields
+ --> $DIR/tuple_struct_destructure_fail.rs:34:25
+ |
+LL | SingleVariant(S, T)
+ | - - tuple variant has 2 fields
+...
+LL | Enum::SingleVariant(_) = Enum::SingleVariant(1, 2);
+ | ^ expected 2 fields, found 1
+ |
+help: use `_` to explicitly ignore each field
+ |
+LL | Enum::SingleVariant(_, _) = Enum::SingleVariant(1, 2);
+ | +++
+help: use `..` to ignore all fields
+ |
+LL | Enum::SingleVariant(..) = Enum::SingleVariant(1, 2);
+ | ~~
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/tuple_struct_destructure_fail.rs:38:12
+ |
+LL | test() = TupleStruct(0, 0);
+ | ------ ^
+ | |
+ | cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/tuple_struct_destructure_fail.rs:40:14
+ |
+LL | (test)() = TupleStruct(0, 0);
+ | -------- ^
+ | |
+ | cannot assign to this expression
+
+error[E0070]: invalid left-hand side of assignment
+ --> $DIR/tuple_struct_destructure_fail.rs:42:38
+ |
+LL | <Alias::<isize> as Test>::test() = TupleStruct(0, 0);
+ | -------------------------------- ^
+ | |
+ | cannot assign to this expression
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0023, E0070.
+For more information about an error, try `rustc --explain E0023`.
diff --git a/src/test/ui/destructuring-assignment/warn-unused-duplication.rs b/src/test/ui/destructuring-assignment/warn-unused-duplication.rs
new file mode 100644
index 000000000..390f44b8a
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/warn-unused-duplication.rs
@@ -0,0 +1,21 @@
+// run-pass
+
+#![warn(unused_assignments)]
+
+fn main() {
+ let mut a;
+ // Assignment occurs left-to-right.
+ // However, we emit warnings when this happens, so it is clear that this is happening.
+ (a, a) = (0, 1); //~ WARN value assigned to `a` is never read
+ assert_eq!(a, 1);
+
+ // We can't always tell when a variable is being assigned to twice, which is why we don't try
+ // to emit an error, which would be fallible.
+ let mut x = 1;
+ (*foo(&mut x), *foo(&mut x)) = (5, 6);
+ assert_eq!(x, 6);
+}
+
+fn foo<'a>(x: &'a mut u32) -> &'a mut u32 {
+ x
+}
diff --git a/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr b/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr
new file mode 100644
index 000000000..1df7a5f22
--- /dev/null
+++ b/src/test/ui/destructuring-assignment/warn-unused-duplication.stderr
@@ -0,0 +1,15 @@
+warning: value assigned to `a` is never read
+ --> $DIR/warn-unused-duplication.rs:9:6
+ |
+LL | (a, a) = (0, 1);
+ | ^
+ |
+note: the lint level is defined here
+ --> $DIR/warn-unused-duplication.rs:3:9
+ |
+LL | #![warn(unused_assignments)]
+ | ^^^^^^^^^^^^^^^^^^
+ = help: maybe it is overwritten before being read?
+
+warning: 1 warning emitted
+