diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a27d016e0ba51..36c2723b66ded 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -2,7 +2,7 @@ #![allow(rustc::untranslatable_diagnostic)] use core::ops::ControlFlow; -use hir::ExprKind; +use hir::{ExprKind, Param}; use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; @@ -725,25 +725,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { _ => local_decl.source_info.span, }; - let def_id = self.body.source.def_id(); - let hir_id = if let Some(local_def_id) = def_id.as_local() - && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id) - { - let body = self.infcx.tcx.hir().body(body_id); - BindingFinder { span: pat_span }.visit_body(body).break_value() - } else { - None - }; - // With ref-binding patterns, the mutability suggestion has to apply to // the binding, not the reference (which would be a type error): // // `let &b = a;` -> `let &(mut b) = a;` - if let Some(hir_id) = hir_id + // or + // `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)` + let def_id = self.body.source.def_id(); + if let Some(local_def_id) = def_id.as_local() + && let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id) + && let body = self.infcx.tcx.hir().body(body_id) + && let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(body).break_value() + && let node = self.infcx.tcx.hir_node(hir_id) && let hir::Node::Local(hir::Local { pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, .. - }) = self.infcx.tcx.hir_node(hir_id) + }) + | hir::Node::Param(Param { + pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. }, + .. + }) = node && let Ok(name) = self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span) { @@ -1310,6 +1311,16 @@ impl<'tcx> Visitor<'tcx> for BindingFinder { hir::intravisit::walk_stmt(self, s) } } + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result { + if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat + && *span == self.span + { + ControlFlow::Break(param.hir_id) + } else { + ControlFlow::Continue(()) + } + } } pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 03e4ecca9d6fd..5b4ef4e93dded 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3463,7 +3463,6 @@ "ui/pattern/issue-106552.rs", "ui/pattern/issue-106862.rs", "ui/pattern/issue-110508.rs", -"ui/pattern/issue-114896.rs", "ui/pattern/issue-115599.rs", "ui/pattern/issue-11577.rs", "ui/pattern/issue-117626.rs", diff --git a/tests/ui/pattern/patkind-ref-binding-issue-114896.fixed b/tests/ui/pattern/patkind-ref-binding-issue-114896.fixed new file mode 100644 index 0000000000000..086a119eb7764 --- /dev/null +++ b/tests/ui/pattern/patkind-ref-binding-issue-114896.fixed @@ -0,0 +1,10 @@ +//@ run-rustfix +#![allow(dead_code)] + +fn main() { + fn x(a: &char) { + let &(mut b) = a; + b.make_ascii_uppercase(); +//~^ cannot borrow `b` as mutable, as it is not declared as mutable + } +} diff --git a/tests/ui/pattern/issue-114896.rs b/tests/ui/pattern/patkind-ref-binding-issue-114896.rs similarity index 81% rename from tests/ui/pattern/issue-114896.rs rename to tests/ui/pattern/patkind-ref-binding-issue-114896.rs index cde37f658d6ae..b4d6b72c01f2a 100644 --- a/tests/ui/pattern/issue-114896.rs +++ b/tests/ui/pattern/patkind-ref-binding-issue-114896.rs @@ -1,3 +1,6 @@ +//@ run-rustfix +#![allow(dead_code)] + fn main() { fn x(a: &char) { let &b = a; diff --git a/tests/ui/pattern/issue-114896.stderr b/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr similarity index 87% rename from tests/ui/pattern/issue-114896.stderr rename to tests/ui/pattern/patkind-ref-binding-issue-114896.stderr index 285c9109e1b88..68538255eddf0 100644 --- a/tests/ui/pattern/issue-114896.stderr +++ b/tests/ui/pattern/patkind-ref-binding-issue-114896.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable - --> $DIR/issue-114896.rs:4:9 + --> $DIR/patkind-ref-binding-issue-114896.rs:7:9 | LL | let &b = a; | -- help: consider changing this to be mutable: `&(mut b)` diff --git a/tests/ui/pattern/patkind-ref-binding-issue-122415.fixed b/tests/ui/pattern/patkind-ref-binding-issue-122415.fixed new file mode 100644 index 0000000000000..6144f06216986 --- /dev/null +++ b/tests/ui/pattern/patkind-ref-binding-issue-122415.fixed @@ -0,0 +1,11 @@ +//@ run-rustfix +#![allow(dead_code)] + +fn mutate(_y: &mut i32) {} + +fn foo(&(mut x): &i32) { + mutate(&mut x); + //~^ ERROR cannot borrow `x` as mutable +} + +fn main() {} diff --git a/tests/ui/pattern/patkind-ref-binding-issue-122415.rs b/tests/ui/pattern/patkind-ref-binding-issue-122415.rs new file mode 100644 index 0000000000000..b9f6416027a37 --- /dev/null +++ b/tests/ui/pattern/patkind-ref-binding-issue-122415.rs @@ -0,0 +1,11 @@ +//@ run-rustfix +#![allow(dead_code)] + +fn mutate(_y: &mut i32) {} + +fn foo(&x: &i32) { + mutate(&mut x); + //~^ ERROR cannot borrow `x` as mutable +} + +fn main() {} diff --git a/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr b/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr new file mode 100644 index 0000000000000..39283133ac7c8 --- /dev/null +++ b/tests/ui/pattern/patkind-ref-binding-issue-122415.stderr @@ -0,0 +1,11 @@ +error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable + --> $DIR/patkind-ref-binding-issue-122415.rs:7:12 + | +LL | fn foo(&x: &i32) { + | -- help: consider changing this to be mutable: `&(mut x)` +LL | mutate(&mut x); + | ^^^^^^ cannot borrow as mutable + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0596`.