about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/unstable-book/src/language-features/match_default_bindings.md58
-rw-r--r--src/librustc/hir/pat_util.rs14
-rw-r--r--src/librustc/middle/mem_categorization.rs52
-rw-r--r--src/librustc/ty/context.rs35
-rw-r--r--src/librustc_const_eval/pattern.rs38
-rw-r--r--src/librustc_typeck/check/_match.rs174
-rw-r--r--src/librustc_typeck/check/mod.rs18
-rw-r--r--src/librustc_typeck/check/writeback.rs21
-rw-r--r--src/libsyntax/feature_gate.rs3
-rw-r--r--src/test/compile-fail/feature-gate-match_default_bindings.rs16
-rw-r--r--src/test/compile-fail/issue-20261.rs3
-rw-r--r--src/test/compile-fail/issue-7867.rs13
-rw-r--r--src/test/compile-fail/match-vec-mismatch.rs3
-rw-r--r--src/test/compile-fail/pat-slice-old-style.rs10
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/box.rs27
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/constref.rs51
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/enum.rs56
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/for.rs31
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/general.rs259
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/lit.rs44
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/range.rs20
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/ref-region.rs27
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/slice.rs36
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/struct.rs33
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/tuple-struct.rs29
-rw-r--r--src/test/run-pass/rfc-2005-default-binding-mode/tuple.rs23
-rw-r--r--src/test/ui/const-expr-addr-operator.rs20
-rw-r--r--src/test/ui/const-expr-addr-operator.stderr14
-rw-r--r--src/test/ui/mismatched_types/issue-38371.rs2
-rw-r--r--src/test/ui/mismatched_types/issue-38371.stderr13
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/const.rs29
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/const.stderr11
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/enum.rs34
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/enum.stderr26
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs40
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr26
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/for.rs20
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/for.stderr10
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs21
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr8
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/lit.rs36
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/lit.stderr20
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/no-double-error.rs21
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr8
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/slice.rs20
-rw-r--r--src/test/ui/rfc-2005-default-binding-mode/slice.stderr8
46 files changed, 1406 insertions, 75 deletions
diff --git a/src/doc/unstable-book/src/language-features/match_default_bindings.md b/src/doc/unstable-book/src/language-features/match_default_bindings.md
new file mode 100644
index 00000000000..cc542931cbe
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/match_default_bindings.md
@@ -0,0 +1,58 @@
+# `match_default_bindings`
+
+The tracking issue for this feature is: [#42640]
+
+[#42640]: https://github.com/rust-lang/rust/issues/42640
+
+------------------------
+
+Match default bindings (also called "default binding modes in match") improves ergonomics for
+pattern-matching on references by introducing automatic dereferencing (and a corresponding shift
+in binding modes) for large classes of patterns that would otherwise not compile.
+
+For example, under match default bindings,
+
+```rust
+#![feature(match_default_bindings)]
+
+fn main() {
+    let x: &Option<_> = &Some(0);
+
+    match x {
+        Some(y) => {
+            println!("y={}", *y);
+        },
+        None => {},
+    }
+}
+```
+
+compiles and is equivalent to either of the below:
+
+```rust
+fn main() {
+    let x: &Option<_> = &Some(0);
+
+    match *x {
+        Some(ref y) => {
+            println!("y={}", *y);
+        },
+        None => {},
+    }
+}
+```
+
+or
+
+```rust
+fn main() {
+    let x: &Option<_> = &Some(0);
+
+    match x {
+        &Some(ref y) => {
+            println!("y={}", *y);
+        },
+        &None => {},
+    }
+}
+```
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 144cb34ee35..2bec224362e 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -160,11 +160,13 @@ impl hir::Pat {
         variants
     }
 
-    /// Checks if the pattern contains any `ref` or `ref mut` bindings,
-    /// and if yes whether it contains mutable or just immutables ones.
+    /// Checks if the pattern contains any `ref` or `ref mut` bindings, and if
+    /// yes whether it contains mutable or just immutables ones.
     ///
-    /// FIXME(tschottdorf): this is problematic as the HIR is being scraped,
-    /// but ref bindings may be implicit after #42640.
+    /// FIXME(tschottdorf): this is problematic as the HIR is being scraped, but
+    /// ref bindings are be implicit after #42640 (default match binding modes).
+    ///
+    /// See #44848.
     pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
         let mut result = None;
         self.each_binding(|annotation, _, _, _| {
@@ -188,7 +190,9 @@ impl hir::Arm {
     /// bindings, and if yes whether its containing mutable ones or just immutables ones.
     pub fn contains_explicit_ref_binding(&self) -> Option<hir::Mutability> {
         // FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
-        // for #42640.
+        // for #42640 (default match binding modes).
+        //
+        // See #44848.
         self.pats.iter()
                  .filter_map(|pat| pat.contains_explicit_ref_binding())
                  .max_by_key(|m| match *m {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 5102b41598d..c973881c980 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -1094,7 +1094,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
     }
 
     // FIXME(#19596) This is a workaround, but there should be a better way to do this
-    fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
+    fn cat_pattern_<F>(&self, mut cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
         where F : FnMut(cmt<'tcx>, &hir::Pat)
     {
         // Here, `cmt` is the categorization for the value being
@@ -1144,6 +1144,56 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
 
         debug!("cat_pattern: {:?} cmt={:?}", pat, cmt);
 
+        // If (pattern) adjustments are active for this pattern, adjust the `cmt` correspondingly.
+        // `cmt`s are constructed differently from patterns. For example, in
+        //
+        // ```
+        // match foo {
+        //     &&Some(x, ) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
+        // corresponding `cmt` we start with a `cmt` for `foo`, and then, by traversing the
+        // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
+        //
+        // `&&Some(x,)` `cmt_foo`
+        //  `&Some(x,)` `deref { cmt_foo}`
+        //   `Some(x,)` `deref { deref { cmt_foo }}`
+        //        (x,)` `field0 { deref { deref { cmt_foo }}}` <- resulting cmt
+        //
+        // The above example has no adjustments. If the code were instead the (after adjustments,
+        // equivalent) version
+        //
+        // ```
+        // match foo {
+        //     Some(x, ) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // Then we see that to get the same result, we must start with `deref { deref { cmt_foo }}`
+        // instead of `cmt_foo` since the pattern is now `Some(x,)` and not `&&Some(x,)`, even
+        // though its assigned type is that of `&&Some(x,)`.
+        for _ in 0..self.tables
+                        .pat_adjustments()
+                        .get(pat.hir_id)
+                        .map(|v| v.len())
+                        .unwrap_or(0) {
+            cmt = self.cat_deref(pat, cmt, true /* implicit */)?;
+        }
+        let cmt = cmt; // lose mutability
+
+        // Invoke the callback, but only now, after the `cmt` has adjusted.
+        //
+        // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
+        // case, the initial `cmt` will be that for `&Some(3)` and the pattern is `Some(x)`. We
+        // don't want to call `op` with these incompatible values. As written, what happens instead
+        // is that `op` is called with the adjusted cmt (that for `*&Some(3)`) and the pattern
+        // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
+        // result in the cmt `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
+        // that (where the `ref` on `x` is implied).
         op(cmt.clone(), pat);
 
         match pat.node {
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 315ba622ccf..15e10f8c5e8 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -337,9 +337,24 @@ pub struct TypeckTables<'tcx> {
 
     adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
-    // Stores the actual binding mode for all instances of hir::BindingAnnotation.
+    /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
     pat_binding_modes: ItemLocalMap<BindingMode>,
 
+    /// Stores the types which were implicitly dereferenced in pattern binding modes
+    /// for later usage in HAIR lowering. For example,
+    ///
+    /// ```
+    /// match &&Some(5i32) {
+    ///     Some(n) => {},
+    ///     _ => {},
+    /// }
+    /// ```
+    /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
+    ///
+    /// See:
+    /// https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions
+    pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
+
     /// Borrows
     pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
 
@@ -394,6 +409,7 @@ impl<'tcx> TypeckTables<'tcx> {
             node_substs: ItemLocalMap(),
             adjustments: ItemLocalMap(),
             pat_binding_modes: ItemLocalMap(),
+            pat_adjustments: ItemLocalMap(),
             upvar_capture_map: FxHashMap(),
             generator_sigs: ItemLocalMap(),
             generator_interiors: ItemLocalMap(),
@@ -574,6 +590,21 @@ impl<'tcx> TypeckTables<'tcx> {
         }
     }
 
+    pub fn pat_adjustments(&self) -> LocalTableInContext<Vec<Ty<'tcx>>> {
+        LocalTableInContext {
+            local_id_root: self.local_id_root,
+            data: &self.pat_adjustments,
+        }
+    }
+
+    pub fn pat_adjustments_mut(&mut self)
+                           -> LocalTableInContextMut<Vec<Ty<'tcx>>> {
+        LocalTableInContextMut {
+            local_id_root: self.local_id_root,
+            data: &mut self.pat_adjustments,
+        }
+    }
+
     pub fn upvar_capture(&self, upvar_id: ty::UpvarId) -> ty::UpvarCapture<'tcx> {
         self.upvar_capture_map[&upvar_id]
     }
@@ -699,6 +730,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
             ref node_substs,
             ref adjustments,
             ref pat_binding_modes,
+            ref pat_adjustments,
             ref upvar_capture_map,
             ref closure_tys,
             ref closure_kinds,
@@ -720,6 +752,7 @@ impl<'gcx> HashStable<StableHashingContext<'gcx>> for TypeckTables<'gcx> {
             node_substs.hash_stable(hcx, hasher);
             adjustments.hash_stable(hcx, hasher);
             pat_binding_modes.hash_stable(hcx, hasher);
+            pat_adjustments.hash_stable(hcx, hasher);
             hash_stable_hashmap(hcx, hasher, upvar_capture_map, |up_var_id, hcx| {
                 let ty::UpvarId {
                     var_id,
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index 7586ad5a75f..d7a16e9d2fc 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -301,6 +301,44 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> {
     }
 
     pub fn lower_pattern(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
+        // When implicit dereferences have been inserted in this pattern, the unadjusted lowered
+        // pattern has the type that results *after* dereferencing. For example, in this code:
+        //
+        // ```
+        // match &&Some(0i32) {
+        //     Some(n) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // the type assigned to `Some(n)` in `unadjusted_pat` would be `Option<i32>` (this is
+        // determined in rustc_typeck::check::match). The adjustments would be
+        //
+        // `vec![&&Option<i32>, &Option<i32>]`.
+        //
+        // Applying the adjustments, we want to instead output `&&Some(n)` (as a HAIR pattern). So
+        // we wrap the unadjusted pattern in `PatternKind::Deref` repeatedly, consuming the
+        // adjustments in *reverse order* (last-in-first-out, so that the last `Deref` inserted
+        // gets the least-dereferenced type).
+        let unadjusted_pat = self.lower_pattern_unadjusted(pat);
+        self.tables
+            .pat_adjustments()
+            .get(pat.hir_id)
+            .unwrap_or(&vec![])
+            .iter()
+            .rev()
+            .fold(unadjusted_pat, |pat, ref_ty| {
+                    debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
+                    Pattern {
+                        span: pat.span,
+                        ty: ref_ty,
+                        kind: Box::new(PatternKind::Deref { subpattern: pat }),
+                    }
+                },
+            )
+    }
+
+    fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
         let mut ty = self.tables.node_id_to_type(pat.hir_id);
 
         let kind = match pat.node {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index d942b2d1230..ab8994bcae2 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -27,25 +27,111 @@ use syntax::ptr::P;
 use syntax_pos::Span;
 
 impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
-    pub fn check_pat(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>) {
-        self.check_pat_arg(pat, expected, false);
-    }
-
     /// The `is_arg` argument indicates whether this pattern is the
     /// *outermost* pattern in an argument (e.g., in `fn foo(&x:
     /// &u32)`, it is true for the `&x` pattern but not `x`). This is
     /// used to tailor error reporting.
-    pub fn check_pat_arg(&self, pat: &'gcx hir::Pat, expected: Ty<'tcx>, is_arg: bool) {
+    pub fn check_pat_walk(
+        &self,
+        pat: &'gcx hir::Pat,
+        mut expected: Ty<'tcx>,
+        mut def_bm: ty::BindingMode,
+        is_arg: bool)
+    {
         let tcx = self.tcx;
 
-        debug!("check_pat(pat={:?},expected={:?},is_arg={})", pat, expected, is_arg);
+        debug!("check_pat_walk(pat={:?},expected={:?},def_bm={:?},is_arg={})",
+            pat, expected, def_bm, is_arg);
+
+        let is_non_ref_pat = match pat.node {
+            PatKind::Struct(..) |
+            PatKind::TupleStruct(..) |
+            PatKind::Tuple(..) |
+            PatKind::Box(_) |
+            PatKind::Range(..) |
+            PatKind::Slice(..) => true,
+            PatKind::Lit(ref lt) => {
+                let ty = self.check_expr(lt);
+                match ty.sty {
+                    ty::TypeVariants::TyRef(..) => false,
+                    _ => true,
+                }
+            }
+            PatKind::Path(ref qpath) => {
+                let (def, _, _) = self.resolve_ty_and_def_ufcs(qpath, pat.id, pat.span);
+                match def {
+                    Def::Const(..) | Def::AssociatedConst(..) => false,
+                    _ => true,
+                }
+            }
+            PatKind::Wild |
+            PatKind::Binding(..) |
+            PatKind::Ref(..) => false,
+        };
+        if is_non_ref_pat && tcx.sess.features.borrow().match_default_bindings {
+            debug!("pattern is non reference pattern");
+            let mut exp_ty = self.resolve_type_vars_with_obligations(&expected);
+
+            // Peel off as many `&` or `&mut` from the discriminant as possible. For example,
+            // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
+            // the `Some(5)` which is not of type TyRef.
+            //
+            // For each ampersand peeled off, update the binding mode and push the original
+            // type into the adjustments vector.
+            //
+            // See the examples in `run-pass/match-defbm*.rs`.
+            let mut pat_adjustments = vec![];
+            expected = loop {
+                debug!("inspecting {:?} with type {:?}", exp_ty, exp_ty.sty);
+                match exp_ty.sty {
+                    ty::TypeVariants::TyRef(_, ty::TypeAndMut{
+                        ty: inner_ty, mutbl: inner_mutability,
+                    }) => {
+                        debug!("current discriminant is TyRef, inserting implicit deref");
+                        // Preserve the reference type. We'll need it later during HAIR lowering.
+                        pat_adjustments.push(exp_ty);
+
+                        exp_ty = inner_ty;
+                        def_bm = match def_bm {
+                            // If default binding mode is by value, make it `ref` or `ref mut`
+                            // (depending on whether we observe `&` or `&mut`).
+                            ty::BindByValue(_) =>
+                                ty::BindByReference(inner_mutability),
+
+                            // Once a `ref`, always a `ref`. This is because a `& &mut` can't mutate
+                            // the underlying value.
+                            ty::BindByReference(hir::Mutability::MutImmutable) =>
+                                ty::BindByReference(hir::Mutability::MutImmutable),
+
+                            // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref`
+                            // (on `&`).
+                            ty::BindByReference(hir::Mutability::MutMutable) =>
+                                ty::BindByReference(inner_mutability),
+                        };
+                    },
+                    _ => break exp_ty,
+                }
+            };
+            if pat_adjustments.len() > 0 {
+                debug!("default binding mode is now {:?}", def_bm);
+                self.inh.tables.borrow_mut()
+                    .pat_adjustments_mut()
+                    .insert(pat.hir_id, pat_adjustments);
+            }
+        }
+
+        // Lose mutability now that we know binding mode and discriminant type.
+        let def_bm = def_bm;
+        let expected = expected;
 
         let ty = match pat.node {
             PatKind::Wild => {
                 expected
             }
             PatKind::Lit(ref lt) => {
-                let ty = self.check_expr(&lt);
+                // We've already computed the type above (when checking for a non-ref pat), so
+                // avoid computing it again.
+                let ty = self.node_ty(lt.hir_id);
 
                 // Byte string patterns behave the same way as array patterns
                 // They can denote both statically and dynamically sized byte arrays
@@ -114,10 +200,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 common_type
             }
             PatKind::Binding(ba, var_id, _, ref sub) => {
-                // Note the binding mode in the typeck tables. For now, what we store is always
-                // identical to what could be scraped from the HIR, but this will change with
-                // default binding modes (#42640).
-                let bm = ty::BindingMode::convert(ba);
+                let bm = if ba == hir::BindingAnnotation::Unannotated {
+                    def_bm
+                } else {
+                    ty::BindingMode::convert(ba)
+                };
                 self.inh
                     .tables
                     .borrow_mut()
@@ -155,19 +242,19 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
 
                 if let Some(ref p) = *sub {
-                    self.check_pat(&p, expected);
+                    self.check_pat_walk(&p, expected, def_bm, true);
                 }
 
                 typ
             }
             PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
-                self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected)
+                self.check_pat_tuple_struct(pat, qpath, &subpats, ddpos, expected, def_bm)
             }
             PatKind::Path(ref qpath) => {
                 self.check_pat_path(pat, qpath, expected)
             }
             PatKind::Struct(ref qpath, ref fields, etc) => {
-                self.check_pat_struct(pat, qpath, fields, etc, expected)
+                self.check_pat_struct(pat, qpath, fields, etc, expected, def_bm)
             }
             PatKind::Tuple(ref elements, ddpos) => {
                 let mut expected_len = elements.len();
@@ -188,7 +275,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 let pat_ty = tcx.mk_ty(ty::TyTuple(element_tys, false));
                 self.demand_eqtype(pat.span, expected, pat_ty);
                 for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
-                    self.check_pat(elem, &element_tys[i]);
+                    self.check_pat_walk(elem, &element_tys[i], def_bm, true);
                 }
                 pat_ty
             }
@@ -201,10 +288,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // think any errors can be introduced by using
                     // `demand::eqtype`.
                     self.demand_eqtype(pat.span, expected, uniq_ty);
-                    self.check_pat(&inner, inner_ty);
+                    self.check_pat_walk(&inner, inner_ty, def_bm, true);
                     uniq_ty
                 } else {
-                    self.check_pat(&inner, tcx.types.err);
+                    self.check_pat_walk(&inner, tcx.types.err, def_bm, true);
                     tcx.types.err
                 }
             }
@@ -219,7 +306,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                     // can, to avoid creating needless variables.  This
                     // also helps with the bad interactions of the given
                     // hack detailed in (*) below.
-                    debug!("check_pat_arg: expected={:?}", expected);
+                    debug!("check_pat_walk: expected={:?}", expected);
                     let (rptr_ty, inner_ty) = match expected.sty {
                         ty::TyRef(_, mt) if mt.mutbl == mutbl => {
                             (expected, mt.ty)
@@ -230,7 +317,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                             let mt = ty::TypeAndMut { ty: inner_ty, mutbl: mutbl };
                             let region = self.next_region_var(infer::PatternRegion(pat.span));
                             let rptr_ty = tcx.mk_ref(region, mt);
-                            debug!("check_pat_arg: demanding {:?} = {:?}", expected, rptr_ty);
+                            debug!("check_pat_walk: demanding {:?} = {:?}", expected, rptr_ty);
                             let err = self.demand_eqtype_diag(pat.span, expected, rptr_ty);
 
                             // Look for a case like `fn foo(&foo: u32)` and suggest
@@ -253,10 +340,10 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                     };
 
-                    self.check_pat(&inner, inner_ty);
+                    self.check_pat_walk(&inner, inner_ty, def_bm, true);
                     rptr_ty
                 } else {
-                    self.check_pat(&inner, tcx.types.err);
+                    self.check_pat_walk(&inner, tcx.types.err, def_bm, true);
                     tcx.types.err
                 }
             }
@@ -314,13 +401,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 };
 
                 for elt in before {
-                    self.check_pat(&elt, inner_ty);
+                    self.check_pat_walk(&elt, inner_ty, def_bm, true);
                 }
                 if let Some(ref slice) = *slice {
-                    self.check_pat(&slice, slice_ty);
+                    self.check_pat_walk(&slice, slice_ty, def_bm, true);
                 }
                 for elt in after {
-                    self.check_pat(&elt, inner_ty);
+                    self.check_pat_walk(&elt, inner_ty, def_bm, true);
                 }
                 expected_ty
             }
@@ -329,7 +416,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.write_ty(pat.hir_id, ty);
 
         // (*) In most of the cases above (literals and constants being
-        // the exception), we relate types using strict equality, evewn
+        // the exception), we relate types using strict equality, even
         // though subtyping would be sufficient. There are a few reasons
         // for this, some of which are fairly subtle and which cost me
         // (nmatsakis) an hour or two debugging to remember, so I thought
@@ -339,7 +426,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // cause some inconvenience. What we are saying is that the type
         // of `x` becomes *exactly* what is expected. This can cause unnecessary
         // errors in some cases, such as this one:
-        // it will cause errors in a case like this:
         //
         // ```
         // fn foo<'x>(x: &'x int) {
@@ -409,11 +495,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // use the *precise* type of the discriminant, *not* some supertype, as
         // the "discriminant type" (issue #23116).
         //
-        // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
-        // is problematic as the HIR is being scraped, but ref bindings may be
-        // implicit after #42640. We need to make sure that pat_adjustments
-        // (once introduced) is populated by the time we get here.
-        //
         // arielb1 [writes here in this comment thread][c] that there
         // is certainly *some* potential danger, e.g. for an example
         // like:
@@ -455,7 +536,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         //     assert_eq!(foo.0.0, 42);
         // }
         // ```
-
+        //
+        // FIXME(tschottdorf): don't call contains_explicit_ref_binding, which
+        // is problematic as the HIR is being scraped, but ref bindings may be
+        // implicit after #42640. We need to make sure that pat_adjustments
+        // (once introduced) is populated by the time we get here.
+        //
+        // See #44848.
         let contains_ref_bindings = arms.iter()
                                         .filter_map(|a| a.contains_explicit_ref_binding())
                                         .max_by_key(|m| match *m {
@@ -495,7 +582,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             let mut all_pats_diverge = Diverges::WarnedAlways;
             for p in &arm.pats {
                 self.diverges.set(Diverges::Maybe);
-                self.check_pat(&p, discrim_ty);
+                self.check_pat_walk(&p, discrim_ty,
+                    ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true);
                 all_pats_diverge &= self.diverges.get();
             }
 
@@ -576,14 +664,15 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         qpath: &hir::QPath,
                         fields: &'gcx [Spanned<hir::FieldPat>],
                         etc: bool,
-                        expected: Ty<'tcx>) -> Ty<'tcx>
+                        expected: Ty<'tcx>,
+                        def_bm: ty::BindingMode) -> Ty<'tcx>
     {
         // Resolve the path and check the definition for errors.
         let (variant, pat_ty) = if let Some(variant_ty) = self.check_struct_path(qpath, pat.id) {
             variant_ty
         } else {
             for field in fields {
-                self.check_pat(&field.node.pat, self.tcx.types.err);
+                self.check_pat_walk(&field.node.pat, self.tcx.types.err, def_bm, true);
             }
             return self.tcx.types.err;
         };
@@ -592,7 +681,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
-        self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc);
+        self.check_struct_pat_fields(pat_ty, pat.id, pat.span, variant, fields, etc, def_bm);
         pat_ty
     }
 
@@ -637,12 +726,13 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                               qpath: &hir::QPath,
                               subpats: &'gcx [P<hir::Pat>],
                               ddpos: Option<usize>,
-                              expected: Ty<'tcx>) -> Ty<'tcx>
+                              expected: Ty<'tcx>,
+                              def_bm: ty::BindingMode) -> Ty<'tcx>
     {
         let tcx = self.tcx;
         let on_error = || {
             for pat in subpats {
-                self.check_pat(&pat, tcx.types.err);
+                self.check_pat_walk(&pat, tcx.types.err, def_bm, true);
             }
         };
         let report_unexpected_def = |def: Def| {
@@ -678,6 +768,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // Replace constructor type with constructed type for tuple struct patterns.
         let pat_ty = pat_ty.fn_sig(tcx).output();
         let pat_ty = tcx.no_late_bound_regions(&pat_ty).expect("expected fn type");
+
         self.demand_eqtype(pat.span, expected, pat_ty);
 
         // Type check subpatterns.
@@ -689,7 +780,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             };
             for (i, subpat) in subpats.iter().enumerate_and_adjust(variant.fields.len(), ddpos) {
                 let field_ty = self.field_ty(subpat.span, &variant.fields[i], substs);
-                self.check_pat(&subpat, field_ty);
+                self.check_pat_walk(&subpat, field_ty, def_bm, true);
 
                 self.tcx.check_stability(variant.fields[i].did, pat.id, subpat.span);
             }
@@ -715,7 +806,8 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                span: Span,
                                variant: &'tcx ty::VariantDef,
                                fields: &'gcx [Spanned<hir::FieldPat>],
-                               etc: bool) {
+                               etc: bool,
+                               def_bm: ty::BindingMode) {
         let tcx = self.tcx;
 
         let (substs, kind_name) = match adt_ty.sty {
@@ -772,7 +864,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             };
 
-            self.check_pat(&field.pat, field_ty);
+            self.check_pat_walk(&field.pat, field_ty, def_bm, true);
         }
 
         // Report an error if incorrect number of the fields were specified.
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 33ac95ffcd1..9c6a4abfbd7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1037,7 +1037,8 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     // Add formal parameters.
     for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
         // Check the pattern.
-        fcx.check_pat_arg(&arg.pat, arg_ty, true);
+        fcx.check_pat_walk(&arg.pat, arg_ty,
+            ty::BindingMode::BindByValue(hir::Mutability::MutImmutable), true);
 
         // Check that argument is Sized.
         // The check for a non-trivial pattern is a hack to avoid duplicate warnings
@@ -4106,6 +4107,12 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 (self.to_ty(qself), segment)
             }
         };
+        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
+        if let Some(cached_def) = self.tables.borrow().type_dependent_defs().get(hir_id) {
+            // Return directly on cache hit. This is useful to avoid doubly reporting
+            // errors with default match binding modes. See #44614.
+            return (*cached_def, Some(ty), slice::ref_slice(&**item_segment))
+        }
         let item_name = item_segment.name;
         let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
             Ok(def) => def,
@@ -4122,7 +4129,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         };
 
         // Write back the new resolution.
-        let hir_id = self.tcx.hir.node_to_hir_id(node_id);
         self.tables.borrow_mut().type_dependent_defs_mut().insert(hir_id, def);
         (def, Some(ty), slice::ref_slice(&**item_segment))
     }
@@ -4132,7 +4138,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                   init: &'gcx hir::Expr) -> Ty<'tcx>
     {
         // FIXME(tschottdorf): contains_explicit_ref_binding() must be removed
-        // for #42640.
+        // for #42640 (default match binding modes).
+        //
+        // See #44848.
         let ref_bindings = local.pat.contains_explicit_ref_binding();
 
         let local_ty = self.local_ty(init.span, local.id);
@@ -4164,7 +4172,9 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         }
 
-        self.check_pat(&local.pat, t);
+        self.check_pat_walk(&local.pat, t,
+                            ty::BindingMode::BindByValue(hir::Mutability::MutImmutable),
+                            true);
         let pat_ty = self.node_ty(local.pat.hir_id);
         if pat_ty.references_error() {
             self.write_ty(local.hir_id, pat_ty);
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index 3c650718a4b..b3648d357e5 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -197,6 +197,8 @@ impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
             _ => {}
         };
 
+        self.visit_pat_adjustments(p.span, p.hir_id);
+
         self.visit_node_id(p.span, p.hir_id);
         intravisit::walk_pat(self, p);
     }
@@ -366,6 +368,25 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
         }
     }
 
