Skip to content

Commit a922780

Browse files
committed
More precisely point out what is immutable for E0596
1 parent 90f0b24 commit a922780

File tree

7 files changed

+110
-9
lines changed

7 files changed

+110
-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
@@ -511,9 +511,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
511511
self.expected_fn_found_fn_mut_call(&mut err, span, act);
512512
}
513513

514-
PlaceRef { local: _, projection: [.., ProjectionElem::Deref] } => {
515-
err.span_label(span, format!("cannot {act}"));
516-
514+
PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => {
515+
let mut span = span;
517516
match opt_source {
518517
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
519518
err.help(format!(
@@ -528,8 +527,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
528527
));
529528
self.suggest_map_index_mut_alternatives(ty, &mut err, span);
530529
}
530+
Some(BorrowedContentSource::DerefSharedRef) => {
531+
let place_ref =
532+
PlaceRef { local: the_place_err.local, projection: proj_base };
533+
let ty = place_ref.ty(self.body, self.infcx.tcx).ty;
534+
self.suggest_detailed_hint_for_ref(ty, &mut err, &mut span);
535+
}
531536
_ => (),
532537
}
538+
err.span_label(span, format!("cannot {act}"));
533539
}
534540

535541
_ => {
@@ -544,6 +550,46 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
544550
}
545551
}
546552

553+
fn suggest_detailed_hint_for_ref(&self, ty: Ty<'_>, err: &mut Diagnostic, span: &mut Span) {
554+
struct ExprFinder {
555+
span: Span,
556+
hir_id: Option<hir::HirId>,
557+
}
558+
559+
impl<'tcx> Visitor<'tcx> for ExprFinder {
560+
fn visit_expr(&mut self, s: &'tcx hir::Expr<'tcx>) {
561+
if s.span.contains(self.span) {
562+
self.hir_id = Some(s.hir_id);
563+
}
564+
hir::intravisit::walk_expr(self, s);
565+
}
566+
}
567+
let hir_map = self.infcx.tcx.hir();
568+
let def_id = self.body.source.def_id();
569+
let hir_id = if let Some(local_def_id) = def_id.as_local()
570+
&& let Some(body_id) = hir_map.maybe_body_owned_by(local_def_id) {
571+
let body = hir_map.body(body_id);
572+
let mut v = ExprFinder {
573+
span: *span,
574+
hir_id: None,
575+
};
576+
v.visit_body(body);
577+
v.hir_id
578+
} else {
579+
None
580+
};
581+
let expr = if let Some(hir_id) = hir_id {
582+
hir_map.expect_expr(hir_id)
583+
} else {
584+
return;
585+
};
586+
if let hir::ExprKind::AddrOf(hir::BorrowKind::Ref, Mutability::Mut, ex) = expr.kind
587+
&& !matches!(ex.kind, hir::ExprKind::Unary(hir::UnOp::Deref, _) | hir::ExprKind::Field(_, _) | hir::ExprKind::Lit(_)) {
588+
*span = ex.span;
589+
err.span_help(ex.span, format!("this expression is of type `{:?}`, which is an immutable reference", ty));
590+
}
591+
}
592+
547593
fn suggest_map_index_mut_alternatives(&self, ty: Ty<'tcx>, err: &mut Diagnostic, span: Span) {
548594
let Some(adt) = ty.ty_adt_def() else { return };
549595
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: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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+
fn main() {
12+
some_library::foo(&mut some_library::bar()); //~ ERROR cannot borrow data in a `&` reference as mutable
13+
}

tests/ui/borrowck/issue_113842.stderr

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
error[E0596]: cannot borrow data in a `&` reference as mutable
2+
--> $DIR/issue_113842.rs:12:23
3+
|
4+
LL | some_library::foo(&mut some_library::bar());
5+
| ^^^^^-------------------
6+
| |
7+
| cannot borrow as mutable
8+
|
9+
help: this expression is of type `&[i32]`, which is an immutable reference
10+
--> $DIR/issue_113842.rs:12:28
11+
|
12+
LL | some_library::foo(&mut some_library::bar());
13+
| ^^^^^^^^^^^^^^^^^^^
14+
15+
error: aborting due to previous error
16+
17+
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 `&std::option::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)