about summary refs log tree commit diff
path: root/tests/ui/destructuring-assignment
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/destructuring-assignment')
-rw-r--r--tests/ui/destructuring-assignment/bad-expr-lhs.rs9
-rw-r--r--tests/ui/destructuring-assignment/bad-expr-lhs.stderr44
-rw-r--r--tests/ui/destructuring-assignment/default-match-bindings-forbidden.rs5
-rw-r--r--tests/ui/destructuring-assignment/default-match-bindings-forbidden.stderr14
-rw-r--r--tests/ui/destructuring-assignment/drop-order.rs43
-rw-r--r--tests/ui/destructuring-assignment/nested_destructure.rs18
-rw-r--r--tests/ui/destructuring-assignment/note-unsupported.rs22
-rw-r--r--tests/ui/destructuring-assignment/note-unsupported.stderr66
-rw-r--r--tests/ui/destructuring-assignment/slice_destructure.rs15
-rw-r--r--tests/ui/destructuring-assignment/slice_destructure_fail.rs6
-rw-r--r--tests/ui/destructuring-assignment/slice_destructure_fail.stderr23
-rw-r--r--tests/ui/destructuring-assignment/struct-or-enum-variant-path.rs34
-rw-r--r--tests/ui/destructuring-assignment/struct_destructure.rs20
-rw-r--r--tests/ui/destructuring-assignment/struct_destructure_fail.rs16
-rw-r--r--tests/ui/destructuring-assignment/struct_destructure_fail.stderr45
-rw-r--r--tests/ui/destructuring-assignment/tuple_destructure.rs37
-rw-r--r--tests/ui/destructuring-assignment/tuple_destructure_fail.rs9
-rw-r--r--tests/ui/destructuring-assignment/tuple_destructure_fail.stderr42
-rw-r--r--tests/ui/destructuring-assignment/tuple_struct_destructure.rs34
-rw-r--r--tests/ui/destructuring-assignment/tuple_struct_destructure_fail.rs44
-rw-r--r--tests/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr98
-rw-r--r--tests/ui/destructuring-assignment/warn-unused-duplication.rs21
-rw-r--r--tests/ui/destructuring-assignment/warn-unused-duplication.stderr15
23 files changed, 680 insertions, 0 deletions
diff --git a/tests/ui/destructuring-assignment/bad-expr-lhs.rs b/tests/ui/destructuring-assignment/bad-expr-lhs.rs
new file mode 100644
index 00000000000..53794783a3c
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/bad-expr-lhs.stderr b/tests/ui/destructuring-assignment/bad-expr-lhs.stderr
new file mode 100644
index 00000000000..d2986747480
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/default-match-bindings-forbidden.rs b/tests/ui/destructuring-assignment/default-match-bindings-forbidden.rs
new file mode 100644
index 00000000000..ff867c00071
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/default-match-bindings-forbidden.stderr b/tests/ui/destructuring-assignment/default-match-bindings-forbidden.stderr
new file mode 100644
index 00000000000..950e0223e22
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/drop-order.rs b/tests/ui/destructuring-assignment/drop-order.rs
new file mode 100644
index 00000000000..79671054ca7
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/nested_destructure.rs b/tests/ui/destructuring-assignment/nested_destructure.rs
new file mode 100644
index 00000000000..94b3a5ff9a7
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/note-unsupported.rs b/tests/ui/destructuring-assignment/note-unsupported.rs
new file mode 100644
index 00000000000..c69edd42170
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/note-unsupported.stderr b/tests/ui/destructuring-assignment/note-unsupported.stderr
new file mode 100644
index 00000000000..8a88332b73e
--- /dev/null
+++ b/tests/ui/destructuring-assignment/note-unsupported.stderr
@@ -0,0 +1,66 @@
+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 trait `AddAssign` must be implemented
+  --> $SRC_DIR/core/src/ops/arith.rs:LL:COL
+
+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/tests/ui/destructuring-assignment/slice_destructure.rs b/tests/ui/destructuring-assignment/slice_destructure.rs
new file mode 100644
index 00000000000..762c4b5e8ea
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/slice_destructure_fail.rs b/tests/ui/destructuring-assignment/slice_destructure_fail.rs
new file mode 100644
index 00000000000..33b09eb349d
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/slice_destructure_fail.stderr b/tests/ui/destructuring-assignment/slice_destructure_fail.stderr
new file mode 100644
index 00000000000..92c86febac4
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/struct-or-enum-variant-path.rs b/tests/ui/destructuring-assignment/struct-or-enum-variant-path.rs
new file mode 100644
index 00000000000..8da7f90c524
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/struct_destructure.rs b/tests/ui/destructuring-assignment/struct_destructure.rs
new file mode 100644
index 00000000000..8cceaadd7b9
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/struct_destructure_fail.rs b/tests/ui/destructuring-assignment/struct_destructure_fail.rs
new file mode 100644
index 00000000000..c001fccd4cb
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/struct_destructure_fail.stderr b/tests/ui/destructuring-assignment/struct_destructure_fail.stderr
new file mode 100644
index 00000000000..ae7b3d1e5a9
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/tuple_destructure.rs b/tests/ui/destructuring-assignment/tuple_destructure.rs
new file mode 100644
index 00000000000..2a8584029d0
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/tuple_destructure_fail.rs b/tests/ui/destructuring-assignment/tuple_destructure_fail.rs
new file mode 100644
index 00000000000..4e3172d1973
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/tuple_destructure_fail.stderr b/tests/ui/destructuring-assignment/tuple_destructure_fail.stderr
new file mode 100644
index 00000000000..a3004cbbe10
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/tuple_struct_destructure.rs b/tests/ui/destructuring-assignment/tuple_struct_destructure.rs
new file mode 100644
index 00000000000..07b5f7a314e
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/tuple_struct_destructure_fail.rs b/tests/ui/destructuring-assignment/tuple_struct_destructure_fail.rs
new file mode 100644
index 00000000000..845f867d7b8
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr b/tests/ui/destructuring-assignment/tuple_struct_destructure_fail.stderr
new file mode 100644
index 00000000000..5cc7acba3f3
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/warn-unused-duplication.rs b/tests/ui/destructuring-assignment/warn-unused-duplication.rs
new file mode 100644
index 00000000000..390f44b8aa5
--- /dev/null
+++ b/tests/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/tests/ui/destructuring-assignment/warn-unused-duplication.stderr b/tests/ui/destructuring-assignment/warn-unused-duplication.stderr
new file mode 100644
index 00000000000..e16625136ac
--- /dev/null
+++ b/tests/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);
+   |      ^
+   |
+   = help: maybe it is overwritten before being read?
+note: the lint level is defined here
+  --> $DIR/warn-unused-duplication.rs:3:9
+   |
+LL | #![warn(unused_assignments)]
+   |         ^^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+