about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_ast/src/ast.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs9
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs19
-rw-r--r--compiler/rustc_hir/src/hir.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/errs.rs42
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs2
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs54
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs5
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs14
-rw-r--r--compiler/rustc_middle/src/thir.rs39
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs10
-rw-r--r--compiler/rustc_middle/src/ty/binding.rs18
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs25
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs69
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs18
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs14
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs14
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs27
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs22
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs3
-rw-r--r--compiler/rustc_parse/messages.ftl3
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs16
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs39
31 files changed, 219 insertions, 303 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 915cb386075..aba94f4d817 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -702,19 +702,10 @@ pub struct PatField {
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
 pub enum ByRef {
-    Yes,
+    Yes(Mutability),
     No,
 }
 
-impl From<bool> for ByRef {
-    fn from(b: bool) -> ByRef {
-        match b {
-            false => ByRef::No,
-            true => ByRef::Yes,
-        }
-    }
-}
-
 /// Explicit binding annotations given in the HIR for a binding. Note
 /// that this is not the final binding *mode* that we infer after type
 /// inference.
@@ -724,9 +715,11 @@ pub struct BindingAnnotation(pub ByRef, pub Mutability);
 
 impl BindingAnnotation {
     pub const NONE: Self = Self(ByRef::No, Mutability::Not);
-    pub const REF: Self = Self(ByRef::Yes, Mutability::Not);
+    pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
     pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
-    pub const REF_MUT: Self = Self(ByRef::Yes, Mutability::Mut);
+    pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
+    pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
+    pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
 
     pub fn prefix_str(self) -> &'static str {
         match self {
@@ -734,6 +727,8 @@ impl BindingAnnotation {
             Self::REF => "ref ",
             Self::MUT => "mut ",
             Self::REF_MUT => "ref mut ",
+            Self::MUT_REF => "mut ref ",
+            Self::MUT_REF_MUT => "mut ref mut ",
         }
     }
 }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index b5b98659e2f..833b0e9b567 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1847,8 +1847,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     // the case where we have a mutable pattern to a reference as that would
                     // no longer be an `ImplicitSelf`.
                     TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
-                        hir::Mutability::Not => hir::ImplicitSelfKind::ImmRef,
-                        hir::Mutability::Mut => hir::ImplicitSelfKind::MutRef,
+                        hir::Mutability::Not => hir::ImplicitSelfKind::RefImm,
+                        hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut,
                     },
                     _ => hir::ImplicitSelfKind::None,
                 }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index a70daf1b644..3ea182c5867 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1545,12 +1545,15 @@ impl<'a> State<'a> {
             PatKind::Wild => self.word("_"),
             PatKind::Never => self.word("!"),
             PatKind::Ident(BindingAnnotation(by_ref, mutbl), ident, sub) => {
-                if *by_ref == ByRef::Yes {
-                    self.word_nbsp("ref");
-                }
                 if mutbl.is_mut() {
                     self.word_nbsp("mut");
                 }
+                if let ByRef::Yes(rmutbl) = by_ref {
+                    self.word_nbsp("ref");
+                    if rmutbl.is_mut() {
+                        self.word_nbsp("mut");
+                    }
+                }
                 self.print_ident(*ident);
                 if let Some(p) = sub {
                     self.space();
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 2aeea1dd341..26bb6800348 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -4,9 +4,8 @@
 use core::ops::ControlFlow;
 use hir::{ExprKind, Param};
 use rustc_errors::{Applicability, Diag};
-use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::Node;
+use rustc_hir::{self as hir, BindingAnnotation, ByRef, Node};
 use rustc_infer::traits;
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
 use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt};
@@ -304,7 +303,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 {
                     match *decl.local_info() {
                         LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
-                            binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+                            binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
                             opt_ty_info: Some(sp),
                             opt_match_place: _,
                             pat_span: _,
@@ -342,7 +341,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 } else if decl.mutability.is_not() {
                     if matches!(
                         decl.local_info(),
-                        LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef))
+                        LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::RefMut))
                     ) {
                         err.note(
                             "as `Self` may be unsized, this call attempts to take `&mut &mut self`",
@@ -407,7 +406,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                             if let Some(fn_decl) = node.fn_decl() {
                                 if !matches!(
                                     fn_decl.implicit_self,
-                                    hir::ImplicitSelfKind::ImmRef | hir::ImplicitSelfKind::MutRef
+                                    hir::ImplicitSelfKind::RefImm | hir::ImplicitSelfKind::RefMut
                                 ) {
                                     err.span_suggestion(
                                         upvar_ident.span,
@@ -717,7 +716,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         debug!("local_decl: {:?}", local_decl);
         let pat_span = match *local_decl.local_info() {
             LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
-                binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+                binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
                 opt_ty_info: _,
                 opt_match_place: _,
                 pat_span,
@@ -1070,7 +1069,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
 
             LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
-                binding_mode: ty::BindingMode::BindByValue(_),
+                binding_mode: BindingAnnotation(ByRef::No, _),
                 opt_ty_info,
                 ..
             })) => {
@@ -1138,7 +1137,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             }
 
             LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
-                binding_mode: ty::BindingMode::BindByReference(_),
+                binding_mode: BindingAnnotation(ByRef::Yes(_), _),
                 ..
             })) => {
                 let pattern_span: Span = local_decl.source_info.span;
@@ -1329,7 +1328,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
     match *local_decl.local_info() {
         // Check if mutably borrowing a mutable reference.
         LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
-            binding_mode: ty::BindingMode::BindByValue(Mutability::Not),
+            binding_mode: BindingAnnotation(ByRef::No, Mutability::Not),
             ..
         })) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
         LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
@@ -1338,7 +1337,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
             //
             // Deliberately fall into this case for all implicit self types,
             // so that we don't fall into the next case with them.
