about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs35
-rw-r--r--compiler/rustc_mir_build/src/build/matches/util.rs6
-rw-r--r--tests/ui/pattern/deref-patterns/bindings.rs15
4 files changed, 48 insertions, 15 deletions
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 2ac2c2546dd..265d80ed8bc 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1163,7 +1163,7 @@ enum TestCase<'pat, 'tcx> {
     Constant { value: mir::Const<'tcx> },
     Range(&'pat PatRange<'tcx>),
     Slice { len: usize, variable_length: bool },
-    Deref { temp: Place<'tcx> },
+    Deref { temp: Place<'tcx>, mutability: Mutability },
     Or { pats: Box<[FlatPat<'pat, 'tcx>]> },
 }
 
@@ -1224,10 +1224,11 @@ enum TestKind<'tcx> {
     /// Test that the length of the slice is equal to `len`.
     Len { len: u64, op: BinOp },
 
-    /// Call `Deref::deref` on the value.
+    /// Call `Deref::deref[_mut]` on the value.
     Deref {
-        /// Temporary to store the result of `deref()`.
+        /// Temporary to store the result of `deref()`/`deref_mut()`.
         temp: Place<'tcx>,
+        mutability: Mutability,
     },
 }
 
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index f6827fd7c52..5dd478aa422 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -42,7 +42,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 TestKind::Len { len: len as u64, op }
             }
 
-            TestCase::Deref { temp } => TestKind::Deref { temp },
+            TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
 
             TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
 
@@ -149,7 +149,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     let ref_str = self.temp(ref_str_ty, test.span);
                     let eq_block = self.cfg.start_new_block();
                     // `let ref_str: &str = <String as Deref>::deref(&place);`
-                    self.call_deref(block, eq_block, place, ty, ref_str, test.span);
+                    self.call_deref(
+                        block,
+                        eq_block,
+                        place,
+                        Mutability::Not,
+                        ty,
+                        ref_str,
+                        test.span,
+                    );
                     self.non_scalar_compare(
                         eq_block,
                         success_block,
@@ -249,37 +257,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 );
             }
 
-            TestKind::Deref { temp } => {
+            TestKind::Deref { temp, mutability } => {
                 let ty = place_ty.ty;
                 let target = target_block(TestBranch::Success);
-                self.call_deref(block, target, place, ty, temp, test.span);
+                self.call_deref(block, target, place, mutability, ty, temp, test.span);
             }
         }
     }
 
     /// Perform `let temp = <ty as Deref>::deref(&place)`.
+    /// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`.
     pub(super) fn call_deref(
         &mut self,
         block: BasicBlock,
         target_block: BasicBlock,
         place: Place<'tcx>,
+        mutability: Mutability,
         ty: Ty<'tcx>,
         temp: Place<'tcx>,
         span: Span,
     ) {
+        let (trait_item, method) = match mutability {
+            Mutability::Not => (LangItem::Deref, sym::deref),
+            Mutability::Mut => (LangItem::DerefMut, sym::deref_mut),
+        };
+        let borrow_kind = super::util::ref_pat_borrow_kind(mutability);
         let source_info = self.source_info(span);
         let re_erased = self.tcx.lifetimes.re_erased;
-        let deref = self.tcx.require_lang_item(LangItem::Deref, None);
-        let method = trait_method(self.tcx, deref, sym::deref, [ty]);
-        let ref_src = self.temp(Ty::new_imm_ref(self.tcx, re_erased, ty), span);
+        let trait_item = self.tcx.require_lang_item(trait_item, None);
+        let method = trait_method(self.tcx, trait_item, method, [ty]);
+        let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span);
         // `let ref_src = &src_place;`
+        // or `let ref_src = &mut src_place;`
         self.cfg.push_assign(
             block,
             source_info,
             ref_src,
-            Rvalue::Ref(re_erased, BorrowKind::Shared, place),
+            Rvalue::Ref(re_erased, borrow_kind, place),
         );
         // `let temp = <Ty as Deref>::deref(ref_src);`
+        // or `let temp = <Ty as DerefMut>::deref_mut(ref_src);`
         self.cfg.terminate(
             block,
             source_info,
@@ -686,7 +703,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 }
             }
 
-            (TestKind::Deref { temp: test_temp }, TestCase::Deref { temp })
+            (TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
                 if test_temp == temp =>
             {
                 fully_matched = true;
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 3292ab1f1b7..8f9fb8beba1 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -249,15 +249,15 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
                 default_irrefutable()
             }
 
-            PatKind::DerefPattern { ref subpattern, .. } => {
+            PatKind::DerefPattern { ref subpattern, mutability } => {
                 // Create a new temporary for each deref pattern.
                 // FIXME(deref_patterns): dedup temporaries to avoid multiple `deref()` calls?
                 let temp = cx.temp(
-                    Ty::new_imm_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty),
+                    Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, subpattern.ty, mutability),
                     pattern.span,
                 );
                 subpairs.push(MatchPair::new(PlaceBuilder::from(temp).deref(), subpattern, cx));
-                TestCase::Deref { temp }
+                TestCase::Deref { temp, mutability }
             }
         };
 
diff --git a/tests/ui/pattern/deref-patterns/bindings.rs b/tests/ui/pattern/deref-patterns/bindings.rs
index c0c8a70dbf0..4f72058af8f 100644
--- a/tests/ui/pattern/deref-patterns/bindings.rs
+++ b/tests/ui/pattern/deref-patterns/bindings.rs
@@ -24,6 +24,19 @@ fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
     }
 }
 
+fn ref_mut(val: u32) -> u32 {
+    let mut b = Box::new(0u32);
+    match &mut b {
+        deref!(_x) if false => unreachable!(),
+        deref!(x) => {
+            *x = val;
+        }
+        _ => unreachable!(),
+    }
+    let deref!(x) = &b else { unreachable!() };
+    *x
+}
+
 fn main() {
     assert_eq!(simple_vec(vec![1]), 1);
     assert_eq!(simple_vec(vec![1, 2]), 202);
@@ -34,4 +47,6 @@ fn main() {
     assert_eq!(nested_vec(vec![vec![1, 42]]), 42);
     assert_eq!(nested_vec(vec![vec![1, 2, 3]]), 6);
     assert_eq!(nested_vec(vec![vec![], vec![1, 2, 3]]), 1);
+
+    assert_eq!(ref_mut(42), 42)
 }