about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2023-11-09 20:59:17 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2023-11-09 20:59:17 +0330
commit3bcdb7d886f0673799ea961220b557c28b6213b4 (patch)
tree0c3dcd9e03e8159deb537b59e19d802898f5b210
parent7059ae2fc2d55fa20d7e2671597b516431129445 (diff)
downloadrust-3bcdb7d886f0673799ea961220b557c28b6213b4.tar.gz
rust-3bcdb7d886f0673799ea961220b557c28b6213b4.zip
Truncate closure capture place for raw pointer
-rw-r--r--crates/hir-ty/src/chalk_ext.rs5
-rw-r--r--crates/hir-ty/src/infer/closure.rs27
-rw-r--r--crates/ide-diagnostics/src/handlers/mutability_errors.rs16
3 files changed, 48 insertions, 0 deletions
diff --git a/crates/hir-ty/src/chalk_ext.rs b/crates/hir-ty/src/chalk_ext.rs
index c0b243ea248..c9ab356854b 100644
--- a/crates/hir-ty/src/chalk_ext.rs
+++ b/crates/hir-ty/src/chalk_ext.rs
@@ -28,6 +28,7 @@ pub trait TyExt {
     fn is_unknown(&self) -> bool;
     fn contains_unknown(&self) -> bool;
     fn is_ty_var(&self) -> bool;
+    fn is_union(&self) -> bool;
 
     fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
     fn as_builtin(&self) -> Option<BuiltinType>;
@@ -96,6 +97,10 @@ impl TyExt for Ty {
         matches!(self.kind(Interner), TyKind::InferenceVar(_, _))
     }
 
+    fn is_union(&self) -> bool {
+        matches!(self.adt_id(Interner), Some(AdtId(hir_def::AdtId::UnionId(_))))
+    }
+
     fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
         match self.kind(Interner) {
             TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 0805e20447a..af74df1032c 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -735,6 +735,32 @@ impl InferenceContext<'_> {
         self.walk_expr(expr);
     }
 
+    fn restrict_precision_for_unsafe(&mut self) {
+        for capture in &mut self.current_captures {
+            let mut ty = self.table.resolve_completely(self.result[capture.place.local].clone());
+            if ty.as_raw_ptr().is_some() || ty.is_union() {
+                capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
+                capture.place.projections.truncate(0);
+                continue;
+            }
+            for (i, p) in capture.place.projections.iter().enumerate() {
+                ty = p.projected_ty(
+                    ty,
+                    self.db,
+                    |_, _, _| {
+                        unreachable!("Closure field only happens in MIR");
+                    },
+                    self.owner.module(self.db.upcast()).krate(),
+                );
+                if ty.as_raw_ptr().is_some() || ty.is_union() {
+                    capture.kind = CaptureKind::ByRef(BorrowKind::Shared);
+                    capture.place.projections.truncate(i + 1);
+                    break;
+                }
+            }
+        }
+    }
+
     fn adjust_for_move_closure(&mut self) {
         for capture in &mut self.current_captures {
             if let Some(first_deref) =
@@ -924,6 +950,7 @@ impl InferenceContext<'_> {
                 self.result.mutated_bindings_in_closure.insert(item.place.local);
             }
         }
+        self.restrict_precision_for_unsafe();
         // closure_kind should be done before adjust_for_move_closure
         let closure_kind = self.closure_kind();
         match capture_by {
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index ee096a100aa..1875111492c 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -1228,4 +1228,20 @@ fn foo(mut foo: Foo) {
 "#,
         );
     }
+
+    #[test]
+    fn regression_15670() {
+        check_diagnostics(
+            r#"
+//- minicore: fn
+
+pub struct A {}
+pub unsafe fn foo(a: *mut A) {
+    let mut b = || -> *mut A { &mut *a };
+      //^^^^^ 💡 warn: variable does not need to be mutable
+    let _ = b();
+}
+"#,
+        );
+    }
 }