]> git.lizzy.rs Git - rust.git/blobdiff - compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs
Fix incorrect use mut diagnostics
[rust.git] / compiler / rustc_mir / src / borrow_check / diagnostics / mutability_errors.rs
index 73196c732f5bbc8586147a279885af5da6caf269..74abe2d35ee748814c01f83ead67999cc05d9ab6 100644 (file)
@@ -64,12 +64,29 @@ pub(crate) fn report_mutability_error(
                     Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
-                item_msg = format!("`{}`", access_place_desc.unwrap());
-                if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
-                    reason = ", as it is not declared as mutable".to_string();
+                let imm_borrow_derefed = self.upvars[upvar_index.index()]
+                    .place
+                    .place
+                    .deref_tys()
+                    .any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not)));
+
+                // If the place is immutable then:
+                //
+                // - Either we deref a immutable ref to get to our final place.
+                //    - We don't capture derefs of raw ptrs
+                // - Or the final place is immut because the root variable of the capture
+                //   isn't marked mut and we should suggest that to the user.
+                if imm_borrow_derefed {
+                    // If we deref an immutable ref then the suggestion here doesn't help.
+                    return;
                 } else {
-                    let name = self.upvars[upvar_index.index()].name;
-                    reason = format!(", as `{}` is not declared as mutable", name);
+                    item_msg = format!("`{}`", access_place_desc.unwrap());
+                    if self.is_upvar_field_projection(access_place.as_ref()).is_some() {
+                        reason = ", as it is not declared as mutable".to_string();
+                    } else {
+                        let name = self.upvars[upvar_index.index()].name;
+                        reason = format!(", as `{}` is not declared as mutable", name);
+                    }
                 }
             }
 
@@ -259,9 +276,12 @@ pub(crate) fn report_mutability_error(
                     Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty
                 ));
 
+                let captured_place = &self.upvars[upvar_index.index()].place;
+
                 err.span_label(span, format!("cannot {ACT}", ACT = act));
 
-                let upvar_hir_id = self.upvars[upvar_index.index()].var_hir_id;
+                let upvar_hir_id = captured_place.get_root_variable();
+
                 if let Some(Node::Binding(pat)) = self.infcx.tcx.hir().find(upvar_hir_id) {
                     if let hir::PatKind::Binding(
                         hir::BindingAnnotation::Unannotated,