about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNadrieril <nadrieril+git@gmail.com>2024-04-05 23:42:29 +0200
committerNadrieril <nadrieril+git@gmail.com>2024-04-20 15:59:54 +0200
commitb55afe475aee1e51196e35845ba1553c96f041cf (patch)
tree60007c906bbbab8d7fc54a595cd1fab8ccffa56a
parent377e095371ae99dfdd61d5b50d4a43422b34ca23 (diff)
downloadrust-b55afe475aee1e51196e35845ba1553c96f041cf.tar.gz
rust-b55afe475aee1e51196e35845ba1553c96f041cf.zip
Address closure-related review
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs4
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs2
-rw-r--r--tests/ui/pattern/deref-patterns/closure_capture.rs21
4 files changed, 35 insertions, 1 deletions
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index a0a5a75d382..cc42e69f538 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -750,6 +750,15 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                         }
                     }
                 }
+            } else if let PatKind::Deref(subpattern) = pat.kind {
+                // A deref pattern is a bit special: the binding mode of its inner bindings
+                // determines whether to borrow *at the level of the deref pattern* rather than
+                // borrowing the bound place (since that inner place is inside the temporary that
+                // stores the result of calling `deref()`/`deref_mut()` so can't be captured).
+                let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern);
+                let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
+                let bk = ty::BorrowKind::from_mutbl(mutability);
+                delegate.borrow(place, discr_place.hir_id, bk);
             }
         }));
     }
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 15f802560fd..b44c2345933 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -719,7 +719,11 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                 self.cat_pattern_(subplace, subpat, op)?;
             }
             PatKind::Deref(subpat) => {
+                let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat);
+                let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
+                let re_erased = self.tcx().lifetimes.re_erased;
                 let ty = self.pat_ty_adjusted(subpat)?;
+                let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability);
                 // A deref pattern generates a temporary.
                 let place = self.cat_rvalue(pat.hir_id, ty);
                 self.cat_pattern_(place, subpat, op)?;
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index a28afcc4fb8..25bca70f102 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -451,7 +451,7 @@ impl<'tcx> TypeckResults<'tcx> {
     /// This is computed from the typeck results since we want to make
     /// sure to apply any match-ergonomics adjustments, which we cannot
     /// determine from the HIR alone.
-    pub fn pat_has_ref_mut_binding(&self, pat: &'tcx hir::Pat<'tcx>) -> bool {
+    pub fn pat_has_ref_mut_binding(&self, pat: &hir::Pat<'_>) -> bool {
         let mut has_ref_mut = false;
         pat.walk(|pat| {
             if let hir::PatKind::Binding(_, id, _, _) = pat.kind
diff --git a/tests/ui/pattern/deref-patterns/closure_capture.rs b/tests/ui/pattern/deref-patterns/closure_capture.rs
new file mode 100644
index 00000000000..fc0ddedac2b
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/closure_capture.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let b = Box::new("aaa".to_string());
+    let f = || {
+        let deref!(ref s) = b else { unreachable!() };
+        assert_eq!(s.len(), 3);
+    };
+    assert_eq!(b.len(), 3);
+    f();
+
+    let mut b = Box::new("aaa".to_string());
+    let mut f = || {
+        let deref!(ref mut s) = b else { unreachable!() };
+        s.push_str("aa");
+    };
+    f();
+    assert_eq!(b.len(), 5);
+}