Skip to content

Commit fc0abde

Browse files
committed
More precisely point out what is immutable for E0596
1 parent e9addfd commit fc0abde

File tree

7 files changed

+133
-9
lines changed

7 files changed

+133
-9
lines changed

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -506,9 +506,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
506506
self.expected_fn_found_fn_mut_call(&mut err, span, act);
507507
}
508508

509-
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
510-
err.span_label(span, format!("cannot {act}"));
511-
509+
PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
510+
let mut span = span;
512511
match opt_source {
513512
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
514513
err.help(format!(
@@ -523,8 +522,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
523522
));
524523
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
525524
}
525+
Some(BorrowedContentSource::DerefSharedRef) => {
526+
let place_ref =
527+
PlaceRef { local: the_place_err.local, projection: proj_base };
528+
let ty = place_ref.ty(self.body, self.infcx.tcx).ty;
529+
self.suggest_detailed_hint_for_ref(ty, &mut err, &mut span);
530+
}
526531
_ => (),
527532
}
533+
err.span_label(span, format!("cannot {act}"));
528534
}
529535

530536
_ => {
@@ -539,6 +545,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
539545
}
540546
}
541547

548+
fn suggest_detailed_hint_for_ref(&self, ty: Ty<'_>, err: &mut Diagnostic, span: &mut Span) {
549+
struct ExprFinder {
550+
span: Span,
551+
hir_id: Option<hir::HirId>,
552+
}
553+
554+
impl<'tcx> Visitor<'tcx> for ExprFinder {
555+
fn visit_expr(&mut self, s: &'tcx hir::Expr<'tcx>) {
556+
if s.span.contains(self.span) {
557+
self.hir_id = Some(s.hir_id);
558+
}
559+
hir::intravisit::walk_expr(self, s);
560+
}
561+
}
562+
let hir_map = self.infcx.tcx.hir();
563+
let def_id = self.body.source.def_id();
564+
let hir_id = if let Some(local_def_id) = def_id.as_local()
565+
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) {
566+
let body = hir_map.body(body_id);
567+
let mut v = ExprFinder {
568+
span: *span,
569+
hir_id: None,
570+
};
571+
v.visit_body(body);
572+
v.hir_id
573+
} else {
574+
None
575+
};
576+
let expr = if let Some(hir_id) = hir_id {
577+
hir_map.expect_expr(hir_id)
578+
} else {
579+
return;
580+
};
581+
if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, Mutability::Mut, ex) = expr.kind
582+
&& !matches!(ex.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _) | hir::ExprKind::Field(_, _) | hir::ExprKind::Lit(_)) {
583+
*span = ex.span;
584+
err.span_help(ex.span, format!("this expression is of type `{}`, which is an immutable reference", ty));
585+
}
586+
}
587+
542588
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
543589
let Some(adt) = ty.ty_adt_def() else { return };
544590
let did = adt.did();

tests/ui/borrowck/issue-111554.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,15 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
1414
--> $DIR/issue-111554.rs:10:16
1515
|
1616
LL | || bar(&mut self);
17-
| ^^^^^^^^^ cannot borrow as mutable
17+
| ^^^^^----
18+
| |
19+
| cannot borrow as mutable
20+
|
21+
help: this expression is of type `&Foo`, which is an immutable reference
22+
--> $DIR/issue-111554.rs:10:21
23+
|
24+
LL | || bar(&mut self);
25+
| ^^^^
1826

1927
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
2028
--> $DIR/issue-111554.rs:21:16

tests/ui/borrowck/issue_113842.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
mod some_library {
2+
pub fn foo(_: &mut [i32]) {}
3+
pub fn bar<'a>() -> &'a [i32] {
4+
&[]
5+
}
6+
pub fn bar_mut<'a>() -> &'a mut [i32] {
7+
&mut []
8+
}
9+
}
10+
11+
struct Foo {
12+
pub x: i32,
13+
}
14+
15+
fn foo() {
16+
let foo = Foo { x: 0 };
17+
let _y: &mut Foo = &mut &foo; //~ ERROR cannot borrow data in a `&` reference as mutable
18+
}
19+
20+
fn main() {
21+
some_library::foo(&mut some_library::bar()); //~ ERROR cannot borrow data in a `&` reference as mutable
22+
}

