Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #15860 - HKalbasi:fix-capture-raw-pointer, r=HKalbasi
Truncate closure capture place for raw pointer fix https://github.com/rust-lang/rust-analyzer/issues/15670#issuecomment-1804070623
bors 2023-11-10
parent ebb9ed9 · parent 3bcdb7d · commit 7663319
-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 c0b243ea24..c9ab356854 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 0805e20447..af74df1032 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 ee096a100a..1875111492 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();
+}
+"#,
+ );
+ }
}