Skip to content

Commit 19f72df

Browse files
committed
Fix incorrect mutable suggestion information for binding in ref pattern.
For ref pattern in func param, the mutability suggestion has to apply to the binding. For example: `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)` fixes #122415
1 parent 21d94a3 commit 19f72df

8 files changed

+71
-15
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

+24-13
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#![allow(rustc::untranslatable_diagnostic)]
33

44
use core::ops::ControlFlow;
5-
use hir::ExprKind;
5+
use hir::{ExprKind, Param};
66
use rustc_errors::{Applicability, Diag};
77
use rustc_hir as hir;
88
use rustc_hir::intravisit::Visitor;
@@ -725,25 +725,26 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
725725
_ => local_decl.source_info.span,
726726
};
727727

728-
let def_id = self.body.source.def_id();
729-
let hir_id = if let Some(local_def_id) = def_id.as_local()
730-
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
731-
{
732-
let body = self.infcx.tcx.hir().body(body_id);
733-
BindingFinder { span: pat_span }.visit_body(body).break_value()
734-
} else {
735-
None
736-
};
737-
738728
// With ref-binding patterns, the mutability suggestion has to apply to
739729
// the binding, not the reference (which would be a type error):
740730
//
741731
// `let &b = a;` -> `let &(mut b) = a;`
742-
if let Some(hir_id) = hir_id
732+
// or
733+
// `fn foo(&x: &i32)` -> `fn foo(&(mut x): &i32)`
734+
let def_id = self.body.source.def_id();
735+
if let Some(local_def_id) = def_id.as_local()
736+
&& let Some(body_id) = self.infcx.tcx.hir().maybe_body_owned_by(local_def_id)
737+
&& let body = self.infcx.tcx.hir().body(body_id)
738+
&& let Some(hir_id) = (BindingFinder { span: pat_span }).visit_body(body).break_value()
739+
&& let node = self.infcx.tcx.hir_node(hir_id)
743740
&& let hir::Node::Local(hir::Local {
744741
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
745742
..
746-
}) = self.infcx.tcx.hir_node(hir_id)
743+
})
744+
| hir::Node::Param(Param {
745+
pat: hir::Pat { kind: hir::PatKind::Ref(_, _), .. },
746+
..
747+
}) = node
747748
&& let Ok(name) =
748749
self.infcx.tcx.sess.source_map().span_to_snippet(local_decl.source_info.span)
749750
{
@@ -1310,6 +1311,16 @@ impl<'tcx> Visitor<'tcx> for BindingFinder {
13101311
hir::intravisit::walk_stmt(self, s)
13111312
}
13121313
}
1314+
1315+
fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) -> Self::Result {
1316+
if let hir::Pat { kind: hir::PatKind::Ref(_, _), span, .. } = param.pat
1317+
&& *span == self.span
1318+
{
1319+
ControlFlow::Break(param.hir_id)
1320+
} else {
1321+
ControlFlow::Continue(())
1322+
}
1323+
}
13131324
}
13141325

13151326
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {

src/tools/tidy/src/issues.txt

-1
Original file line numberDiff line numberDiff line change
@@ -3463,7 +3463,6 @@
34633463
"ui/pattern/issue-106552.rs",
34643464
"ui/pattern/issue-106862.rs",
34653465
"ui/pattern/issue-110508.rs",
3466-
"ui/pattern/issue-114896.rs",
34673466
"ui/pattern/issue-115599.rs",
34683467
"ui/pattern/issue-11577.rs",
34693468
"ui/pattern/issue-117626.rs",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
4+
fn main() {
5+
fn x(a: &char) {
6+
let &(mut b) = a;
7+
b.make_ascii_uppercase();
8+
//~^ cannot borrow `b` as mutable, as it is not declared as mutable
9+
}
10+
}

tests/ui/pattern/issue-114896.rs renamed to tests/ui/pattern/patkind-ref-binding-issue-114896.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
14
fn main() {
25
fn x(a: &char) {
36
let &b = a;

tests/ui/pattern/issue-114896.stderr renamed to tests/ui/pattern/patkind-ref-binding-issue-114896.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error[E0596]: cannot borrow `b` as mutable, as it is not declared as mutable
2-
--> $DIR/issue-114896.rs:4:9
2+
--> $DIR/patkind-ref-binding-issue-114896.rs:7:9
33
|
44
LL | let &b = a;
55
| -- help: consider changing this to be mutable: `&(mut b)`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
4+
fn mutate(_y: &mut i32) {}
5+
6+
fn foo(&(mut x): &i32) {
7+
mutate(&mut x);
8+
//~^ ERROR cannot borrow `x` as mutable
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//@ run-rustfix
2+
#![allow(dead_code)]
3+
4+
fn mutate(_y: &mut i32) {}
5+
6+
fn foo(&x: &i32) {
7+
mutate(&mut x);
8+
//~^ ERROR cannot borrow `x` as mutable
9+
}
10+
11+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
2+
--> $DIR/patkind-ref-binding-issue-122415.rs:7:12
3+
|
4+
LL | fn foo(&x: &i32) {
5+
| -- help: consider changing this to be mutable: `&(mut x)`
6+
LL | mutate(&mut x);
7+
| ^^^^^^ cannot borrow as mutable
8+
9+
error: aborting due to 1 previous error
10+
11+
For more information about this error, try `rustc --explain E0596`.

0 commit comments

Comments
 (0)