about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-03-21 14:38:01 -0400
committerMichael Goulet <michael@errs.io>2024-03-25 19:39:45 -0400
commit5fdc7555c1d6c80a51a3a88c494f255f719bdd35 (patch)
treeaa1bfca15d1bad7756cd896e7bb16ed37c523bf2
parentb56279569be90758f1b53bb658ceace1527f5837 (diff)
downloadrust-5fdc7555c1d6c80a51a3a88c494f255f719bdd35.tar.gz
rust-5fdc7555c1d6c80a51a3a88c494f255f719bdd35.zip
Require DerefMut if deref pattern has nested ref mut binding
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs24
-rw-r--r--tests/ui/pattern/deref-patterns/ref-mut.rs17
-rw-r--r--tests/ui/pattern/deref-patterns/ref-mut.stderr20
3 files changed, 61 insertions, 0 deletions
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 242523fb317..5f8b833b306 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -2017,6 +2017,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let ty = self.normalize(span, ty);
         let ty = self.try_structurally_resolve_type(span, ty);
         self.check_pat(inner, ty, pat_info);
+
+        // Check if the pattern has any `ref mut` bindings, which would require
+        // `DerefMut` to be emitted in MIR building instead of just `Deref`.
+        let mut needs_mut = false;
+        inner.walk(|pat| {
+            if let hir::PatKind::Binding(_, id, _, _) = pat.kind
+                && let Some(ty::BindByReference(ty::Mutability::Mut)) =
+                    self.typeck_results.borrow().pat_binding_modes().get(id)
+            {
+                needs_mut = true;
+                // No need to continue recursing
+                false
+            } else {
+                true
+            }
+        });
+        if needs_mut {
+            self.register_bound(
+                expected,
+                tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
+                self.misc(span),
+            );
+        }
+
         expected
     }
 
diff --git a/tests/ui/pattern/deref-patterns/ref-mut.rs b/tests/ui/pattern/deref-patterns/ref-mut.rs
new file mode 100644
index 00000000000..1918008a761
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/ref-mut.rs
@@ -0,0 +1,17 @@
+#![feature(deref_patterns)]
+//~^ WARN the feature `deref_patterns` is incomplete
+
+use std::rc::Rc;
+
+fn main() {
+    match &mut vec![1] {
+        deref!(x) => {}
+        _ => {}
+    }
+
+    match &mut Rc::new(1) {
+        deref!(x) => {}
+        //~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied
+        _ => {}
+    }
+}
diff --git a/tests/ui/pattern/deref-patterns/ref-mut.stderr b/tests/ui/pattern/deref-patterns/ref-mut.stderr
new file mode 100644
index 00000000000..41f1c3061ce
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/ref-mut.stderr
@@ -0,0 +1,20 @@
+warning: the feature `deref_patterns` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/ref-mut.rs:1:12
+   |
+LL | #![feature(deref_patterns)]
+   |            ^^^^^^^^^^^^^^
+   |
+   = note: see issue #87121 <https://github.com/rust-lang/rust/issues/87121> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
+  --> $DIR/ref-mut.rs:13:9
+   |
+LL |         deref!(x) => {}
+   |         ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
+   |
+   = note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.