tests/ui/borrowck/issue_113842.stderr

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0596]: cannot borrow data in a `&` reference as mutable
2+
--> $DIR/issue_113842.rs:17:24
3+
|
4+
LL | let _y: &mut Foo = &mut &foo;
5+
| ^^^^^----
6+
| |
7+
| cannot borrow as mutable
8+
|
9+
help: this expression is of type `&Foo`, which is an immutable reference
10+
--> $DIR/issue_113842.rs:17:29
11+
|
12+
LL | let _y: &mut Foo = &mut &foo;
13+
| ^^^^
14+
15+
error[E0596]: cannot borrow data in a `&` reference as mutable
16+
--> $DIR/issue_113842.rs:21:23
17+
|
18+
LL | some_library::foo(&mut some_library::bar());
19+
| ^^^^^-------------------
20+
| |
21+
| cannot borrow as mutable
22+
|
23+
help: this expression is of type `&[i32]`, which is an immutable reference
24+
--> $DIR/issue_113842.rs:21:28
25+
|
26+
LL | some_library::foo(&mut some_library::bar());
27+
| ^^^^^^^^^^^^^^^^^^^
28+
29+
error: aborting due to 2 previous errors
30+
31+
For more information about this error, try `rustc --explain E0596`.

tests/ui/let-else/let-else-binding-explicit-mut-borrow.stderr

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
22
--> $DIR/let-else-binding-explicit-mut-borrow.rs:7:37
33
|
44
LL | let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
5-
| ^^^^^^^^^^^^^^^^ cannot borrow as mutable
5+
| ^^^^^-----------
6+
| |
7+
| cannot borrow as mutable
8+
|
9+
help: this expression is of type `&Option<i32>`, which is an immutable reference
10+
--> $DIR/let-else-binding-explicit-mut-borrow.rs:7:42
11+
|
12+
LL | let Some(n): &mut Option<i32> = &mut &Some(5i32) else {
13+
| ^^^^^^^^^^^
614

715
error: aborting due to previous error
816

tests/ui/nll/issue-51191.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ impl Struct {
2222
(&mut self).bar();
2323
//~^ ERROR cannot borrow `self` as mutable, as it is not declared as mutable [E0596]
2424
//~^^ ERROR cannot borrow data in a `&` reference as mutable [E0596]
25+
//~^^^ HELP this expression is of type `&Struct`, which is an immutable reference
2526
}
2627

2728
fn mtblref(&mut self) {

tests/ui/nll/issue-51191.stderr

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,29 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
4848
--> $DIR/issue-51191.rs:22:9
4949
|
5050
LL | (&mut self).bar();
51-
| ^^^^^^^^^^^ cannot borrow as mutable
51+
| ^^^^^^----^
52+
| |
53+
| cannot borrow as mutable
54+
|
55+
help: this expression is of type `&Struct`, which is an immutable reference
56+
--> $DIR/issue-51191.rs:22:15
57+
|
58+
LL | (&mut self).bar();
59+
| ^^^^
5260

5361
error[E0596]: cannot borrow `self` as mutable, as it is not declared as mutable
54-
--> $DIR/issue-51191.rs:28:9
62+
--> $DIR/issue-51191.rs:29:9
5563
|
5664
LL | (&mut self).bar();
5765
| ^^^^^^^^^^^ cannot borrow as mutable
5866
|
5967
note: the binding is already a mutable borrow
60-
--> $DIR/issue-51191.rs:27:16
68+
--> $DIR/issue-51191.rs:28:16
6169
|
6270
LL | fn mtblref(&mut self) {
6371
| ^^^^^^^^^
6472
help: try removing `&mut` here
65-
--> $DIR/issue-51191.rs:28:9
73+
--> $DIR/issue-51191.rs:29:9
6674
|
6775
LL | (&mut self).bar();
6876
| ^^^^^^^^^^^

0 commit comments

Comments
 (0)