]> git.lizzy.rs Git - rust.git/commitdiff
Introduce `#![feature(bindings_after_at)]`.
authorMazdak Farrokhzad <twingoow@gmail.com>
Mon, 11 Nov 2019 10:39:52 +0000 (11:39 +0100)
committerMazdak Farrokhzad <twingoow@gmail.com>
Mon, 23 Dec 2019 13:47:19 +0000 (14:47 +0100)
Under the gate, `x @ Some(y)` is allowed.
This is subject to various restrictions for soundness.

38 files changed:
src/librustc_feature/active.rs
src/librustc_mir/hair/pattern/check_match.rs
src/librustc_parse/parser/pat.rs
src/libsyntax_pos/symbol.rs
src/test/ui/error-codes/E0007.rs
src/test/ui/error-codes/E0007.stderr
src/test/ui/error-codes/E0303.rs [deleted file]
src/test/ui/error-codes/E0303.stderr [deleted file]
src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/nested-patterns.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/nested-patterns.stderr [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs [new file with mode: 0644]
src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr [new file with mode: 0644]
src/test/ui/pattern/pattern-bindings-after-at.rs [deleted file]
src/test/ui/pattern/pattern-bindings-after-at.stderr [deleted file]

index a386cbf56af85f145bcbc501d1febbd8db7abd25..06dbc8faf1dabd813dc74fc8bae345c441075d95 100644 (file)
@@ -539,6 +539,10 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Allows the use of `loop` and `while` in constants.
     (active, const_loop, "1.41.0", Some(52000), None),
 
+    /// Allows bindings in the subpattern of a binding pattern.
+    /// For example, you can write `x @ Some(y)`.
+    (active, bindings_after_at, "1.41.0", Some(65490), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
@@ -554,4 +558,5 @@ pub fn set(&self, features: &mut Features, span: Span) {
     sym::or_patterns,
     sym::let_chains,
     sym::raw_dylib,
+    sym::bindings_after_at,
 ];
index 4ebf41fb9d21f1d022ed26d40b7e6ac1bede7800..a740b507b3a1627e309f163d9cd403c952556c21 100644 (file)
@@ -4,23 +4,22 @@
 
 use super::{PatCtxt, PatKind, PatternError};
 
-use rustc::lint;
-use rustc::session::Session;
-use rustc::ty::subst::{InternalSubsts, SubstsRef};
-use rustc::ty::{self, Ty, TyCtxt};
-use rustc_errors::{Applicability, DiagnosticBuilder};
-
 use rustc::hir::def::*;
 use rustc::hir::def_id::DefId;
 use rustc::hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc::hir::HirId;
 use rustc::hir::{self, Pat};
-
-use std::slice;
-
+use rustc::lint;
+use rustc::session::Session;
+use rustc::ty::subst::{InternalSubsts, SubstsRef};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc_error_codes::*;
+use rustc_errors::{Applicability, DiagnosticBuilder};
+use syntax::feature_gate::feature_err;
+use syntax_pos::symbol::sym;
 use syntax_pos::{MultiSpan, Span};
 
-use rustc_error_codes::*;
+use std::slice;
 
 crate fn check_match(tcx: TyCtxt<'_>, def_id: DefId) {
     let body_id = match tcx.hir().as_local_hir_id(def_id) {
@@ -123,7 +122,9 @@ fn span_e0158(&self, span: Span, text: &str) {
 impl<'tcx> MatchVisitor<'_, 'tcx> {
     fn check_patterns(&mut self, has_guard: bool, pat: &Pat) {
         check_legality_of_move_bindings(self, has_guard, pat);
-        check_legality_of_bindings_in_at_patterns(self, pat);
+        if !self.tcx.features().bindings_after_at {
+            check_legality_of_bindings_in_at_patterns(self, pat);
+        }
     }
 
     fn check_match(&mut self, scrut: &hir::Expr, arms: &'tcx [hir::Arm], source: hir::MatchSource) {
@@ -656,13 +657,12 @@ fn visit_pat(&mut self, pat: &Pat) {
         match pat.kind {
             hir::PatKind::Binding(.., ref subpat) => {
                 if !self.bindings_allowed {
-                    struct_span_err!(
-                        self.cx.tcx.sess,
+                    feature_err(
+                        &self.cx.tcx.sess.parse_sess,
+                        sym::bindings_after_at,
                         pat.span,
-                        E0303,
-                        "pattern bindings are not allowed after an `@`"
+                        "pattern bindings after an `@` are unstable",
                     )
-                    .span_label(pat.span, "not allowed after `@`")
                     .emit();
                 }
 
index 9b5bf7e2378f58f08cc7cce11e9598ff627a85b6..1540e6d7c053f63e86cd4217362b039bc9404006 100644 (file)
@@ -406,6 +406,7 @@ fn recover_intersection_pat(&mut self, lhs: P<Pat>) -> PResult<'a, P<Pat>> {
         if let PatKind::Ident(_, _, ref mut sub @ None) = rhs.kind {
             // The user inverted the order, so help them fix that.
             let mut applicability = Applicability::MachineApplicable;
+            // FIXME(bindings_after_at): Remove this code when stabilizing the feature.
             lhs.walk(&mut |p| match p.kind {
                 // `check_match` is unhappy if the subpattern has a binding anywhere.
                 PatKind::Ident(..) => {
index 7e0308ee356df2ac325fdcb008d2eefc413e49e0..8fdc199d9ed7ce2cdb8bea2578c02d0e824d3e44 100644 (file)
         bench,
         bin,
         bind_by_move_pattern_guards,
+        bindings_after_at,
         block,
         bool,
         borrowck_graphviz_postflow,
index cdda735ba443554f05cde8285a295a8d99b59f1b..4f7fc0dc2326cadcc2bb1c276ed202d92286fb8d 100644 (file)
@@ -1,9 +1,11 @@
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
 fn main() {
     let x = Some("s".to_string());
     match x {
         op_string @ Some(s) => {},
         //~^ ERROR E0007
-        //~| ERROR E0303
         //~| ERROR E0382
         None => {},
     }
index 89a6298c8752fbea999b5165e42f071f94610227..d7b8050c3a4cdc24df7563b88cd183a6d982b67a 100644 (file)
@@ -1,17 +1,19 @@
-error[E0007]: cannot bind by-move with sub-bindings
-  --> $DIR/E0007.rs:4:9
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/E0007.rs:1:12
    |
-LL |         op_string @ Some(s) => {},
-   |         ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
 
-error[E0303]: pattern bindings are not allowed after an `@`
-  --> $DIR/E0007.rs:4:26
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/E0007.rs:7:9
    |
 LL |         op_string @ Some(s) => {},
-   |                          ^ not allowed after `@`
+   |         ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
 
 error[E0382]: use of moved value
-  --> $DIR/E0007.rs:4:26
+  --> $DIR/E0007.rs:7:26
    |
 LL |     let x = Some("s".to_string());
    |         - move occurs because `x` has type `std::option::Option<std::string::String>`, which does not implement the `Copy` trait
@@ -22,7 +24,7 @@ LL |         op_string @ Some(s) => {},
    |         |                value used here after move
    |         value moved here
 
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0007, E0303, E0382.
+Some errors have detailed explanations: E0007, E0382.
 For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/error-codes/E0303.rs b/src/test/ui/error-codes/E0303.rs
deleted file mode 100644 (file)
index 0530d43..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-fn main() {
-    match Some("hi".to_string()) {
-        ref op_string_ref @ Some(s) => {},
-        //~^ ERROR pattern bindings are not allowed after an `@` [E0303]
-        //~| ERROR E0009
-        None => {},
-    }
-}
diff --git a/src/test/ui/error-codes/E0303.stderr b/src/test/ui/error-codes/E0303.stderr
deleted file mode 100644 (file)
index af537ce..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0009]: cannot bind by-move and by-ref in the same pattern
-  --> $DIR/E0303.rs:3:34
-   |
-LL |         ref op_string_ref @ Some(s) => {},
-   |         -------------------------^-
-   |         |                        |
-   |         |                        by-move pattern here
-   |         both by-ref and by-move used
-
-error[E0303]: pattern bindings are not allowed after an `@`
-  --> $DIR/E0303.rs:3:34
-   |
-LL |         ref op_string_ref @ Some(s) => {},
-   |                                  ^ not allowed after `@`
-
-error: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0009, E0303.
-For more information about an error, try `rustc --explain E0009`.
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs
new file mode 100644 (file)
index 0000000..53d16e7
--- /dev/null
@@ -0,0 +1,12 @@
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+struct X { x: () }
+
+fn main() {
+    let x = Some(X { x: () });
+    match x {
+        Some(ref _y @ _z) => { }, //~ ERROR cannot bind by-move and by-ref in the same pattern
+        None => panic!()
+    }
+}
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
new file mode 100644 (file)
index 0000000..c4afdc5
--- /dev/null
@@ -0,0 +1,20 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:1:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:9:23
+   |
+LL |         Some(ref _y @ _z) => { },
+   |              ---------^^
+   |              |        |
+   |              |        by-move pattern here
+   |              both by-ref and by-move used
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0009`.
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs
new file mode 100644 (file)
index 0000000..bfaab69
--- /dev/null
@@ -0,0 +1,15 @@
+// See issue #12534.
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+fn main() {}
+
+struct A(Box<u8>);
+
+fn f(a @ A(u): A) -> Box<u8> {
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+    drop(a);
+    u
+}
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr
new file mode 100644 (file)
index 0000000..15b0d5e
--- /dev/null
@@ -0,0 +1,28 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/bind-by-move-no-subbindings-fun-param.rs:3:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/bind-by-move-no-subbindings-fun-param.rs:10:6
+   |
+LL | fn f(a @ A(u): A) -> Box<u8> {
+   |      ^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0382]: use of moved value
+  --> $DIR/bind-by-move-no-subbindings-fun-param.rs:10:12
+   |
+LL | fn f(a @ A(u): A) -> Box<u8> {
+   |      ------^-
+   |      |     |
+   |      |     value used here after move
+   |      value moved here
+   |      move occurs because value has type `A`, which does not implement the `Copy` trait
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0007, E0382.
+For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs
new file mode 100644 (file)
index 0000000..e18d3bc
--- /dev/null
@@ -0,0 +1,24 @@
+// Test that moving on both sides of an `@` pattern is not allowed.
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+fn main() {
+    struct U; // Not copy!
+
+    let a @ b = U;
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+
+    let a @ (b, c) = (U, U);
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+
+    match Ok(U) {
+        a @ Ok(b) | a @ Err(b) => {}
+        //~^ ERROR cannot bind by-move with sub-bindings
+        //~| ERROR use of moved value
+        //~| ERROR cannot bind by-move with sub-bindings
+        //~| ERROR use of moved value
+    }
+}
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
new file mode 100644 (file)
index 0000000..0b69ff0
--- /dev/null
@@ -0,0 +1,76 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/borrowck-move-and-move.rs:3:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-move-and-move.rs:9:9
+   |
+LL |     let a @ b = U;
+   |         ^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-move-and-move.rs:13:9
+   |
+LL |     let a @ (b, c) = (U, U);
+   |         ^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-move-and-move.rs:18:9
+   |
+LL |         a @ Ok(b) | a @ Err(b) => {}
+   |         ^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-move-and-move.rs:18:21
+   |
+LL |         a @ Ok(b) | a @ Err(b) => {}
+   |                     ^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0382]: use of moved value
+  --> $DIR/borrowck-move-and-move.rs:9:13
+   |
+LL |     let a @ b = U;
+   |         ----^   - move occurs because value has type `main::U`, which does not implement the `Copy` trait
+   |         |   |
+   |         |   value used here after move
+   |         value moved here
+
+error[E0382]: use of moved value
+  --> $DIR/borrowck-move-and-move.rs:13:17
+   |
+LL |     let a @ (b, c) = (U, U);
+   |         --------^-   ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait
+   |         |       |
+   |         |       value used here after move
+   |         value moved here
+
+error[E0382]: use of moved value
+  --> $DIR/borrowck-move-and-move.rs:18:16
+   |
+LL |     match Ok(U) {
+   |           ----- move occurs because value has type `std::result::Result<main::U, main::U>`, which does not implement the `Copy` trait
+LL |         a @ Ok(b) | a @ Err(b) => {}
+   |         -------^-
+   |         |      |
+   |         |      value used here after move
+   |         value moved here
+
+error[E0382]: use of moved value
+  --> $DIR/borrowck-move-and-move.rs:18:29
+   |
+LL |     match Ok(U) {
+   |           ----- move occurs because value has type `std::result::Result<main::U, main::U>`, which does not implement the `Copy` trait
+LL |         a @ Ok(b) | a @ Err(b) => {}
+   |                     --------^-
+   |                     |       |
+   |                     |       value used here after move
+   |                     value moved here
+
+error: aborting due to 8 previous errors
+
+Some errors have detailed explanations: E0007, E0382.
+For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs
new file mode 100644 (file)
index 0000000..4d94d94
--- /dev/null
@@ -0,0 +1,44 @@
+// Test `@` patterns combined with `box` patterns.
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+#![feature(box_patterns)]
+
+#[derive(Copy, Clone)]
+struct C;
+
+fn main() {
+    let a @ box &b = Box::new(&C);
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+
+    let a @ box b = Box::new(C);
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+
+    let ref a @ box b = Box::new(C); // OK; the type is `Copy`.
+    drop(b);
+    drop(b);
+    drop(a);
+
+    struct NC;
+
+    let ref a @ box b = Box::new(NC); //~ ERROR cannot bind by-move and by-ref in the same pattern
+
+    let ref a @ box ref b = Box::new(NC); // OK.
+    drop(a);
+    drop(b);
+
+    let ref a @ box ref mut b = Box::new(NC); // FIXME: This should not compile.
+    let ref a @ box ref mut b = Box::new(NC); // FIXME: This should not compile.
+    *b = NC;
+    let ref a @ box ref mut b = Box::new(NC);
+    //~^ ERROR cannot borrow `_` as mutable because it is also borrowed as immutable
+    *b = NC;
+    drop(a);
+
+    let ref mut a @ box ref b = Box::new(NC);
+    //~^ ERROR cannot borrow `_` as immutable because it is also borrowed as mutable
+    *a = Box::new(NC);
+    drop(b);
+}
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
new file mode 100644 (file)
index 0000000..fbf9dff
--- /dev/null
@@ -0,0 +1,75 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/borrowck-pat-at-and-box.rs:3:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-pat-at-and-box.rs:11:9
+   |
+LL |     let a @ box &b = Box::new(&C);
+   |         ^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-pat-at-and-box.rs:15:9
+   |
+LL |     let a @ box b = Box::new(C);
+   |         ^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/borrowck-pat-at-and-box.rs:26:21
+   |
+LL |     let ref a @ box b = Box::new(NC);
+   |         ------------^
+   |         |           |
+   |         |           by-move pattern here
+   |         both by-ref and by-move used
+
+error[E0382]: use of moved value
+  --> $DIR/borrowck-pat-at-and-box.rs:11:18
+   |
+LL |     let a @ box &b = Box::new(&C);
+   |         ---------^   ------------ move occurs because value has type `std::boxed::Box<&C>`, which does not implement the `Copy` trait
+   |         |        |
+   |         |        value used here after move
+   |         value moved here
+
+error[E0382]: use of moved value
+  --> $DIR/borrowck-pat-at-and-box.rs:15:17
+   |
+LL |     let a @ box b = Box::new(C);
+   |         --------^   ----------- move occurs because value has type `std::boxed::Box<C>`, which does not implement the `Copy` trait
+   |         |       |
+   |         |       value used here after move
+   |         value moved here
+
+error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-pat-at-and-box.rs:35:21
+   |
+LL |     let ref a @ box ref mut b = Box::new(NC);
+   |         ------------^^^^^^^^^
+   |         |           |
+   |         |           mutable borrow occurs here
+   |         immutable borrow occurs here
+...
+LL |     drop(a);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-pat-at-and-box.rs:40:25
+   |
+LL |     let ref mut a @ box ref b = Box::new(NC);
+   |         ----------------^^^^^
+   |         |               |
+   |         |               immutable borrow occurs here
+   |         mutable borrow occurs here
+LL |
+LL |     *a = Box::new(NC);
+   |     -- mutable borrow later used here
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0007, E0009, E0382, E0502.
+For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs
new file mode 100644 (file)
index 0000000..1115dd5
--- /dev/null
@@ -0,0 +1,41 @@
+// check-pass
+
+// Test `Copy` bindings in the rhs of `@` patterns.
+
+#![feature(slice_patterns)]
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+#[derive(Copy, Clone)]
+struct 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, C);
+    let a @ P(b, P(c, d)) = P(C, P(C, C));
+    let a @ [b, c] = [C, C];
+    let a @ [b, .., c] = [C, C, C];
+    let a @ &(b, c) = &(C, C);
+    let a @ &(b, &P(c, d)) = &(C, &P(C, C));
+
+    use self::E::*;
+    match L(C) {
+        L(a) | R(a) => {
+            let a: C = a;
+            drop(a);
+            drop(a);
+        }
+    }
+    match R(&L(&C)) {
+        L(L(&a)) | L(R(&a)) | R(L(&a)) | R(R(&a)) => {
+            let a: C = a;
+            drop(a);
+            drop(a);
+        }
+    }
+}
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.stderr
new file mode 100644 (file)
index 0000000..e5bbc11
--- /dev/null
@@ -0,0 +1,8 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/borrowck-pat-by-copy-bindings-in-at.rs:6:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs
new file mode 100644 (file)
index 0000000..4b7f61c
--- /dev/null
@@ -0,0 +1,10 @@
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+fn main() {
+    match Some("hi".to_string()) {
+        ref op_string_ref @ Some(s) => {},
+        //~^ ERROR E0009
+        None => {},
+    }
+}
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
new file mode 100644 (file)
index 0000000..9c8a4e2
--- /dev/null
@@ -0,0 +1,20 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:1:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/borrowck-pat-by-move-and-ref.rs:6:34
+   |
+LL |         ref op_string_ref @ Some(s) => {},
+   |         -------------------------^-
+   |         |                        |
+   |         |                        by-move pattern here
+   |         both by-ref and by-move used
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0009`.
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.rs
new file mode 100644 (file)
index 0000000..5fbedd0
--- /dev/null
@@ -0,0 +1,38 @@
+// check-pass
+
+// Test that `ref` patterns may be used on both sides
+// of an `@` pattern according to NLL borrowck.
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+fn main() {
+    struct U; // Not copy!
+
+    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;
+
+    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/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-both-sides.stderr
new file mode 100644 (file)
index 0000000..7a500df
--- /dev/null
@@ -0,0 +1,8 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/borrowck-pat-ref-both-sides.rs:6:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs
new file mode 100644 (file)
index 0000000..3ea3d93
--- /dev/null
@@ -0,0 +1,87 @@
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+enum Option<T> {
+    None,
+    Some(T),
+}
+
+fn main() {
+    match &mut Some(1) {
+        ref mut z @ &mut Some(ref a) => {
+        //~^ ERROR cannot borrow `_` as immutable because it is also borrowed as mutable
+            **z = None;
+            println!("{}", *a);
+        }
+        _ => ()
+    }
+
+    struct U;
+
+    let ref a @ ref mut b = U; // FIXME: This should not compile.
+    let ref mut a @ ref b = U; // FIXME: This should not compile.
+    let ref a @ (ref mut b, ref mut c) = (U, U); // FIXME: This should not compile.
+    let ref mut a @ (ref b, ref c) = (U, U); // FIXME: This should not compile.
+
+    // FIXME: Seems like we have a soundness hole here.
+    let ref mut a @ ref b = U;
+    *a = U; // We are mutating...
+    drop(b); // ..but at the same time we are holding a live shared borrow.
+    // FIXME: Inverted; seems like the same issue exists here as well.
+    let ref a @ ref mut b = U;
+    *b = U;
+    drop(a);
+
+    match Ok(U) {
+        ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => {
+            *a = Err(U); // FIXME: ^ should not compile.
+            drop(b);
+        }
+    }
+
+    match Ok(U) {
+        ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => {
+            //~^ ERROR cannot borrow `_` as mutable because it is also borrowed as immutable
+            //~| ERROR cannot borrow `_` 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 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 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 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 move out of `a` in pattern guard
+        _ => {}
+    }
+
+    let ref a @ (ref mut b, ref mut c) = (U, U);
+    *b = U; // FIXME: ^ should not compile.
+    *c = U;
+
+    let ref a @ (ref mut b, ref mut c) = (U, U);
+    //~^ ERROR cannot borrow `_` as mutable because it is also borrowed as immutable
+    //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable
+    *b = U;
+    drop(a);
+
+    let ref a @ (ref mut b, ref mut c) = (U, U);
+    *b = U; //~^ ERROR cannot borrow `_` as mutable because it is also borrowed as immutable
+    *c = U; //~| ERROR cannot borrow `_` as mutable because it is also borrowed as immutable
+    drop(a);
+    let ref mut a @ (ref b, ref c) = (U, U); // FIXME: This should not compile.
+}
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr
new file mode 100644 (file)
index 0000000..ce79b56
--- /dev/null
@@ -0,0 +1,128 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:1:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:31
+   |
+LL |         ref mut z @ &mut Some(ref a) => {
+   |         ----------------------^^^^^-
+   |         |                     |
+   |         |                     immutable borrow occurs here
+   |         mutable borrow occurs here
+LL |
+LL |             **z = None;
+   |             ---------- mutable borrow later used here
+
+error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43: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 `_` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43: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:52: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:57: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:62: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 main::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:67: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 std::result::Result<main::U, main::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 `_` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:18
+   |
+LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
+   |         ---------^^^^^^^^^------------
+   |         |        |
+   |         |        mutable borrow occurs here
+   |         immutable borrow occurs here
+...
+LL |     drop(a);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:76:29
+   |
+LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
+   |         --------------------^^^^^^^^^-
+   |         |                   |
+   |         |                   mutable borrow occurs here
+   |         immutable borrow occurs here
+...
+LL |     drop(a);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:82:18
+   |
+LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
+   |         ---------^^^^^^^^^------------
+   |         |        |
+   |         |        mutable borrow occurs here
+   |         immutable borrow occurs here
+...
+LL |     drop(a);
+   |          - immutable borrow later used here
+
+error[E0502]: cannot borrow `_` as mutable because it is also borrowed as immutable
+  --> $DIR/borrowck-pat-ref-mut-and-ref.rs:82:29
+   |
+LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
+   |         --------------------^^^^^^^^^-
+   |         |                   |
+   |         |                   mutable borrow occurs here
+   |         immutable borrow occurs here
+...
+LL |     drop(a);
+   |          - immutable borrow later used here
+
+error: aborting due to 11 previous errors
+
+Some errors have detailed explanations: E0502, E0507.
+For more information about an error, try `rustc --explain E0502`.
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs
new file mode 100644 (file)
index 0000000..482fa04
--- /dev/null
@@ -0,0 +1,68 @@
+// Test that `ref mut x @ ref mut y` and varieties of that are not allowed.
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+fn main() {
+    struct U;
+
+    let ref mut a @ ref mut b = U;
+    //~^ ERROR cannot borrow `_` as mutable more than once at a time
+    drop(a);
+    let ref mut a @ ref mut b = U; // FIXME: This should not compile.
+    drop(b);
+    let ref mut a @ ref mut b = U; // FIXME: This should not compile.
+
+    let ref mut a @ ref mut b = U;
+    //~^ ERROR cannot borrow `_` as mutable more than once at a time
+    *a = U;
+    let ref mut a @ ref mut b = U; // FIXME: This should not compile.
+    *b = U;
+
+    let ref mut a @ (ref mut b, [ref mut c, ref mut d]) = (U, [U, U]);
+    // FIXME: This should not compile.
+
+    let a @ (ref mut b, ref mut c) = (U, U);
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR borrow of moved value
+    let mut val = (U, [U, U]);
+    let a @ (b, [c, d]) = &mut val; // Same as ^--
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR borrow of moved value
+
+    let a @ &mut ref mut b = &mut U;
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR borrow of moved value
+    let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR borrow of moved value
+
+    match Ok(U) {
+        ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+            // FIXME: This should not compile.
+        }
+    }
+    match Ok(U) {
+        ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+            *b = U;
+            // FIXME: This should not compile.
+        }
+    }
+    match Ok(U) {
+        ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => {
+            //~^ ERROR cannot borrow `_` as mutable more than once at a time
+            //~| ERROR cannot borrow `_` as mutable more than once at a time
+            *a = Err(U);
+
+            // FIXME: The binding name `_` 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 `_` as mutable more than once at a time
+            //~| ERROR cannot borrow `_` as mutable more than once at a time
+            drop(a);
+        }
+    }
+}
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
new file mode 100644 (file)
index 0000000..c9bfba8
--- /dev/null
@@ -0,0 +1,144 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:3:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:25:9
+   |
+LL |     let a @ (ref mut b, ref mut c) = (U, U);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:29:9
+   |
+LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
+   |         ^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:33:9
+   |
+LL |     let a @ &mut ref mut b = &mut U;
+   |         ^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:36:9
+   |
+LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0499]: cannot borrow `_` as mutable more than once at a time
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:9:21
+   |
+LL |     let ref mut a @ ref mut b = U;
+   |         ------------^^^^^^^^^
+   |         |           |
+   |         |           second mutable borrow occurs here
+   |         first mutable borrow occurs here
+LL |
+LL |     drop(a);
+   |          - first borrow later used here
+
+error[E0499]: cannot borrow `_` as mutable more than once at a time
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:16:21
+   |
+LL |     let ref mut a @ ref mut b = U;
+   |         ------------^^^^^^^^^
+   |         |           |
+   |         |           second mutable borrow occurs here
+   |         first mutable borrow occurs here
+LL |
+LL |     *a = U;
+   |     ------ first borrow later used here
+
+error[E0382]: borrow of moved value
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:25:25
+   |
+LL |     let a @ (ref mut b, ref mut c) = (U, U);
+   |         ----------------^^^^^^^^^-   ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait
+   |         |               |
+   |         |               value borrowed here after move
+   |         value moved here
+
+error[E0382]: borrow of moved value
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:29:21
+   |
+LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
+   |         ------------^--   -------- move occurs because value has type `&mut (main::U, [main::U; 2])`, which does not implement the `Copy` trait
+   |         |           |
+   |         |           value borrowed here after move
+   |         value moved here
+
+error[E0382]: borrow of moved value
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:33:18
+   |
+LL |     let a @ &mut ref mut b = &mut U;
+   |         ---------^^^^^^^^^   ------ move occurs because value has type `&mut main::U`, which does not implement the `Copy` trait
+   |         |        |
+   |         |        value borrowed here after move
+   |         value moved here
+
+error[E0382]: borrow of moved value
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:36:30
+   |
+LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+   |         ---------------------^^^^^^^^^-   ----------- move occurs because value has type `&mut (main::U, main::U)`, which does not implement the `Copy` trait
+   |         |                    |
+   |         |                    value borrowed here after move
+   |         value moved here
+
+error[E0499]: cannot borrow `_` as mutable more than once at a time
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:52: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 `_` as mutable more than once at a time
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:52: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 `_` as mutable more than once at a time
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:62: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 `_` as mutable more than once at a time
+  --> $DIR/borrowck-pat-ref-mut-twice.rs:62: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: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0007, E0382, E0499.
+For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs
new file mode 100644 (file)
index 0000000..b517ed7
--- /dev/null
@@ -0,0 +1,21 @@
+// Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden.
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+#[derive(Copy, Clone)]
+struct C;
+
+struct NC<A, B>(A, B);
+
+fn main() {
+    let a @ NC(b, c) = NC(C, C);
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+
+    let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+    //~^ ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+    //~| ERROR cannot bind by-move with sub-bindings
+    //~| ERROR use of moved value
+}
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
new file mode 100644 (file)
index 0000000..89993a4
--- /dev/null
@@ -0,0 +1,59 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/copy-and-move-mixed.rs:3:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/copy-and-move-mixed.rs:12:9
+   |
+LL |     let a @ NC(b, c) = NC(C, C);
+   |         ^^^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/copy-and-move-mixed.rs:16:9
+   |
+LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0007]: cannot bind by-move with sub-bindings
+  --> $DIR/copy-and-move-mixed.rs:16:19
+   |
+LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+   |                   ^^^^^^^^^^^^ binds an already bound by-move value by moving it
+
+error[E0382]: use of moved value
+  --> $DIR/copy-and-move-mixed.rs:12:19
+   |
+LL |     let a @ NC(b, c) = NC(C, C);
+   |         ----------^-   -------- move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
+   |         |         |
+   |         |         value used here after move
+   |         value moved here
+
+error[E0382]: use of moved value
+  --> $DIR/copy-and-move-mixed.rs:16:19
+   |
+LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+   |         ----------^^^^^^^^^^^^-   --------------- move occurs because value has type `NC<C, NC<C, C>>`, which does not implement the `Copy` trait
+   |         |         |
+   |         |         value used here after move
+   |         value moved here
+
+error[E0382]: use of moved value
+  --> $DIR/copy-and-move-mixed.rs:16:29
+   |
+LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
+   |                   ----------^-
+   |                   |         |
+   |                   |         value used here after move
+   |                   value moved here
+   |
+   = note: move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0007, E0382.
+For more information about an error, try `rustc --explain E0007`.
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs
new file mode 100644 (file)
index 0000000..df2efd0
--- /dev/null
@@ -0,0 +1,31 @@
+// 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.
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+fn main() {
+    struct NotCopy;
+
+    let a @ b = &NotCopy; // OK
+    let _: &NotCopy = a;
+    let ref a @ b = &NotCopy; // OK
+    let _: &&NotCopy = a;
+
+    let ref a @ b = NotCopy; //~ ERROR cannot bind by-move and by-ref in the same pattern
+    let ref mut a @ b = NotCopy; //~ ERROR cannot bind by-move and by-ref in the same pattern
+    match Ok(NotCopy) {
+        Ok(ref a @ b) | Err(ref a @ b) => {}
+        //~^ ERROR cannot bind by-move and by-ref in the same pattern
+    }
+    match NotCopy {
+        ref a @ b => {}
+        //~^ ERROR cannot bind by-move and by-ref in the same pattern
+    }
+}
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
new file mode 100644 (file)
index 0000000..bb0d893
--- /dev/null
@@ -0,0 +1,48 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/default-binding-modes-both-sides-independent.rs:10:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/default-binding-modes-both-sides-independent.rs:21:17
+   |
+LL |     let ref a @ b = NotCopy;
+   |         --------^
+   |         |       |
+   |         |       by-move pattern here
+   |         both by-ref and by-move used
+
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/default-binding-modes-both-sides-independent.rs:22:21
+   |
+LL |     let ref mut a @ b = NotCopy;
+   |         ------------^
+   |         |           |
+   |         |           by-move pattern here
+   |         both by-ref and by-move used
+
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/default-binding-modes-both-sides-independent.rs:24:20
+   |
+LL |         Ok(ref a @ b) | Err(ref a @ b) => {}
+   |                    ^        --------^
+   |                    |        |       |
+   |                    |        |       by-move pattern here
+   |                    |        both by-ref and by-move used
+   |                    by-move pattern here
+
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/default-binding-modes-both-sides-independent.rs:28:17
+   |
+LL |         ref a @ b => {}
+   |         --------^
+   |         |       |
+   |         |       by-move pattern here
+   |         both by-ref and by-move used
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0009`.
diff --git a/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.rs b/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.rs
new file mode 100644 (file)
index 0000000..d655f15
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    let x @ y = 0; //~ ERROR pattern bindings after an `@` are unstable
+}
diff --git a/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.stderr b/src/test/ui/pattern/bindings-after-at/feature-gate-bindings_after_at.stderr
new file mode 100644 (file)
index 0000000..5408f6b
--- /dev/null
@@ -0,0 +1,12 @@
+error[E0658]: pattern bindings after an `@` are unstable
+  --> $DIR/feature-gate-bindings_after_at.rs:2:13
+   |
+LL |     let x @ y = 0;
+   |             ^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/65490
+   = help: add `#![feature(bindings_after_at)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/pattern/bindings-after-at/nested-patterns.rs b/src/test/ui/pattern/bindings-after-at/nested-patterns.rs
new file mode 100644 (file)
index 0000000..63e0784
--- /dev/null
@@ -0,0 +1,16 @@
+// run-pass
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+
+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/src/test/ui/pattern/bindings-after-at/nested-patterns.stderr b/src/test/ui/pattern/bindings-after-at/nested-patterns.stderr
new file mode 100644 (file)
index 0000000..1864a8e
--- /dev/null
@@ -0,0 +1,8 @@
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/nested-patterns.rs:3:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
diff --git a/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.rs
new file mode 100644 (file)
index 0000000..2b5528f
--- /dev/null
@@ -0,0 +1,21 @@
+// 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`).
+
+#![feature(bindings_after_at)]
+//~^ WARN the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+#![feature(or_patterns)]
+//~^ WARN the feature `or_patterns` is incomplete and may cause the compiler to crash
+
+fn main() {
+    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/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr b/src/test/ui/pattern/bindings-after-at/pat-at-same-name-both.stderr
new file mode 100644 (file)
index 0000000..92a97be
--- /dev/null
@@ -0,0 +1,53 @@
+error[E0416]: identifier `a` is bound more than once in the same pattern
+  --> $DIR/pat-at-same-name-both.rs:10: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:10: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:13: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:15: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:18: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:18:26
+   |
+LL |     let a @ (Ok(a) | Err(a)) = Ok(());
+   |                          ^ used in a pattern more than once
+
+warning: the feature `bindings_after_at` is incomplete and may cause the compiler to crash
+  --> $DIR/pat-at-same-name-both.rs:4:12
+   |
+LL | #![feature(bindings_after_at)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: the feature `or_patterns` is incomplete and may cause the compiler to crash
+  --> $DIR/pat-at-same-name-both.rs:6:12
+   |
+LL | #![feature(or_patterns)]
+   |            ^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0416`.
diff --git a/src/test/ui/pattern/pattern-bindings-after-at.rs b/src/test/ui/pattern/pattern-bindings-after-at.rs
deleted file mode 100644 (file)
index aff7264..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-enum Option<T> {
-    None,
-    Some(T),
-}
-
-fn main() {
-    match &mut Some(1) {
-        ref mut z @ &mut Some(ref a) => {
-        //~^ ERROR pattern bindings are not allowed after an `@`
-        //~| ERROR cannot borrow `_` as immutable because it is also borrowed as mutable
-            **z = None;
-            println!("{}", *a);
-        }
-        _ => ()
-    }
-}
diff --git a/src/test/ui/pattern/pattern-bindings-after-at.stderr b/src/test/ui/pattern/pattern-bindings-after-at.stderr
deleted file mode 100644 (file)
index 35ee787..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0303]: pattern bindings are not allowed after an `@`
-  --> $DIR/pattern-bindings-after-at.rs:8:31
-   |
-LL |         ref mut z @ &mut Some(ref a) => {
-   |                               ^^^^^ not allowed after `@`
-
-error[E0502]: cannot borrow `_` as immutable because it is also borrowed as mutable
-  --> $DIR/pattern-bindings-after-at.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: aborting due to 2 previous errors
-
-Some errors have detailed explanations: E0303, E0502.
-For more information about an error, try `rustc --explain E0303`.