about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-03-02 13:52:12 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-03-06 21:09:09 +0330
commitbf0f99f15ddc00ddc49eb357764a58aaf7a93b02 (patch)
tree60c416bdad4a4dc87c5a1ddcca340a5afe0c6644
parent6377d50bd137424a38f2f71bb3eba29d74d02210 (diff)
downloadrust-bf0f99f15ddc00ddc49eb357764a58aaf7a93b02.tar.gz
rust-bf0f99f15ddc00ddc49eb357764a58aaf7a93b02.zip
Fix overloaded deref unused mut false positive
-rw-r--r--crates/hir-ty/src/mir/eval.rs12
-rw-r--r--crates/hir-ty/src/mir/lower.rs11
-rw-r--r--crates/ide-diagnostics/src/handlers/mutability_errors.rs28
3 files changed, 45 insertions, 6 deletions
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index b0b09fcd53b..c5d843d9ebd 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -263,12 +263,14 @@ impl Evaluator<'_> {
         for proj in &p.projection {
             match proj {
                 ProjectionElem::Deref => {
-                    match &ty.data(Interner).kind {
-                        TyKind::Ref(_, _, inner) => {
-                            ty = inner.clone();
+                    ty = match &ty.data(Interner).kind {
+                        TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
+                        _ => {
+                            return Err(MirEvalError::TypeError(
+                                "Overloaded deref in MIR is disallowed",
+                            ))
                         }
-                        _ => not_supported!("dereferencing smart pointers"),
-                    }
+                    };
                     let x = from_bytes!(usize, self.read_memory(addr, self.ptr_size())?);
                     addr = Address::from_usize(x);
                 }
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index f9a66286b28..8e7fb091c03 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -129,6 +129,12 @@ impl MirLowerCtx<'_> {
             }
             Expr::UnaryOp { expr, op } => match op {
                 hir_def::expr::UnaryOp::Deref => {
+                    if !matches!(
+                        self.expr_ty(*expr).kind(Interner),
+                        TyKind::Ref(..) | TyKind::Raw(..)
+                    ) {
+                        return None;
+                    }
                     let mut r = self.lower_expr_as_place(*expr)?;
                     r.projection.push(ProjectionElem::Deref);
                     Some(r)
@@ -210,7 +216,7 @@ impl MirLowerCtx<'_> {
                         Adjust::Deref(None) => {
                             r.projection.push(ProjectionElem::Deref);
                         }
-                        Adjust::Deref(Some(_)) => not_supported!("overloaded dereference"),
+                        Adjust::Deref(Some(_)) => not_supported!("implicit overloaded dereference"),
                         Adjust::Borrow(AutoBorrow::Ref(m) | AutoBorrow::RawPtr(m)) => {
                             let tmp = self.temp(adjustment.target.clone())?;
                             self.push_assignment(
@@ -757,6 +763,9 @@ impl MirLowerCtx<'_> {
             Expr::Box { .. } => not_supported!("box expression"),
             Expr::UnaryOp { expr, op } => match op {
                 hir_def::expr::UnaryOp::Deref => {
+                    if !matches!(self.expr_ty(*expr).kind(Interner), TyKind::Ref(..) | TyKind::Raw(..)) {
+                        not_supported!("explicit overloaded deref");
+                    }
                     let (mut tmp, Some(current)) = self.lower_expr_to_some_place(*expr, current)? else {
                         return Ok(None);
                     };
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index a6aa069e27b..1203a961247 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -526,4 +526,32 @@ fn f(x: [(i32, u8); 10]) {
 "#,
         );
     }
+
+    #[test]
+    fn overloaded_deref() {
+        check_diagnostics(
+            r#"
+//- minicore: deref_mut
+use core::ops::{Deref, DerefMut};
+
+struct Foo;
+impl Deref for Foo {
+    type Target = i32;
+    fn deref(&self) -> &i32 {
+        &5
+    }
+}
+impl DerefMut for Foo {
+    fn deref_mut(&mut self) -> &mut i32 {
+        &mut 5
+    }
+}
+fn f() {
+    // FIXME: remove this mut and detect error
+    let mut x = Foo;
+    let y = &mut *x;
+}
+"#,
+        );
+    }
 }