+    fn visit_pat_adjustments(&mut self, span: Span, hir_id: hir::HirId) {
+        let adjustment = self.fcx
+                             .tables
+                             .borrow_mut()
+                             .pat_adjustments_mut()
+                             .remove(hir_id);
+        match adjustment {
+            None => {
+                debug!("No pat_adjustments for node {:?}", hir_id);
+            }
+
+            Some(adjustment) => {
+                let resolved_adjustment = self.resolve(&adjustment, &span);
+                debug!("pat_adjustments for node {:?}: {:?}", hir_id, resolved_adjustment);
+                self.tables.pat_adjustments_mut().insert(hir_id, resolved_adjustment);
+            }
+        }
+    }
+
     fn visit_generator_interiors(&mut self) {
         let common_local_id_root = self.fcx.tables.borrow().local_id_root.unwrap();
         for (&id, interior) in self.fcx.tables.borrow().generator_interiors().iter() {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 1dac0433f14..a2f29181a20 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -395,6 +395,9 @@ declare_features! (
 
     // allow `..=` in patterns (RFC 1192)
     (active, dotdoteq_in_patterns, "1.22.0", Some(28237)),
+
+    // Default match binding modes (RFC 2005)
+    (active, match_default_bindings, "1.22.0", Some(42640)),
 );
 
 declare_features! (
diff --git a/src/test/compile-fail/feature-gate-match_default_bindings.rs b/src/test/compile-fail/feature-gate-match_default_bindings.rs
new file mode 100644
index 00000000000..2b3bf94eadc
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-match_default_bindings.rs
@@ -0,0 +1,16 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main() {
+    match &Some(3) {
+        Some(n) => {}, //~ ERROR mismatched types [E0308]
+        _ => panic!(),
+    }
+}
diff --git a/src/test/compile-fail/issue-20261.rs b/src/test/compile-fail/issue-20261.rs
index 2f1910b26bb..7b5e61380f2 100644
--- a/src/test/compile-fail/issue-20261.rs
+++ b/src/test/compile-fail/issue-20261.rs
@@ -9,7 +9,8 @@
 // except according to those terms.
 
 fn main() {
-    for (ref i,) in [].iter() { //~ ERROR mismatched types
+    // NB: this (almost) typechecks when default binding modes are enabled.
+    for (ref i,) in [].iter() { //~ ERROR mismatched types [E0308]
         i.clone();
     }
 }
diff --git a/src/test/compile-fail/issue-7867.rs b/src/test/compile-fail/issue-7867.rs
index 7d9f8e90585..016df6cb6ef 100644
--- a/src/test/compile-fail/issue-7867.rs
+++ b/src/test/compile-fail/issue-7867.rs
@@ -21,17 +21,4 @@ fn main() {
         //~| expected tuple, found enum `A`
         _ => ()
     }
-
-    match &Some(42) {
-        Some(x) => (),
-        //~^ ERROR mismatched types
-        //~| expected type `&std::option::Option<{integer}>`
-        //~| found type `std::option::Option<_>`
-        //~| expected reference, found enum `std::option::Option`
-        None => ()
-        //~^ ERROR mismatched types
-        //~| expected type `&std::option::Option<{integer}>`
-        //~| found type `std::option::Option<_>`
-        //~| expected reference, found enum `std::option::Option`
-    }
 }
diff --git a/src/test/compile-fail/match-vec-mismatch.rs b/src/test/compile-fail/match-vec-mismatch.rs
index 11c04e38035..d72ec8ba408 100644
--- a/src/test/compile-fail/match-vec-mismatch.rs
+++ b/src/test/compile-fail/match-vec-mismatch.rs
@@ -17,8 +17,9 @@ fn main() {
         _ => { }
     };
 
+    // Note that this one works with default binding modes.
     match &[0, 1, 2] {
-        [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]`
+        [..] => {} //~ ERROR expected an array or slice, found `&[{integer}; 3]` [E0529]
     };
 
     match &[0, 1, 2] {
diff --git a/src/test/compile-fail/pat-slice-old-style.rs b/src/test/compile-fail/pat-slice-old-style.rs
index ccb25d859ac..54028ffa63f 100644
--- a/src/test/compile-fail/pat-slice-old-style.rs
+++ b/src/test/compile-fail/pat-slice-old-style.rs
@@ -10,13 +10,19 @@
 
 #![feature(slice_patterns)]
 
+// NB: this test was introduced in #23121 and will have to change when default match binding modes
+// stabilizes.
+
 fn slice_pat(x: &[u8]) {
     // OLD!
     match x {
-        [a, b..] => {}
+        [a, b..] => {},
         //~^ ERROR expected an array or slice, found `&[u8]`
         //~| HELP the semantics of slice patterns changed recently; see issue #23121
+        _ => panic!(),
     }
 }
 
-fn main() {}
+fn main() {
+    slice_pat("foo".as_bytes());
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/box.rs b/src/test/run-pass/rfc-2005-default-binding-mode/box.rs
new file mode 100644
index 00000000000..85453f32208
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/box.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(box_syntax, box_patterns)]
+#![feature(match_default_bindings)]
+
+struct Foo{}
+
+pub fn main() {
+    let b = box Foo{};
+    let box f = &b;
+    let _: &Foo = f;
+
+    match &&&b {
+        box f => {
+            let _: &Foo = f;
+        },
+        _ => panic!(),
+    }
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/constref.rs b/src/test/run-pass/rfc-2005-default-binding-mode/constref.rs
new file mode 100644
index 00000000000..1b8fdbaa4d7
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/constref.rs
@@ -0,0 +1,51 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+const CONST_REF: &[u8; 3] = b"foo";
+
+trait Foo {
+    const CONST_REF_DEFAULT: &'static [u8; 3] = b"bar";
+    const CONST_REF: &'static [u8; 3];
+}
+
+impl Foo for i32 {
+    const CONST_REF: &'static [u8; 3] = b"jjj";
+}
+
+impl Foo for i64 {
+    const CONST_REF_DEFAULT: &'static [u8; 3] = b"ggg";
+    const CONST_REF: &'static [u8; 3] = b"fff";
+}
+
+// Check that (associated and free) const references are not mistaken for a
+// non-reference pattern (in which case they would be auto-dereferenced, making
+// the types mismatched).
+
+fn const_ref() -> bool {
+    let f = b"foo";
+    match f {
+        CONST_REF => true,
+        _ => false,
+    }
+}
+
+fn associated_const_ref() -> bool {
+    match (b"bar", b"jjj", b"ggg", b"fff") {
+        (i32::CONST_REF_DEFAULT, i32::CONST_REF, i64::CONST_REF_DEFAULT, i64::CONST_REF) => true,
+        _ => false,
+    }
+}
+
+pub fn main() {
+    assert!(const_ref());
+    assert!(associated_const_ref());
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/enum.rs b/src/test/run-pass/rfc-2005-default-binding-mode/enum.rs
new file mode 100644
index 00000000000..a7b3db021b0
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/enum.rs
@@ -0,0 +1,56 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+enum Wrapper {
+    Wrap(i32),
+}
+
+use Wrapper::Wrap;
+
+pub fn main() {
+    let Wrap(x) = &Wrap(3);
+    println!("{}", *x);
+
+    let Wrap(x) = &mut Wrap(3);
+    println!("{}", *x);
+
+    if let Some(x) = &Some(3) {
+        println!("{}", *x);
+    } else {
+        panic!();
+    }
+
+    if let Some(x) = &mut Some(3) {
+        println!("{}", *x);
+    } else {
+        panic!();
+    }
+
+    if let Some(x) = &mut Some(3) {
+        *x += 1;
+    } else {
+        panic!();
+    }
+
+    while let Some(x) = &Some(3) {
+        println!("{}", *x);
+        break;
+    }
+    while let Some(x) = &mut Some(3) {
+        println!("{}", *x);
+        break;
+    }
+    while let Some(x) = &mut Some(3) {
+        *x += 1;
+        break;
+    }
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/for.rs b/src/test/run-pass/rfc-2005-default-binding-mode/for.rs
new file mode 100644
index 00000000000..4feab94a7ed
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/for.rs
@@ -0,0 +1,31 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+pub fn main() {
+    let mut tups = vec![(0u8, 1u8)];
+
+    for (n, m) in &tups {
+        let _: &u8 = n;
+        let _: &u8 = m;
+    }
+
+    for (n, m) in &mut tups {
+        *n += 1;
+        *m += 2;
+    }
+
+    assert_eq!(tups, vec![(1u8, 3u8)]);
+
+    for (n, m) in tups {
+        println!("{} {}", m, n);
+    }
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/general.rs b/src/test/run-pass/rfc-2005-default-binding-mode/general.rs
new file mode 100644
index 00000000000..779a38bdb16
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/general.rs
@@ -0,0 +1,259 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+fn some_or_wildcard(r: &Option<i32>, b: &i32) {
+    let _: &i32 = match r {
+        Some(a) => a,
+        _ => b,
+    };
+}
+
+fn none_or_wildcard(r: &Option<i32>, b: &i32) {
+    let _: &i32 = match r {
+        None => b,
+        _ => b,
+    };
+}
+
+fn some_or_ref_none(r: &Option<i32>, b: &i32) {
+    let _: &i32 = match r {
+        Some(a) => a,
+        &None => b,
+    };
+}
+
+fn ref_some_or_none(r: &Option<i32>, b: &i32) {
+    let _: &i32 = match r {
+        &Some(ref a) => a,
+        None => b,
+    };
+}
+
+fn some_or_self(r: &Option<i32>) {
+    let _: &Option<i32> = match r {
+        Some(n) => {
+            let _: &i32 = n;
+            r
+        },
+        x => x,
+    };
+}
+
+fn multiple_deref(r: &&&&&Option<i32>) {
+    let _: i32 = match r {
+        Some(a) => *a,
+        None => 5,
+    };
+}
+
+fn match_with_or() {
+    // FIXME(tschottdorf): #44912.
+    //
+    // let x = &Some((3, 3));
+    // let _: &i32 = match x {
+    //     Some((x, 3)) | &Some((ref x, 5)) => x,
+    //     _ => &5i32,
+    // };
+}
+
+fn nested_mixed() {
+    match (&Some(5), &Some(6)) {
+        (Some(a), &Some(mut b)) => {
+            // Here, the `a` will be `&i32`, because in the first half of the tuple
+            // we hit a non-reference pattern and shift into `ref` mode.
+            //
+            // In the second half of the tuple there's no non-reference pattern,
+            // so `b` will be `i32` (bound with `move` mode). Moreover, `b` is
+            // mutable.
+            let _: &i32 = a;
+            b = 7;
+            let _: i32 = b;
+        },
+        _ => {},
+    };
+}
+
+fn nested_mixed_multiple_deref_1() {
+    let x = (1, &Some(5));
+    let y = &Some(x);
+    match y {
+        Some((a, Some(b))) => {
+            let _: &i32 = a;
+            let _: &i32 = b;
+        },
+        _ => {},
+    };
+}
+
+fn nested_mixed_multiple_deref_2() {
+    let x = &Some(5);
+    let y = &x;
+    match y {
+        Some(z) => {
+            let _: &i32 = z;
+        },
+        _ => {},
+    }
+}
+
+fn new_mutable_reference() {
+    let mut x = &mut Some(5);
+    match &mut x {
+        Some(y) => {
+            *y = 5;
+        },
+        None => { },
+    }
+
+    match &mut x {
+        Some(y) => {
+            println!("{}", *y);
+        },
+        None => {},
+    }
+}
+
+fn let_implicit_ref_binding() {
+    struct Foo(i32);
+
+    // Note that these rules apply to any pattern matching
+    // whether it be in a `match` or a `let`.
+    // For example, `x` here is a `ref` binding:
+    let Foo(x) = &Foo(3);
+    let _: &i32 = x;
+}
+
+fn explicit_mut_binding() {
+    match &Some(5i32) {
+        Some(mut n) => {
+            n += 1;
+            let _ = n;
+        }
+        None => {},
+    };
+
+    match &mut Some(5i32) {
+        Some(n) => {
+            *n += 1;
+            let _ = n;
+        }
+        None => {},
+    };
+
+    match &mut &mut Some(5i32) {
+        Some(n) => {
+             let _: &mut i32 = n;
+        }
+        None => {},
+    };
+}
+
+fn tuple_mut_and_mut_mut() {
+    match (Some(5i32), &Some(5i32)) {
+        (Some(n), Some(m)) => {
+            // `n` and `m` are bound as immutable references. Make new references from them to
+            // assert that.
+            let r = n;
+            let _ = r;
+            let q = m;
+            let _ = q;
+
+            // Assert the types. Note that we use `n` and `m` here which would fail had they been
+            // moved due to the assignments above.
+            let _: i32 = n;
+            let _: &i32 = m;
+        }
+        (_, _) => {},
+    };
+
+    match (&Some(5i32), &&Some(5i32)) {
+        (Some(n), Some(m)) => {
+            let _: &i32 = n;
+            let _: &i32 = m;
+        }
+        (_, _) => {},
+    };
+
+    match &mut &mut (Some(5i32), Some(5i32)) {
+        (Some(n), Some(m)) => {
+            // Dereferenced through &mut &mut, so a mutable binding results.
+            let _: &mut i32 = n;
+            let _: &mut i32 = m;
+        }
+        (_, _) => {},
+    };
+
+    match (&mut Some(5i32), &mut &mut Some(5i32)) {
+        (Some(n), Some(m)) => {
+            let _: &mut i32 = n;
+            let _: &mut i32 = m;
+        }
+        (_, _) => {},
+    };
+}
+
+fn min_mir_embedded_type() {
+    // The reduced invocation that an ICE was diagnosed with (was consuming
+    // adjustments in wrong order).
+    match (0u8, &&Some(5i32)) {
+        (_, Some(m)) => {
+            let _: &i32 = m;
+        }
+        (_, _) => {},
+    };
+}
+
+fn no_autoderef() {
+    // Binding.
+    let x = &3;
+    println!("{}", *x);
+
+    // Wildcard.
+    let _ = &3;
+
+    // Constant of generic type (string)
+    const Y: &'static str = "foo";
+    assert_eq!(0, match "foo" {
+        Y => 0,
+        _ => 1,
+    });
+
+    // Reference pattern.
+    let &x = &3;
+}
+
+pub fn main() {
+    let r: &Option<i32> = &Some(3);
+    let b = &4i32;
+
+    none_or_wildcard(r, b);
+    some_or_wildcard(r, b);
+    some_or_ref_none(r, b);
+    ref_some_or_none(r, b);
+
+    some_or_self(r);
+    multiple_deref(&&&&r);
+    match_with_or();
+
+    nested_mixed();
+    nested_mixed_multiple_deref_1();
+    nested_mixed_multiple_deref_2();
+
+    new_mutable_reference();
+    explicit_mut_binding();
+    tuple_mut_and_mut_mut();
+    min_mir_embedded_type();
+
+    let_implicit_ref_binding();
+
+    no_autoderef();
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/lit.rs b/src/test/run-pass/rfc-2005-default-binding-mode/lit.rs
new file mode 100644
index 00000000000..0b2a8e52fbf
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/lit.rs
@@ -0,0 +1,44 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+fn with_u8() {
+    let s = 5u8;
+    let r = match &s {
+        4 => false,
+        5 => true,
+        _ => false,
+    };
+    assert!(r);
+}
+
+// A string literal isn't mistaken for a non-ref pattern (in which case we'd
+// deref `s` and mess things up).
+fn with_str() {
+    let s: &'static str = "abc";
+    match s {
+            "abc" => true,
+            _ => panic!(),
+    };
+}
+
+// Ditto with byte strings.
+fn with_bytes() {
+    let s: &'static [u8] = b"abc";
+    match s {
+        b"abc" => true,
+        _ => panic!(),
+    };
+}
+
+pub fn main() {
+    with_str();
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/range.rs b/src/test/run-pass/rfc-2005-default-binding-mode/range.rs
new file mode 100644
index 00000000000..aafaa4cca82
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/range.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+pub fn main() {
+    let i = 5;
+    match &&&&i {
+        1 ... 3 => panic!(),
+        3 ... 8 => {},
+        _ => panic!(),
+    }
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/ref-region.rs b/src/test/run-pass/rfc-2005-default-binding-mode/ref-region.rs
new file mode 100644
index 00000000000..de7df011b56
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/ref-region.rs
@@ -0,0 +1,27 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+fn foo<'a, 'b>(x: &'a &'b Option<u32>) -> &'a u32 {
+    let x: &'a &'a Option<u32> = x;
+    match x {
+        Some(r) => {
+            let _: &u32 = r;
+            r
+        },
+        &None => panic!(),
+    }
+}
+
+pub fn main() {
+    let x = Some(5);
+    foo(&&x);
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/slice.rs b/src/test/run-pass/rfc-2005-default-binding-mode/slice.rs
new file mode 100644
index 00000000000..1717d0d54c0
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/slice.rs
@@ -0,0 +1,36 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(slice_patterns)]
+#![feature(match_default_bindings)]
+
+fn slice_pat() {
+    let sl: &[u8] = b"foo";
+
+    match sl {
+        [first, remainder..] => {
+            let _: &u8 = first;
+            assert_eq!(first, &b'f');
+            assert_eq!(remainder, b"oo");
+        }
+        [] => panic!(),
+    }
+}
+
+fn slice_pat_omission() {
+     match &[0, 1, 2] {
+        [..] => {}
+     };
+}
+
+fn main() {
+    slice_pat();
+    slice_pat_omission();
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/struct.rs b/src/test/run-pass/rfc-2005-default-binding-mode/struct.rs
new file mode 100644
index 00000000000..11a675c0c72
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/struct.rs
@@ -0,0 +1,33 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+#[derive(Debug, PartialEq)]
+struct Foo {
+    x: u8,
+}
+
+pub fn main() {
+    let mut foo = Foo {
+        x: 1,
+    };
+
+    match &mut foo {
+        Foo{x: n} => {
+            *n += 1;
+        },
+    };
+
+    assert_eq!(foo, Foo{x: 2});
+
+    let Foo{x: n} = &foo;
+    assert_eq!(*n, 2);
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/tuple-struct.rs b/src/test/run-pass/rfc-2005-default-binding-mode/tuple-struct.rs
new file mode 100644
index 00000000000..7867d652905
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/tuple-struct.rs
@@ -0,0 +1,29 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+enum Foo {
+    Bar(Option<i8>, (), (), Vec<i32>),
+    Baz,
+}
+
+pub fn main() {
+    let foo = Foo::Bar(Some(1), (), (), vec![2, 3]);
+
+    match &foo {
+        Foo::Baz => panic!(),
+        Foo::Bar(None, ..) => panic!(),
+        Foo::Bar(Some(n), .., v) => {
+            assert_eq!((*v).len(), 2);
+            assert_eq!(*n, 1);
+        }
+    }
+}
diff --git a/src/test/run-pass/rfc-2005-default-binding-mode/tuple.rs b/src/test/run-pass/rfc-2005-default-binding-mode/tuple.rs
new file mode 100644
index 00000000000..cf27265b2ed
--- /dev/null
+++ b/src/test/run-pass/rfc-2005-default-binding-mode/tuple.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+pub fn main() {
+    let foo = (Some(1), (), (), vec![2, 3]);
+
+    match &foo {
+        (Some(n), .., v) => {
+            assert_eq!((*v).len(), 2);
+            assert_eq!(*n, 1);
+        }
+        (None, (), (), ..) => panic!(),
+    }
+}
diff --git a/src/test/ui/const-expr-addr-operator.rs b/src/test/ui/const-expr-addr-operator.rs
new file mode 100644
index 00000000000..282b0d4e45b
--- /dev/null
+++ b/src/test/ui/const-expr-addr-operator.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Encountered while testing #44614.
+
+pub fn main() {
+    // Constant of generic type (int)
+    const X: &'static u32 = &22;
+    assert_eq!(0, match &22 {
+        X => 0,
+        _ => 1,
+    });
+}
\ No newline at end of file
diff --git a/src/test/ui/const-expr-addr-operator.stderr b/src/test/ui/const-expr-addr-operator.stderr
new file mode 100644
index 00000000000..5bda81451d0
--- /dev/null
+++ b/src/test/ui/const-expr-addr-operator.stderr
@@ -0,0 +1,14 @@
+error[E0080]: constant evaluation error
+  --> $DIR/const-expr-addr-operator.rs:15:29
+   |
+15 |     const X: &'static u32 = &22;
+   |                             ^^^ unimplemented constant expression: address operator
+   |
+note: for pattern here
+  --> $DIR/const-expr-addr-operator.rs:17:9
+   |
+17 |         X => 0,
+   |         ^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/mismatched_types/issue-38371.rs b/src/test/ui/mismatched_types/issue-38371.rs
index cf66330017f..6b49079c472 100644
--- a/src/test/ui/mismatched_types/issue-38371.rs
+++ b/src/test/ui/mismatched_types/issue-38371.rs
@@ -25,6 +25,8 @@ fn qux(foo: &Foo) {
 fn zar(&foo: &Foo) {
 }
 
+// The somewhat unexpected help message in this case is courtesy of
+// match_default_bindings.
 fn agh(&&bar: &u32) {
 }
 
diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr
index 9efee4cc559..c80f075021e 100644
--- a/src/test/ui/mismatched_types/issue-38371.stderr
+++ b/src/test/ui/mismatched_types/issue-38371.stderr
@@ -9,27 +9,28 @@ error[E0308]: mismatched types
    = help: did you mean `foo: &Foo`?
 
 error[E0308]: mismatched types
-  --> $DIR/issue-38371.rs:28:9
+  --> $DIR/issue-38371.rs:30:9
    |
-28 | fn agh(&&bar: &u32) {
+30 | fn agh(&&bar: &u32) {
    |         ^^^^ expected u32, found reference
    |
    = note: expected type `u32`
               found type `&_`
+   = help: did you mean `bar: &u32`?
 
 error[E0308]: mismatched types
-  --> $DIR/issue-38371.rs:31:8
+  --> $DIR/issue-38371.rs:33:8
    |
-31 | fn bgh(&&bar: u32) {
+33 | fn bgh(&&bar: u32) {
    |        ^^^^^ expected u32, found reference
    |
    = note: expected type `u32`
               found type `&_`
 
 error[E0529]: expected an array or slice, found `u32`
-  --> $DIR/issue-38371.rs:34:9
+  --> $DIR/issue-38371.rs:36:9
    |
-34 | fn ugh(&[bar]: &u32) {
+36 | fn ugh(&[bar]: &u32) {
    |         ^^^^^ pattern cannot match with input type `u32`
 
 error: aborting due to 4 previous errors
diff --git a/src/test/ui/rfc-2005-default-binding-mode/const.rs b/src/test/ui/rfc-2005-default-binding-mode/const.rs
new file mode 100644
index 00000000000..31923343b6a
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/const.rs
@@ -0,0 +1,29 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// FIXME(tschottdorf): this test should pass.
+
+#![feature(match_default_bindings)]
+
+#[derive(PartialEq, Eq)]
+struct Foo {
+    bar: i32,
+}
+
+const FOO: Foo = Foo{bar: 5};
+
+fn main() {
+    let f = Foo{bar:6};
+
+    match &f {
+        FOO => {},
+        _ => panic!(),
+    }
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/const.stderr b/src/test/ui/rfc-2005-default-binding-mode/const.stderr
new file mode 100644
index 00000000000..0dfd79f3565
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/const.stderr
@@ -0,0 +1,11 @@
+error[E0308]: mismatched types
+  --> $DIR/const.rs:26:9
+   |
+26 |         FOO => {},
+   |         ^^^ expected &Foo, found struct `Foo`
+   |
+   = note: expected type `&Foo`
+              found type `Foo`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.rs b/src/test/ui/rfc-2005-default-binding-mode/enum.rs
new file mode 100644
index 00000000000..58902bf06b3
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/enum.rs
@@ -0,0 +1,34 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+enum Wrapper {
+    Wrap(i32),
+}
+
+use Wrapper::Wrap;
+
+pub fn main() {
+    let Wrap(x) = &Wrap(3);
+    *x += 1;
+
+
+    if let Some(x) = &Some(3) {
+        *x += 1;
+    } else {
+        panic!();
+    }
+
+    while let Some(x) = &Some(3) {
+        *x += 1;
+        break;
+    }
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/enum.stderr b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr
new file mode 100644
index 00000000000..ad08ae83a49
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/enum.stderr
@@ -0,0 +1,26 @@
+error[E0594]: cannot assign to immutable borrowed content `*x`
+  --> $DIR/enum.rs:21:5
+   |
+20 |     let Wrap(x) = &Wrap(3);
+   |              - consider changing this to `x`
+21 |     *x += 1;
+   |     ^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to immutable borrowed content `*x`
+  --> $DIR/enum.rs:25:9
+   |
+24 |     if let Some(x) = &Some(3) {
+   |                 - consider changing this to `x`
+25 |         *x += 1;
+   |         ^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to immutable borrowed content `*x`
+  --> $DIR/enum.rs:31:9
+   |
+30 |     while let Some(x) = &Some(3) {
+   |                    - consider changing this to `x`
+31 |         *x += 1;
+   |         ^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs
new file mode 100644
index 00000000000..b5287b7cccc
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.rs
@@ -0,0 +1,40 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+// Verify the binding mode shifts - only when no `&` are auto-dereferenced is the
+// final default binding mode mutable.
+
+fn main() {
+    match &&Some(5i32) {
+        Some(n) => {
+            *n += 1;
+            let _ = n;
+        }
+        None => {},
+    };
+
+    match &mut &Some(5i32) {
+        Some(n) => {
+            *n += 1;
+            let _ = n;
+        }
+        None => {},
+    };
+
+    match &&mut Some(5i32) {
+        Some(n) => {
+            *n += 1;
+            let _ = n;
+        }
+        None => {},
+    };
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr
new file mode 100644
index 00000000000..1dbd769373b
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/explicit-mut.stderr
@@ -0,0 +1,26 @@
+error[E0594]: cannot assign to immutable borrowed content `*n`
+  --> $DIR/explicit-mut.rs:19:13
+   |
+18 |         Some(n) => {
+   |              - consider changing this to `n`
+19 |             *n += 1;
+   |             ^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to immutable borrowed content `*n`
+  --> $DIR/explicit-mut.rs:27:13
+   |
+26 |         Some(n) => {
+   |              - consider changing this to `n`
+27 |             *n += 1;
+   |             ^^^^^^^ cannot borrow as mutable
+
+error[E0594]: cannot assign to immutable borrowed content `*n`
+  --> $DIR/explicit-mut.rs:35:13
+   |
+34 |         Some(n) => {
+   |              - consider changing this to `n`
+35 |             *n += 1;
+   |             ^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfc-2005-default-binding-mode/for.rs
new file mode 100644
index 00000000000..35f8fbb9b71
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/for.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+struct Foo {}
+
+pub fn main() {
+    let mut tups = vec![(Foo{}, Foo{})];
+    // The below desugars to &(ref n, mut m).
+    for (n, mut m) in &tups {
+    }
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr
new file mode 100644
index 00000000000..795dffb722a
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr
@@ -0,0 +1,10 @@
+error[E0009]: cannot bind by-move and by-ref in the same pattern
+  --> $DIR/for.rs:18:13
+   |
+18 |     for (n, mut m) in &tups {
+   |          -  ^^^^^ by-move pattern here
+   |          |
+   |          both by-ref and by-move used
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs
new file mode 100644
index 00000000000..294d6b88596
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.rs
@@ -0,0 +1,21 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+// FIXME(tschottdorf): This should compile. See #44912.
+
+pub fn main() {
+    let x = &Some((3, 3));
+    let _: &i32 = match x {
+        Some((x, 3)) | &Some((ref x, 5)) => x,
+        _ => &5i32,
+    };
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr
new file mode 100644
index 00000000000..7430dc2c87f
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/issue-44912-or.stderr
@@ -0,0 +1,8 @@
+error[E0409]: variable `x` is bound in inconsistent ways within the same match arm
+  --> $DIR/issue-44912-or.rs:18:35
+   |
+18 |         Some((x, 3)) | &Some((ref x, 5)) => x,
+   |               - first binding     ^ bound in different ways
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2005-default-binding-mode/lit.rs b/src/test/ui/rfc-2005-default-binding-mode/lit.rs
new file mode 100644
index 00000000000..54cee39209b
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/lit.rs
@@ -0,0 +1,36 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(match_default_bindings)]
+
+// FIXME(tschottdorf): we want these to compile, but they don't.
+
+fn with_str() {
+    let s: &'static str = "abc";
+
+    match &s {
+            "abc" => true,
+            _ => panic!(),
+    };
+}
+
+fn with_bytes() {
+    let s: &'static [u8] = b"abc";
+
+    match &s {
+        b"abc" => true,
+        _ => panic!(),
+    };
+}
+
+pub fn main() {
+    with_str();
+    with_bytes();
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/lit.stderr b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr
new file mode 100644
index 00000000000..811d3b8074f
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/lit.stderr
@@ -0,0 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/lit.rs:19:13
+   |
+19 |             "abc" => true,
+   |             ^^^^^ expected &str, found str
+   |
+   = note: expected type `&&str`
+              found type `&'static str`
+
+error[E0308]: mismatched types
+  --> $DIR/lit.rs:28:9
+   |
+28 |         b"abc" => true,
+   |         ^^^^^^ expected &[u8], found array of 3 elements
+   |
+   = note: expected type `&&[u8]`
+              found type `&'static [u8; 3]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/rfc-2005-default-binding-mode/no-double-error.rs b/src/test/ui/rfc-2005-default-binding-mode/no-double-error.rs
new file mode 100644
index 00000000000..a0134c499bb
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/no-double-error.rs
@@ -0,0 +1,21 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Without caching type lookups in FnCtxt.resolve_ty_and_def_ufcs
+// the error below would be reported twice (once when checking
+// for a non-ref pattern, once when processing the pattern).
+
+fn main() {
+    let foo = 22;
+    match foo {
+        u32::XXX => { }
+        _ => { }
+    }
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr b/src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr
new file mode 100644
index 00000000000..da065eea897
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/no-double-error.stderr
@@ -0,0 +1,8 @@
+error[E0599]: no associated item named `XXX` found for type `u32` in the current scope
+  --> $DIR/no-double-error.rs:18:9
+   |
+18 |         u32::XXX => { }
+   |         ^^^^^^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2005-default-binding-mode/slice.rs b/src/test/ui/rfc-2005-default-binding-mode/slice.rs
new file mode 100644
index 00000000000..fb87ed72abc
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/slice.rs
@@ -0,0 +1,20 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(slice_patterns)]
+#![feature(match_default_bindings)]
+
+pub fn main() {
+    let sl: &[u8] = b"foo";
+
+    match sl {
+        [first, remainder..] => {},
+    };
+}
diff --git a/src/test/ui/rfc-2005-default-binding-mode/slice.stderr b/src/test/ui/rfc-2005-default-binding-mode/slice.stderr
new file mode 100644
index 00000000000..90a2f75c07f
--- /dev/null
+++ b/src/test/ui/rfc-2005-default-binding-mode/slice.stderr
@@ -0,0 +1,8 @@
+error[E0004]: non-exhaustive patterns: `&[]` not covered
+  --> $DIR/slice.rs:17:11
+   |
+17 |     match sl {
+   |           ^^ pattern `&[]` not covered
+
+error: aborting due to previous error
+