-            kind == hir::ImplicitSelfKind::MutRef
+            kind == hir::ImplicitSelfKind::RefMut
         }
         _ if Some(kw::SelfLower) == local_name => {
             // Otherwise, check if the name is the `self` keyword - in which case
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a70d2ebbd62..a0f86565929 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2733,9 +2733,9 @@ pub enum ImplicitSelfKind {
     /// Represents a `fn x(mut self);`.
     Mut,
     /// Represents a `fn x(&self);`.
-    ImmRef,
+    RefImm,
     /// Represents a `fn x(&mut self);`.
-    MutRef,
+    RefMut,
     /// Represents when a function does not have a self argument or
     /// when a function has a `self: X` argument.
     None,
diff --git a/compiler/rustc_hir_analysis/src/check/errs.rs b/compiler/rustc_hir_analysis/src/check/errs.rs
index f0c15a070b4..548f9b0810f 100644
--- a/compiler/rustc_hir_analysis/src/check/errs.rs
+++ b/compiler/rustc_hir_analysis/src/check/errs.rs
@@ -14,14 +14,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
         && matches!(borrow_kind, hir::BorrowKind::Ref)
         && let Some(var) = is_path_static_mut(*expr)
     {
-        handle_static_mut_ref(
-            tcx,
-            span,
-            var,
-            span.edition().at_least_rust_2024(),
-            matches!(m, Mutability::Mut),
-            hir_id,
-        );
+        handle_static_mut_ref(tcx, span, var, span.edition().at_least_rust_2024(), m, hir_id);
     }
 }
 
@@ -29,7 +22,7 @@ pub fn maybe_expr_static_mut(tcx: TyCtxt<'_>, expr: hir::Expr<'_>) {
 pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
     if let hir::StmtKind::Let(loc) = stmt.kind
         && let hir::PatKind::Binding(ba, _, _, _) = loc.pat.kind
-        && matches!(ba.0, rustc_ast::ByRef::Yes)
+        && let hir::ByRef::Yes(rmutbl) = ba.0
         && let Some(init) = loc.init
         && let Some(var) = is_path_static_mut(*init)
     {
@@ -38,7 +31,7 @@ pub fn maybe_stmt_static_mut(tcx: TyCtxt<'_>, stmt: hir::Stmt<'_>) {
             init.span,
             var,
             loc.span.edition().at_least_rust_2024(),
-            matches!(ba.1, Mutability::Mut),
+            rmutbl,
             stmt.hir_id,
         );
     }
@@ -60,28 +53,27 @@ fn handle_static_mut_ref(
     span: Span,
     var: String,
     e2024: bool,
-    mutable: bool,
+    mutable: Mutability,
     hir_id: hir::HirId,
 ) {
     if e2024 {
-        let (sugg, shared) = if mutable {
+        let (sugg, shared) = if mutable == Mutability::Mut {
             (errors::StaticMutRefSugg::Mut { span, var }, "mutable")
         } else {
             (errors::StaticMutRefSugg::Shared { span, var }, "shared")
         };
         tcx.sess.psess.dcx.emit_err(errors::StaticMutRef { span, sugg, shared });
-        return;
-    }
-
-    let (sugg, shared) = if mutable {
-        (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
     } else {
-        (errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
-    };
-    tcx.emit_node_span_lint(
-        STATIC_MUT_REFS,
-        hir_id,
-        span,
-        errors::RefOfMutStatic { span, sugg, shared },
-    );
+        let (sugg, shared) = if mutable == Mutability::Mut {
+            (errors::RefOfMutStaticSugg::Mut { span, var }, "mutable")
+        } else {
+            (errors::RefOfMutStaticSugg::Shared { span, var }, "shared")
+        };
+        tcx.emit_node_span_lint(
+            STATIC_MUT_REFS,
+            hir_id,
+            span,
+            errors::RefOfMutStatic { span, sugg, shared },
+        );
+    }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index dcabac6d780..3bdb9a214ec 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -654,7 +654,7 @@ fn resolve_local<'tcx>(
         // & expression, and its lifetime would be extended to the end of the block (due
         // to a different rule, not the below code).
         match pat.kind {
-            PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes, _), ..) => true,
+            PatKind::Binding(hir::BindingAnnotation(hir::ByRef::Yes(_), _), ..) => true,
 
             PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),
 
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 36f59b4ac2e..bd528432e70 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1721,12 +1721,15 @@ impl<'a> State<'a> {
             PatKind::Wild => self.word("_"),
             PatKind::Never => self.word("!"),
             PatKind::Binding(BindingAnnotation(by_ref, mutbl), _, ident, sub) => {
-                if by_ref == ByRef::Yes {
-                    self.word_nbsp("ref");
-                }
                 if mutbl.is_mut() {
                     self.word_nbsp("mut");
                 }
+                if let ByRef::Yes(rmutbl) = by_ref {
+                    self.word_nbsp("ref");
+                    if rmutbl.is_mut() {
+                        self.word_nbsp("mut");
+                    }
+                }
                 self.print_ident(ident);
                 if let Some(p) = sub {
                     self.word("@");
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 3b6accb92ae..5986b959666 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -739,12 +739,12 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                     // In a cases of pattern like `let pat = upvar`, don't use the span
                     // of the pattern, as this just looks confusing, instead use the span
                     // of the discriminant.
-                    match bm {
-                        ty::BindByReference(m) => {
+                    match bm.0 {
+                        hir::ByRef::Yes(m) => {
                             let bk = ty::BorrowKind::from_mutbl(m);
                             delegate.borrow(place, discr_place.hir_id, bk);
                         }
-                        ty::BindByValue(..) => {
+                        hir::ByRef::No => {
                             debug!("walk_pat binding consuming pat");
                             delegate_consume(mc, *delegate, place, discr_place.hir_id);
                         }
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index f5b6dd162b3..f2425d03449 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -206,7 +206,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                     .get(pat.hir_id)
                     .expect("missing binding mode");
 
-                if let ty::BindByReference(_) = bm {
+                if matches!(bm.0, hir::ByRef::Yes(_)) {
                     // a bind-by-ref means that the base_ty will be the type of the ident itself,
                     // but what we want here is the type of the underlying value being borrowed.
                     // So peel off one-level, turning the &T into T.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 861a00ce874..9d247c46bab 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -5,14 +5,13 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
 };
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
-use rustc_hir::{HirId, Pat, PatKind};
+use rustc_hir::{self as hir, BindingAnnotation, ByRef, HirId, Mutability, Pat, PatKind};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::mir::interpret::ErrorHandled;
-use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self, Adt, Ty, TypeVisitableExt};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
@@ -79,7 +78,7 @@ struct TopInfo<'tcx> {
 
 #[derive(Copy, Clone)]
 struct PatInfo<'tcx, 'a> {
-    binding_mode: BindingMode,
+    binding_mode: BindingAnnotation,
     top_info: TopInfo<'tcx>,
     decl_origin: Option<DeclOrigin<'a>>,
 
@@ -124,7 +123,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
     }
 }
 
-const INITIAL_BM: BindingMode = BindingMode::BindByValue(hir::Mutability::Not);
+const INITIAL_BM: BindingAnnotation = BindingAnnotation(ByRef::No, Mutability::Not);
 
 /// Mode for adjusting the expected type and binding mode.
 enum AdjustMode {
@@ -269,9 +268,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         pat: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
-        def_bm: BindingMode,
+        def_bm: BindingAnnotation,
         adjust_mode: AdjustMode,
-    ) -> (Ty<'tcx>, BindingMode) {
+    ) -> (Ty<'tcx>, BindingAnnotation) {
         match adjust_mode {
             AdjustMode::Pass => (expected, def_bm),
             AdjustMode::Reset => (expected, INITIAL_BM),
@@ -354,8 +353,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         pat: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
-        mut def_bm: BindingMode,
-    ) -> (Ty<'tcx>, BindingMode) {
+        mut def_bm: BindingAnnotation,
+    ) -> (Ty<'tcx>, BindingAnnotation) {
         let mut expected = self.try_structurally_resolve_type(pat.span, expected);
         // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
         // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
@@ -374,15 +373,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             pat_adjustments.push(expected);
 
             expected = self.try_structurally_resolve_type(pat.span, inner_ty);
-            def_bm = ty::BindByReference(match def_bm {
+            def_bm.0 = ByRef::Yes(match def_bm.0 {
                 // If default binding mode is by value, make it `ref` or `ref mut`
                 // (depending on whether we observe `&` or `&mut`).
-                ty::BindByValue(_) |
+                ByRef::No |
                 // When `ref mut`, stay a `ref mut` (on `&mut`) or downgrade to `ref` (on `&`).
-                ty::BindByReference(hir::Mutability::Mut) => inner_mutability,
+                ByRef::Yes(Mutability::Mut) => inner_mutability,
                 // Once a `ref`, always a `ref`.
                 // This is because a `& &mut` cannot mutate the underlying value.
-                ty::BindByReference(m @ hir::Mutability::Not) => m,
+                ByRef::Yes(Mutability::Not) => Mutability::Not,
             });
         }
 
@@ -599,7 +598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn check_pat_ident(
         &self,
         pat: &'tcx Pat<'tcx>,
-        ba: hir::BindingAnnotation,
+        ba: BindingAnnotation,
         var_id: HirId,
         sub: Option<&'tcx Pat<'tcx>>,
         expected: Ty<'tcx>,
@@ -609,8 +608,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Determine the binding mode...
         let bm = match ba {
-            hir::BindingAnnotation::NONE => def_bm,
-            _ => BindingMode::convert(ba),
+            BindingAnnotation(ByRef::No, Mutability::Not) => def_bm,
+            _ => ba,
         };
         // ...and store it in a side table:
         self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
@@ -618,8 +617,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("check_pat_ident: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
 
         let local_ty = self.local_ty(pat.span, pat.hir_id);
-        let eq_ty = match bm {
-            ty::BindByReference(mutbl) => {
+        let eq_ty = match bm.0 {
+            ByRef::Yes(mutbl) => {
                 // If the binding is like `ref x | ref mut x`,
                 // then `x` is assigned a value of type `&M T` where M is the
                 // mutability and T is the expected type.
@@ -630,10 +629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.new_ref_ty(pat.span, mutbl, expected)
             }
             // Otherwise, the type of x is the expected type `T`.
-            ty::BindByValue(_) => {
-                // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
-                expected
-            }
+            ByRef::No => expected, // As above, `T <: typeof(x)` is required, but we use equality, see (note_1).
         };
         self.demand_eqtype_pat(pat.span, eq_ty, local_ty, ti);
 
@@ -655,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// bindings have the same type by comparing them all against the type of that first pat.
     fn check_binding_alt_eq_ty(
         &self,
-        ba: hir::BindingAnnotation,
+        ba: BindingAnnotation,
         span: Span,
         var_id: HirId,
         ty: Ty<'tcx>,
@@ -695,10 +691,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
-        ba: hir::BindingAnnotation,
+        ba: BindingAnnotation,
     ) {
         match (expected.kind(), actual.kind(), ba) {
-            (ty::Ref(_, inner_ty, _), _, hir::BindingAnnotation::NONE)
+            (ty::Ref(_, inner_ty, _), _, BindingAnnotation::NONE)
                 if self.can_eq(self.param_env, *inner_ty, actual) =>
             {
                 err.span_suggestion_verbose(
@@ -708,7 +704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Applicability::MaybeIncorrect,
                 );
             }
-            (_, ty::Ref(_, inner_ty, _), hir::BindingAnnotation::REF)
+            (_, ty::Ref(_, inner_ty, _), BindingAnnotation::REF)
                 if self.can_eq(self.param_env, expected, *inner_ty) =>
             {
                 err.span_suggestion_verbose(
@@ -800,7 +796,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if let PatKind::Ref(the_ref, _) = i.kind
                             && let PatKind::Binding(mt, _, ident, _) = the_ref.kind
                         {
-                            let hir::BindingAnnotation(_, mtblty) = mt;
+                            let BindingAnnotation(_, mtblty) = mt;
                             err.span_suggestion_verbose(
                                 i.span,
                                 format!("consider removing `&{mutability}` from the pattern"),
@@ -2037,7 +2033,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         pat: &'tcx Pat<'tcx>,
         inner: &'tcx Pat<'tcx>,
-        mutbl: hir::Mutability,
+        mutbl: Mutability,
         expected: Ty<'tcx>,
         pat_info: PatInfo<'tcx, '_>,
     ) -> Ty<'tcx> {
@@ -2088,7 +2084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     /// Create a reference type with a fresh region variable.
-    fn new_ref_ty(&self, span: Span, mutbl: hir::Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
+    fn new_ref_ty(&self, span: Span, mutbl: Mutability, ty: Ty<'tcx>) -> Ty<'tcx> {
         let region = self.next_region_var(infer::PatternRegion(span));
         Ty::new_ref(self.tcx, region, ty, mutbl)
     }
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index e489b431e81..54344adaabd 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -1711,10 +1711,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
 
-        let mut is_mutbl = match bm {
-            ty::BindByValue(mutability) => mutability,
-            ty::BindByReference(_) => hir::Mutability::Not,
-        };
+        let mut is_mutbl = bm.1;
 
         for pointer_ty in place.deref_tys() {
             match pointer_ty.kind() {
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 02af55fbf0e..e5a650c5ac4 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -17,8 +17,10 @@ use rustc_data_structures::captures::Captures;
 use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, ErrorGuaranteed, IntoDiagArg};
 use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
-use rustc_hir::{self, CoroutineDesugaring, CoroutineKind, ImplicitSelfKind};
-use rustc_hir::{self as hir, HirId};
+use rustc_hir::{
+    self as hir, BindingAnnotation, ByRef, CoroutineDesugaring, CoroutineKind, HirId,
+    ImplicitSelfKind,
+};
 use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 use rustc_target::abi::{FieldIdx, VariantIdx};
@@ -992,8 +994,8 @@ pub enum LocalKind {
 
 #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct VarBindingForm<'tcx> {
-    /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`?
-    pub binding_mode: ty::BindingMode,
+    /// Is variable bound via `x`, `mut x`, `ref x`, `ref mut x`, `mut ref x`, or `mut ref mut x`?
+    pub binding_mode: BindingAnnotation,
     /// If an explicit type was provided for this variable binding,
     /// this holds the source Span of that type.
     ///
@@ -1218,7 +1220,7 @@ impl<'tcx> LocalDecl<'tcx> {
             self.local_info(),
             LocalInfo::User(
                 BindingForm::Var(VarBindingForm {
-                    binding_mode: ty::BindingMode::BindByValue(_),
+                    binding_mode: BindingAnnotation(ByRef::No, _),
                     opt_ty_info: _,
                     opt_match_place: _,
                     pat_span: _,
@@ -1235,7 +1237,7 @@ impl<'tcx> LocalDecl<'tcx> {
             self.local_info(),
             LocalInfo::User(
                 BindingForm::Var(VarBindingForm {
-                    binding_mode: ty::BindingMode::BindByValue(_),
+                    binding_mode: BindingAnnotation(ByRef::No, _),
                     opt_ty_info: _,
                     opt_match_place: _,
                     pat_span: _,
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index f684f83a261..367f6b2a304 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -12,12 +12,12 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
-use rustc_hir::RangeEnd;
+use rustc_hir::{BindingAnnotation, ByRef, RangeEnd};
 use rustc_index::newtype_index;
 use rustc_index::IndexVec;
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::{AllocId, Scalar};
-use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp};
+use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, UnOp};
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{
@@ -581,12 +581,6 @@ pub enum InlineAsmOperand<'tcx> {
     },
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, HashStable)]
-pub enum BindingMode {
-    ByValue,
-    ByRef(BorrowKind),
-}
-
 #[derive(Clone, Debug, HashStable, TypeVisitable)]
 pub struct FieldPat<'tcx> {
     pub field: FieldIdx,
@@ -607,19 +601,22 @@ impl<'tcx> Pat<'tcx> {
 
     pub fn simple_ident(&self) -> Option<Symbol> {
         match self.kind {
-            PatKind::Binding { name, mode: BindingMode::ByValue, subpattern: None, .. } => {
-                Some(name)
-            }
+            PatKind::Binding {
+                name,
+                mode: BindingAnnotation(ByRef::No, _),
+                subpattern: None,
+                ..
+            } => Some(name),
             _ => None,
         }
     }
 
     /// Call `f` on every "binding" in a pattern, e.g., on `a` in
     /// `match foo() { Some(a) => (), None => () }`
-    pub fn each_binding(&self, mut f: impl FnMut(Symbol, BindingMode, Ty<'tcx>, Span)) {
+    pub fn each_binding(&self, mut f: impl FnMut(Symbol, ByRef, Ty<'tcx>, Span)) {
         self.walk_always(|p| {
             if let PatKind::Binding { name, mode, ty, .. } = p.kind {
-                f(name, mode, ty, p.span);
+                f(name, mode.0, ty, p.span);
             }
         });
     }
@@ -730,10 +727,9 @@ pub enum PatKind<'tcx> {
 
     /// `x`, `ref x`, `x @ P`, etc.
     Binding {
-        mutability: Mutability,
         name: Symbol,
         #[type_visitable(ignore)]
-        mode: BindingMode,
+        mode: BindingAnnotation,
         #[type_visitable(ignore)]
         var: LocalVarId,
         ty: Ty<'tcx>,
@@ -1073,17 +1069,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
             PatKind::Wild => write!(f, "_"),
             PatKind::Never => write!(f, "!"),
             PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{subpattern}: _"),
-            PatKind::Binding { mutability, name, mode, ref subpattern, .. } => {
-                let is_mut = match mode {
-                    BindingMode::ByValue => mutability == Mutability::Mut,
-                    BindingMode::ByRef(bk) => {
-                        write!(f, "ref ")?;
-                        matches!(bk, BorrowKind::Mut { .. })
-                    }
-                };
-                if is_mut {
-                    write!(f, "mut ")?;
-                }
+            PatKind::Binding { name, mode, ref subpattern, .. } => {
+                f.write_str(mode.prefix_str())?;
                 write!(f, "{name}")?;
                 if let Some(ref subpattern) = *subpattern {
                     write!(f, " @ {subpattern}")?;
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 99ab006bcc0..e42b85530b5 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -230,15 +230,7 @@ pub fn walk_pat<'thir, 'tcx: 'thir, V: Visitor<'thir, 'tcx>>(
         AscribeUserType { subpattern, ascription: _ }
         | Deref { subpattern }
         | DerefPattern { subpattern }
-        | Binding {
-            subpattern: Some(subpattern),
-            mutability: _,
-            mode: _,
-            var: _,
-            ty: _,
-            is_primary: _,
-            name: _,
-        } => visitor.visit_pat(subpattern),
+        | Binding { subpattern: Some(subpattern), .. } => visitor.visit_pat(subpattern),
         Binding { .. } | Wild | Never | Error(_) => {}
         Variant { subpatterns, adt_def: _, args: _, variant_index: _ } | Leaf { subpatterns } => {
             for subpattern in subpatterns {
diff --git a/compiler/rustc_middle/src/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs
deleted file mode 100644
index af594bc5f24..00000000000
--- a/compiler/rustc_middle/src/ty/binding.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-use rustc_hir::{BindingAnnotation, ByRef, Mutability};
-
-#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Debug, Copy, HashStable)]
-pub enum BindingMode {
-    BindByReference(Mutability),
-    BindByValue(Mutability),
-}
-
-TrivialTypeTraversalImpls! { BindingMode }
-
-impl BindingMode {
-    pub fn convert(BindingAnnotation(by_ref, mutbl): BindingAnnotation) -> BindingMode {
-        match by_ref {
-            ByRef::No => BindingMode::BindByValue(mutbl),
-            ByRef::Yes => BindingMode::BindByReference(mutbl),
-        }
-    }
-}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index aad2f6a4cf8..ae531b3aea6 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -76,8 +76,6 @@ pub use rustc_type_ir::ConstKind::{
 };
 pub use rustc_type_ir::*;
 
-pub use self::binding::BindingMode;
-pub use self::binding::BindingMode::*;
 pub use self::closure::{
     is_ancestor_or_same_capture, place_to_string_for_capture, BorrowKind, CaptureInfo,
     CapturedPlace, ClosureTypeInfo, MinCaptureInformationMap, MinCaptureList,
@@ -123,7 +121,6 @@ pub use self::typeck_results::{
 pub mod _match;
 pub mod abstract_const;
 pub mod adjustment;
-pub mod binding;
 pub mod cast;
 pub mod codec;
 pub mod error;
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index f14ca7ae4b7..a62379def53 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -402,6 +402,7 @@ TrivialTypeTraversalImpls! {
     ::rustc_span::symbol::Symbol,
     ::rustc_hir::def::Res,
     ::rustc_hir::def_id::LocalDefId,
+    ::rustc_hir::ByRef,
     ::rustc_hir::HirId,
     ::rustc_hir::MatchSource,
     ::rustc_target::asm::InlineAsmRegOrRegClass,
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 827b7e088ce..d60926bf796 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -3,8 +3,8 @@ use crate::{
     infer::canonical::Canonical,
     traits::ObligationCause,
     ty::{
-        self, tls, BindingMode, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData,
-        GenericArgKind, GenericArgs, GenericArgsRef, Ty, UserArgs,
+        self, tls, BoundVar, CanonicalPolyFnSig, ClosureSizeProfileData, GenericArgKind,
+        GenericArgs, GenericArgsRef, Ty, UserArgs,
     },
 };
 use rustc_data_structures::{
@@ -12,12 +12,12 @@ use rustc_data_structures::{
     unord::{ExtendUnord, UnordItems, UnordSet},
 };
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
 use rustc_hir::{
+    self as hir,
     def::{DefKind, Res},
     def_id::{DefId, LocalDefId, LocalDefIdMap},
     hir_id::OwnerId,
-    HirId, ItemLocalId, ItemLocalMap, ItemLocalSet,
+    BindingAnnotation, ByRef, HirId, ItemLocalId, ItemLocalMap, ItemLocalSet, Mutability,
 };
 use rustc_index::{Idx, IndexVec};
 use rustc_macros::HashStable;
@@ -78,8 +78,8 @@ pub struct TypeckResults<'tcx> {
 
     adjustments: ItemLocalMap<Vec<ty::adjustment::Adjustment<'tcx>>>,
 
-    /// Stores the actual binding mode for all instances of hir::BindingAnnotation.
-    pat_binding_modes: ItemLocalMap<BindingMode>,
+    /// Stores the actual binding mode for all instances of [`BindingAnnotation`].
+    pat_binding_modes: ItemLocalMap<BindingAnnotation>,
 
     /// Stores the types which were implicitly dereferenced in pattern binding modes
     /// for later usage in THIR lowering. For example,
@@ -408,17 +408,22 @@ impl<'tcx> TypeckResults<'tcx> {
         matches!(self.type_dependent_defs().get(expr.hir_id), Some(Ok((DefKind::AssocFn, _))))
     }
 
-    pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
+    pub fn extract_binding_mode(
+        &self,
+        s: &Session,
+        id: HirId,
+        sp: Span,
+    ) -> Option<BindingAnnotation> {
         self.pat_binding_modes().get(id).copied().or_else(|| {
             s.dcx().span_bug(sp, "missing binding mode");
         })
     }
 
-    pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingMode> {
+    pub fn pat_binding_modes(&self) -> LocalTableInContext<'_, BindingAnnotation> {
         LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_binding_modes }
     }
 
-    pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMode> {
+    pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingAnnotation> {
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
     }
 
@@ -442,7 +447,7 @@ impl<'tcx> TypeckResults<'tcx> {
         let mut has_ref_mut = false;
         pat.walk(|pat| {
             if let hir::PatKind::Binding(_, id, _, _) = pat.kind
-                && let Some(ty::BindByReference(ty::Mutability::Mut)) =
+                && let Some(BindingAnnotation(ByRef::Yes(Mutability::Mut), _)) =
                     self.pat_binding_modes().get(id)
             {
                 has_ref_mut = true;
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 4046122b6fe..6200f4bda6b 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -218,7 +218,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                             this.visit_primary_bindings(
                                 pattern,
                                 UserTypeProjections::none(),
-                                &mut |this, _, _, _, node, span, _, _| {
+                                &mut |this, _, _, node, span, _, _| {
                                     this.storage_live_binding(
                                         block,
                                         node,
@@ -308,7 +308,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         this.visit_primary_bindings(
                             pattern,
                             UserTypeProjections::none(),
-                            &mut |this, _, _, _, node, span, _, _| {
+                            &mut |this, _, _, node, span, _, _| {
                                 this.storage_live_binding(block, node, span, OutsideGuard, true);
                                 this.schedule_drop_for_binding(node, span, OutsideGuard);
                             },
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 6d083e66a9b..b4c98834d0a 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -14,6 +14,7 @@ use rustc_data_structures::{
     fx::{FxHashSet, FxIndexMap, FxIndexSet},
     stack::ensure_sufficient_stack,
 };
+use rustc_hir::{BindingAnnotation, ByRef};
 use rustc_middle::middle::region;
 use rustc_middle::mir::{self, *};
 use rustc_middle::thir::{self, *};
@@ -554,7 +555,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) -> BlockAnd<()> {
         match irrefutable_pat.kind {
             // Optimize the case of `let x = ...` to write directly into `x`
-            PatKind::Binding { mode: BindingMode::ByValue, var, subpattern: None, .. } => {
+            PatKind::Binding {
+                mode: BindingAnnotation(ByRef::No, _),
+                var,
+                subpattern: None,
+                ..
+            } => {
                 let place =
                     self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true);
                 unpack!(block = self.expr_into_dest(place, block, initializer_id));
@@ -580,7 +586,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     box Pat {
                         kind:
                             PatKind::Binding {
-                                mode: BindingMode::ByValue, var, subpattern: None, ..
+                                mode: BindingAnnotation(ByRef::No, _),
+                                var,
+                                subpattern: None,
+                                ..
                             },
                         ..
                     },
@@ -720,7 +729,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         self.visit_primary_bindings(
             pattern,
             UserTypeProjections::none(),
-            &mut |this, mutability, name, mode, var, span, ty, user_ty| {
+            &mut |this, name, mode, var, span, ty, user_ty| {
                 if visibility_scope.is_none() {
                     visibility_scope =
                         Some(this.new_source_scope(scope_span, LintLevel::Inherited, None));
@@ -730,7 +739,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 this.declare_binding(
                     source_info,
                     visibility_scope,
-                    mutability,
                     name,
                     mode,
                     var,
@@ -818,9 +826,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         pattern_user_ty: UserTypeProjections,
         f: &mut impl FnMut(
             &mut Self,
-            Mutability,
             Symbol,
-            BindingMode,
+            BindingAnnotation,
             LocalVarId,
             Span,
             Ty<'tcx>,
@@ -832,18 +839,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             pattern, pattern_user_ty
         );
         match pattern.kind {
-            PatKind::Binding {
-                mutability,
-                name,
-                mode,
-                var,
-                ty,
-                ref subpattern,
-                is_primary,
-                ..
-            } => {
+            PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => {
                 if is_primary {
-                    f(self, mutability, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
+                    f(self, name, mode, var, pattern.span, ty, pattern_user_ty.clone());
                 }
                 if let Some(subpattern) = subpattern.as_ref() {
                     self.visit_primary_bindings(subpattern, pattern_user_ty, f);
@@ -1079,7 +1077,7 @@ struct Binding<'tcx> {
     span: Span,
     source: Place<'tcx>,
     var_id: LocalVarId,
-    binding_mode: BindingMode,
+    binding_mode: BindingAnnotation,
 }
 
 /// Indicates that the type of `source` must be a subtype of the
@@ -2097,9 +2095,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 parent_data.iter().flat_map(|d| &d.bindings).chain(&candidate.extra_data.bindings);
 
             self.bind_matched_candidate_for_guard(block, schedule_drops, bindings.clone());
-            let guard_frame = GuardFrame {
-                locals: bindings.map(|b| GuardFrameLocal::new(b.var_id, b.binding_mode)).collect(),
-            };
+            let guard_frame =
+                GuardFrame { locals: bindings.map(|b| GuardFrameLocal::new(b.var_id)).collect() };
             debug!("entering guard building context: {:?}", guard_frame);
             self.guard_context.push(guard_frame);
 
@@ -2176,7 +2173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 .iter()
                 .flat_map(|d| &d.bindings)
                 .chain(&candidate.extra_data.bindings)
-                .filter(|binding| matches!(binding.binding_mode, BindingMode::ByValue));
+                .filter(|binding| matches!(binding.binding_mode.0, ByRef::No));
             // Read all of the by reference bindings to ensure that the
             // place they refer to can't be modified by the guard.
             for binding in by_value_bindings.clone() {
@@ -2263,12 +2260,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 RefWithinGuard,
                 schedule_drops,
             );
-            match binding.binding_mode {
-                BindingMode::ByValue => {
+            match binding.binding_mode.0 {
+                ByRef::No => {
                     let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, binding.source);
                     self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
                 }
-                BindingMode::ByRef(borrow_kind) => {
+                ByRef::Yes(mutbl) => {
                     let value_for_arm = self.storage_live_binding(
                         block,
                         binding.var_id,
@@ -2277,7 +2274,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         schedule_drops,
                     );
 
-                    let rvalue = Rvalue::Ref(re_erased, borrow_kind, binding.source);
+                    let rvalue =
+                        Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source);
                     self.cfg.push_assign(block, source_info, value_for_arm, rvalue);
                     let rvalue = Rvalue::Ref(re_erased, BorrowKind::Shared, value_for_arm);
                     self.cfg.push_assign(block, source_info, ref_for_guard, rvalue);
@@ -2318,10 +2316,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             if schedule_drops {
                 self.schedule_drop_for_binding(binding.var_id, binding.span, OutsideGuard);
             }
-            let rvalue = match binding.binding_mode {
-                BindingMode::ByValue => Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
-                BindingMode::ByRef(borrow_kind) => {
-                    Rvalue::Ref(re_erased, borrow_kind, binding.source)
+            let rvalue = match binding.binding_mode.0 {
+                ByRef::No => Rvalue::Use(self.consume_by_copy_or_move(binding.source)),
+                ByRef::Yes(mutbl) => {
+                    Rvalue::Ref(re_erased, util::ref_pat_borrow_kind(mutbl), binding.source)
                 }
             };
             self.cfg.push_assign(block, source_info, local, rvalue);
@@ -2338,9 +2336,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         &mut self,
         source_info: SourceInfo,
         visibility_scope: SourceScope,
-        mutability: Mutability,
         name: Symbol,
-        mode: BindingMode,
+        mode: BindingAnnotation,
         var_id: LocalVarId,
         var_ty: Ty<'tcx>,
         user_ty: UserTypeProjections,
@@ -2350,18 +2347,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     ) {
         let tcx = self.tcx;
         let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
-        let binding_mode = match mode {
-            BindingMode::ByValue => ty::BindingMode::BindByValue(mutability),
-            BindingMode::ByRef(_) => ty::BindingMode::BindByReference(mutability),
-        };
         let local = LocalDecl {
-            mutability,
+            mutability: mode.1,
             ty: var_ty,
             user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
             source_info,
             local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var(
                 VarBindingForm {
-                    binding_mode,
+                    binding_mode: mode,
                     // hypothetically, `visit_primary_bindings` could try to unzip
                     // an outermost hir::Ty as we descend, matching up
                     // idents in pat; but complex w/ unclear UI payoff.
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index bc6f0a26582..440be873d4e 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -154,15 +154,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
                 TestCase::Irrefutable { ascription, binding: None }
             }
 
-            PatKind::Binding {
-                name: _,
-                mutability: _,
-                mode,
-                var,
-                ty: _,
-                ref subpattern,
-                is_primary: _,
-            } => {
+            PatKind::Binding { mode, var, ref subpattern, .. } => {
                 let binding = place.map(|source| super::Binding {
                     span: pattern.span,
                     source,
@@ -347,3 +339,11 @@ impl<'a, 'b, 'tcx> FakeBorrowCollector<'a, 'b, 'tcx> {
         }
     }
 }
+
+#[must_use]
+pub fn ref_pat_borrow_kind(ref_mutability: Mutability) -> BorrowKind {
+    match ref_mutability {
+        Mutability::Mut => BorrowKind::Mut { kind: MutBorrowKind::Default },
+        Mutability::Not => BorrowKind::Shared,
+    }
+}
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index a43aadab478..274edf358e0 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -7,10 +7,9 @@ use rustc_ast::attr;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sorted_map::SortedIndexMultiMap;
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::Node;
+use rustc_hir::{self as hir, BindingAnnotation, ByRef, Node};
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -19,9 +18,7 @@ use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::*;
 use rustc_middle::query::TyCtxtAt;
-use rustc_middle::thir::{
-    self, BindingMode, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir,
-};
+use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -337,7 +334,7 @@ struct GuardFrameLocal {
 }
 
 impl GuardFrameLocal {
-    fn new(id: LocalVarId, _binding_mode: BindingMode) -> Self {
+    fn new(id: LocalVarId) -> Self {
         GuardFrameLocal { id }
     }
 }
@@ -967,9 +964,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             match pat.kind {
                 // Don't introduce extra copies for simple bindings
                 PatKind::Binding {
-                    mutability,
                     var,
-                    mode: BindingMode::ByValue,
+                    mode: BindingAnnotation(ByRef::No, mutability),
                     subpattern: None,
                     ..
                 } => {
@@ -979,7 +975,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         if let Some(kind) = param.self_kind {
                             LocalInfo::User(BindingForm::ImplicitSelf(kind))
                         } else {
-                            let binding_mode = ty::BindingMode::BindByValue(mutability);
+                            let binding_mode = BindingAnnotation(ByRef::No, mutability);
                             LocalInfo::User(BindingForm::Var(VarBindingForm {
                                 binding_mode,
                                 opt_ty_info: param.ty_span,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index e04fe31a76f..07dc332b791 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -2,11 +2,11 @@ use std::borrow::Cow;
 
 use crate::build::ExprCategory;
 use crate::errors::*;
-use rustc_middle::thir::visit::Visitor;
 
 use rustc_errors::DiagArgValue;
-use rustc_hir as hir;
+use rustc_hir::{self as hir, BindingAnnotation, ByRef, Mutability};
 use rustc_middle::mir::BorrowKind;
+use rustc_middle::thir::visit::Visitor;
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
@@ -289,22 +289,22 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     visit::walk_pat(self, pat);
                 }
             }
-            PatKind::Binding { mode: BindingMode::ByRef(borrow_kind), ty, .. } => {
+            PatKind::Binding { mode: BindingAnnotation(ByRef::Yes(rm), _), ty, .. } => {
                 if self.inside_adt {
                     let ty::Ref(_, ty, _) = ty.kind() else {
                         span_bug!(
                             pat.span,
-                            "BindingMode::ByRef in pattern, but found non-reference type {}",
+                            "ByRef::Yes in pattern, but found non-reference type {}",
                             ty
                         );
                     };
-                    match borrow_kind {
-                        BorrowKind::Fake | BorrowKind::Shared => {
+                    match rm {
+                        Mutability::Not => {
                             if !ty.is_freeze(self.tcx, self.param_env) {
                                 self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
                             }
                         }
-                        BorrowKind::Mut { .. } => {
+                        Mutability::Mut { .. } => {
                             self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
                         }
                     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 434ed16d5c6..3a688a14dd5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -13,10 +13,9 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
     codes::*, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
 };
-use rustc_hir as hir;
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::HirId;
+use rustc_hir::{self as hir, BindingAnnotation, ByRef, HirId};
 use rustc_middle::middle::limits::get_limit_size;
 use rustc_middle::thir::visit::Visitor;
 use rustc_middle::thir::*;
@@ -723,13 +722,14 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
     let sess = cx.tcx.sess;
 
     // Get the binding move, extract the mutability if by-ref.
-    let mut_outer = match mode {
-        BindingMode::ByValue if is_binding_by_move(ty) => {
+    let mut_outer = match mode.0 {
+        ByRef::No if is_binding_by_move(ty) => {
             // We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
             let mut conflicts_ref = Vec::new();
-            sub.each_binding(|_, mode, _, span| match mode {
-                BindingMode::ByValue => {}
-                BindingMode::ByRef(_) => conflicts_ref.push(span),
+            sub.each_binding(|_, mode, _, span| {
+                if matches!(mode, ByRef::Yes(_)) {
+                    conflicts_ref.push(span)
+                }
             });
             if !conflicts_ref.is_empty() {
                 sess.dcx().emit_err(BorrowOfMovedValue {
@@ -742,8 +742,8 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
             }
             return;
         }
-        BindingMode::ByValue => return,
-        BindingMode::ByRef(m) => m.mutability(),
+        ByRef::No => return,
+        ByRef::Yes(m) => m,
     };
 
     // We now have `ref $mut_outer binding @ sub` (semantically).
@@ -753,7 +753,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
     let mut conflicts_mut_ref = Vec::new();
     sub.each_binding(|name, mode, ty, span| {
         match mode {
-            BindingMode::ByRef(mut_inner) => match (mut_outer, mut_inner.mutability()) {
+            ByRef::Yes(mut_inner) => match (mut_outer, mut_inner) {
                 // Both sides are `ref`.
                 (Mutability::Not, Mutability::Not) => {}
                 // 2x `ref mut`.
@@ -767,10 +767,10 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat:
                     conflicts_mut_ref.push(Conflict::Ref { span, name })
                 }
             },
-            BindingMode::ByValue if is_binding_by_move(ty) => {
+            ByRef::No if is_binding_by_move(ty) => {
                 conflicts_move.push(Conflict::Moved { span, name }) // `ref mut?` + by-move conflict.
             }
-            BindingMode::ByValue => {} // `ref mut?` + by-copy is fine.
+            ByRef::No => {} // `ref mut?` + by-copy is fine.
         }
     });
 
@@ -813,8 +813,7 @@ fn check_for_bindings_named_same_as_variants(
 ) {
     if let PatKind::Binding {
         name,
-        mode: BindingMode::ByValue,
-        mutability: Mutability::Not,
+        mode: BindingAnnotation(ByRef::No, Mutability::Not),
         subpattern: None,
         ty,
         ..
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 0a7e9653377..a4992da679e 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -9,15 +9,14 @@ use crate::errors::*;
 use crate::thir::util::UserAnnotatedTyHelpers;
 
 use rustc_errors::codes::*;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
-use rustc_hir::RangeEnd;
+use rustc_hir::{self as hir, RangeEnd};
 use rustc_index::Idx;
 use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
-use rustc_middle::mir::{self, BorrowKind, Const, Mutability};
+use rustc_middle::mir::{self, Const};
 use rustc_middle::thir::{
-    Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
+    Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
 };
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt};
@@ -281,26 +280,16 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     span = span.with_hi(ident_span.hi());
                 }
 
-                let bm = *self
+                let mode = *self
                     .typeck_results
                     .pat_binding_modes()
                     .get(pat.hir_id)
                     .expect("missing binding mode");
-                let (mutability, mode) = match bm {
-                    ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue),
-                    ty::BindByReference(hir::Mutability::Mut) => (
-                        Mutability::Not,
-                        BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }),
-                    ),
-                    ty::BindByReference(hir::Mutability::Not) => {
-                        (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared))
-                    }
-                };
 
                 // A ref x pattern is the same node used for x, and as such it has
                 // x's type, which is &T, where we want T (the type being matched).
                 let var_ty = ty;
-                if let ty::BindByReference(_) = bm {
+                if let hir::ByRef::Yes(_) = mode.0 {
                     if let ty::Ref(_, rty, _) = ty.kind() {
                         ty = *rty;
                     } else {
@@ -309,7 +298,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 };
 
                 PatKind::Binding {
-                    mutability,
                     mode,
                     name: ident.name,
                     var: LocalVarId(id),
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index 16c4248a159..ef15082a481 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -635,9 +635,8 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
                 self.print_pat(subpattern, depth_lvl + 3);
                 print_indented!(self, "}", depth_lvl + 1);
             }
-            PatKind::Binding { mutability, name, mode, var, ty, subpattern, is_primary } => {
+            PatKind::Binding { name, mode, var, ty, subpattern, is_primary } => {
                 print_indented!(self, "Binding {", depth_lvl + 1);
-                print_indented!(self, format!("mutability: {:?}", mutability), depth_lvl + 2);
                 print_indented!(self, format!("name: {:?}", name), depth_lvl + 2);
                 print_indented!(self, format!("mode: {:?}", mode), depth_lvl + 2);
                 print_indented!(self, format!("var: {:?}", var), depth_lvl + 2);
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 8957d7d1bd3..e2436759c22 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -655,9 +655,6 @@ parse_question_mark_in_type = invalid `?` in type
 parse_recover_import_as_use = expected item, found {$token_name}
     .suggestion = items are imported using the `use` keyword
 
-parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
-    .suggestion = try switching the order
-
 parse_remove_let = expected pattern, found `let`
     .suggestion = remove the unnecessary `let` keyword
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index a6eedabf689..eae2d904c35 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2365,14 +2365,6 @@ pub(crate) struct UnexpectedLifetimeInPattern {
 }
 
 #[derive(Diagnostic)]
-#[diag(parse_ref_mut_order_incorrect)]
-pub(crate) struct RefMutOrderIncorrect {
-    #[primary_span]
-    #[suggestion(code = "ref mut", applicability = "machine-applicable")]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 pub(crate) enum InvalidMutInPattern {
     #[diag(parse_mut_on_nested_ident_pattern)]
     #[note(parse_note_mut_pattern_usage)]
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index de83528b52c..1971591364d 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -24,12 +24,11 @@ use rustc_ast::token::{self, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
 use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
-use rustc_ast::AttrId;
-use rustc_ast::CoroutineKind;
-use rustc_ast::DUMMY_NODE_ID;
-use rustc_ast::{self as ast, AnonConst, Const, DelimArgs, Extern};
-use rustc_ast::{AttrArgs, AttrArgsEq, Expr, ExprKind, Mutability, StrLit};
-use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind};
+use rustc_ast::{
+    self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs,
+    Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, StrLit, Unsafe, Visibility,
+    VisibilityKind, DUMMY_NODE_ID,
+};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::PResult;
@@ -1273,6 +1272,11 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not }
     }
 
+    /// Parses reference binding mode (`ref`, `ref mut`, or nothing).
+    fn parse_byref(&mut self) -> ByRef {
+        if self.eat_keyword(kw::Ref) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
+    }
+
     /// Possibly parses mutability (`const` or `mut`).
     fn parse_const_or_mut(&mut self) -> Option<Mutability> {
         if self.eat_keyword(kw::Mut) {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index fbc28859535..ead00c3f0d4 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -4,11 +4,11 @@ use crate::errors::{
     DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
     ExpectedCommaAfterPatternField, GenericArgsInPatRequireTurbofishSyntax,
     InclusiveRangeExtraEquals, InclusiveRangeMatchArrow, InclusiveRangeNoEnd, InvalidMutInPattern,
-    PatternOnWrongSideOfAt, RefMutOrderIncorrect, RemoveLet, RepeatedMutInPattern,
-    SwitchRefBoxOrder, TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg,
-    TrailingVertNotAllowed, UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern,
-    UnexpectedParenInRangePat, UnexpectedParenInRangePatSugg,
-    UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern,
+    PatternOnWrongSideOfAt, RemoveLet, RepeatedMutInPattern, SwitchRefBoxOrder,
+    TopLevelOrPatternNotAllowed, TopLevelOrPatternNotAllowedSugg, TrailingVertNotAllowed,
+    UnexpectedExpressionInPattern, UnexpectedLifetimeInPattern, UnexpectedParenInRangePat,
+    UnexpectedParenInRangePatSugg, UnexpectedVertVertBeforeFunctionParam,
+    UnexpectedVertVertInPattern,
 };
 use crate::parser::expr::could_be_unclosed_char_literal;
 use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -476,7 +476,7 @@ impl<'a> Parser<'a> {
             // Parse `_`
             PatKind::Wild
         } else if self.eat_keyword(kw::Mut) {
-            self.parse_pat_ident_mut(syntax_loc)?
+            self.parse_pat_ident_mut()?
         } else if self.eat_keyword(kw::Ref) {
             if self.check_keyword(kw::Box) {
                 // Suggest `box ref`.
@@ -486,7 +486,7 @@ impl<'a> Parser<'a> {
             }
             // Parse ref ident @ pat / ref mut ident @ pat
             let mutbl = self.parse_mutability();
-            self.parse_pat_ident(BindingAnnotation(ByRef::Yes, mutbl), syntax_loc)?
+            self.parse_pat_ident(BindingAnnotation(ByRef::Yes(mutbl), Mutability::Not), syntax_loc)?
         } else if self.eat_keyword(kw::Box) {
             self.parse_pat_box()?
         } else if self.check_inline_const(0) {
@@ -746,13 +746,12 @@ impl<'a> Parser<'a> {
     }
 
     /// Parse a mutable binding with the `mut` token already eaten.
-    fn parse_pat_ident_mut(&mut self, syntax_loc: Option<PatternLocation>) -> PResult<'a, PatKind> {
+    fn parse_pat_ident_mut(&mut self) -> PResult<'a, PatKind> {
         let mut_span = self.prev_token.span;
 
-        if self.eat_keyword(kw::Ref) {
-            self.dcx().emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
-            return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc);
-        }
+        self.recover_additional_muts();
+
+        let byref = self.parse_byref();
 
         self.recover_additional_muts();
 
@@ -767,10 +766,12 @@ impl<'a> Parser<'a> {
         let mut pat = self.parse_pat_no_top_alt(Some(Expected::Identifier), None)?;
 
         // If we don't have `mut $ident (@ pat)?`, error.
-        if let PatKind::Ident(BindingAnnotation(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind
+        if let PatKind::Ident(BindingAnnotation(br @ ByRef::No, m @ Mutability::Not), ..) =
+            &mut pat.kind
         {
             // Don't recurse into the subpattern.
             // `mut` on the outer binding doesn't affect the inner bindings.
+            *br = byref;
             *m = Mutability::Mut;
         } else {
             // Add `mut` to any binding in the parsed pattern.
@@ -1390,16 +1391,12 @@ impl<'a> Parser<'a> {
             // Parsing a pattern of the form `(box) (ref) (mut) fieldname`.
             let is_box = self.eat_keyword(kw::Box);
             let boxed_span = self.token.span;
-            let is_ref = self.eat_keyword(kw::Ref);
-            let is_mut = self.eat_keyword(kw::Mut);
+            let mutability = self.parse_mutability();
+            let by_ref = self.parse_byref();
+
             let fieldname = self.parse_field_name()?;
             hi = self.prev_token.span;
-
-            let mutability = match is_mut {
-                false => Mutability::Not,
-                true => Mutability::Mut,
-            };
-            let ann = BindingAnnotation(ByRef::from(is_ref), mutability);
+            let ann = BindingAnnotation(by_ref, mutability);
             let fieldpat = self.mk_pat_ident(boxed_span.to(hi), ann, fieldname);
             let subpat =
                 if is_box { self.mk_pat(lo.to(hi), PatKind::Box(fieldpat)) } else { fieldpat };