Skip to content

Commit 18d1284

Browse files
authored
Rollup merge of #81629 - 1000teslas:issue-81365-fix, r=Aaron1011
Point out implicit deref coercions in borrow Fixes #81365 `@Aaron1011` I'm not sure why my code shows the note even in an implicit `Deref` call. See the output for `issue-81365-8.rs`.
2 parents 446d453 + 1847a6c commit 18d1284

23 files changed

+557
-4
lines changed

compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs

+37-4
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ use rustc_index::vec::Idx;
88
use rustc_middle::mir::{
99
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
1010
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
11-
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
11+
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
1212
};
13-
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
14-
use rustc_span::source_map::DesugaringKind;
15-
use rustc_span::Span;
13+
use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty};
14+
use rustc_span::{source_map::DesugaringKind, symbol::sym, Span};
1615

1716
use crate::dataflow::drop_flag_effects;
1817
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
@@ -1543,9 +1542,43 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15431542
None,
15441543
);
15451544

1545+
self.explain_deref_coercion(loan, &mut err);
1546+
15461547
err.buffer(&mut self.errors_buffer);
15471548
}
15481549

1550+
fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
1551+
let tcx = self.infcx.tcx;
1552+
if let (
1553+
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
1554+
Some((method_did, method_substs)),
1555+
) = (
1556+
&self.body[loan.reserve_location.block].terminator,
1557+
crate::util::find_self_call(
1558+
tcx,
1559+
self.body,
1560+
loan.assigned_place.local,
1561+
loan.reserve_location.block,
1562+
),
1563+
) {
1564+
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
1565+
let deref_target =
1566+
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
1567+
Instance::resolve(tcx, self.param_env, deref_target, method_substs)
1568+
.transpose()
1569+
});
1570+
if let Some(Ok(instance)) = deref_target {
1571+
let deref_target_ty = instance.ty(tcx, self.param_env);
1572+
err.note(&format!(
1573+
"borrow occurs due to deref coercion to `{}`",
1574+
deref_target_ty
1575+
));
1576+
err.span_note(tcx.def_span(instance.def_id()), "deref defined here");
1577+
}
1578+
}
1579+
}
1580+
}
1581+
15491582
/// Reports an illegal reassignment; for example, an assignment to
15501583
/// (part of) a non-`mut` local that occurs potentially after that
15511584
/// local has already been initialized. `place` is the path being

src/test/ui/borrowck/issue-81365-1.rs

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::ops::Deref;
2+
3+
struct DerefTarget {
4+
target_field: bool,
5+
}
6+
struct Container {
7+
target: DerefTarget,
8+
container_field: bool,
9+
}
10+
11+
impl Deref for Container {
12+
type Target = DerefTarget;
13+
fn deref(&self) -> &Self::Target {
14+
&self.target
15+
}
16+
}
17+
18+
impl Container {
19+
fn bad_borrow(&mut self) {
20+
let first = &self.target_field;
21+
self.container_field = true; //~ ERROR E0506
22+
first;
23+
}
24+
}
25+
26+
fn main() {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0506]: cannot assign to `self.container_field` because it is borrowed
2+
--> $DIR/issue-81365-1.rs:21:9
3+
|
4+
LL | let first = &self.target_field;
5+
| ---- borrow of `self.container_field` occurs here
6+
LL | self.container_field = true;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
8+
LL | first;
9+
| ----- borrow later used here
10+
|
11+
= note: borrow occurs due to deref coercion to `DerefTarget`
12+
note: deref defined here
13+
--> $DIR/issue-81365-1.rs:12:5
14+
|
15+
LL | type Target = DerefTarget;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0506`.
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::ops::Deref;
2+
3+
struct DerefTarget {
4+
target_field: bool,
5+
}
6+
struct Container {
7+
target: DerefTarget,
8+
container_field: bool,
9+
}
10+
11+
impl Deref for Container {
12+
type Target = DerefTarget;
13+
fn deref(&self) -> &Self::Target {
14+
&self.target
15+
}
16+
}
17+
18+
impl Container {
19+
fn bad_borrow(&mut self) {
20+
let first = &self.deref().target_field;
21+
self.container_field = true; //~ ERROR E0506
22+
first;
23+
}
24+
}
25+
26+
fn main() {}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0506]: cannot assign to `self.container_field` because it is borrowed
2+
--> $DIR/issue-81365-10.rs:21:9
3+
|
4+
LL | let first = &self.deref().target_field;
5+
| ---- borrow of `self.container_field` occurs here
6+
LL | self.container_field = true;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
8+
LL | first;
9+
| ----- borrow later used here
10+
11+
error: aborting due to previous error
12+
13+
For more information about this error, try `rustc --explain E0506`.
+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
use std::ops::{Deref, DerefMut};
2+
3+
struct DerefTarget {
4+
target_field: bool,
5+
}
6+
struct Container {
7+
target: DerefTarget,
8+
container_field: bool,
9+
}
10+
11+
impl Deref for Container {
12+
type Target = DerefTarget;
13+
fn deref(&self) -> &Self::Target {
14+
&self.target
15+
}
16+
}
17+
18+
impl DerefMut for Container {
19+
fn deref_mut(&mut self) -> &mut Self::Target {
20+
&mut self.target
21+
}
22+
}
23+
24+
impl Container {
25+
fn bad_borrow(&mut self) {
26+
let first = &mut self.target_field;
27+
self.container_field = true; //~ ERROR E0506
28+
first;
29+
}
30+
}
31+
32+
fn main() {}
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
error[E0506]: cannot assign to `self.container_field` because it is borrowed
2+
--> $DIR/issue-81365-11.rs:27:9
3+
|
4+
LL | let first = &mut self.target_field;
5+
| ---- borrow of `self.container_field` occurs here
6+
LL | self.container_field = true;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
8+
LL | first;
9+
| ----- borrow later used here
10+
11+
error: aborting due to previous error
12+
13+
For more information about this error, try `rustc --explain E0506`.

src/test/ui/borrowck/issue-81365-2.rs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use std::ops::Deref;
2+
3+
struct DerefTarget {
4+
target_field: bool,
5+
}
6+
struct Container {
7+
target: DerefTarget,
8+
container_field: bool,
9+
}
10+
11+
impl Deref for Container {
12+
type Target = DerefTarget;
13+
fn deref(&self) -> &Self::Target {
14+
&self.target
15+
}
16+
}
17+
18+
struct Outer {
19+
container: Container,
20+
}
21+
22+
impl Outer {
23+
fn bad_borrow(&mut self) {
24+
let first = &self.container.target_field;
25+
self.container.container_field = true; //~ ERROR E0506
26+
first;
27+
}
28+
}
29+
30+
fn main() {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
2+
--> $DIR/issue-81365-2.rs:25:9
3+
|
4+
LL | let first = &self.container.target_field;
5+
| -------------- borrow of `self.container.container_field` occurs here
6+
LL | self.container.container_field = true;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
8+
LL | first;
9+
| ----- borrow later used here
10+
|
11+
= note: borrow occurs due to deref coercion to `DerefTarget`
12+
note: deref defined here
13+
--> $DIR/issue-81365-2.rs:12:5
14+
|
15+
LL | type Target = DerefTarget;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0506`.

src/test/ui/borrowck/issue-81365-3.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use std::ops::Deref;
2+
3+
struct DerefTarget {
4+
target_field: bool,
5+
}
6+
struct Container {
7+
target: DerefTarget,
8+
container_field: bool,
9+
}
10+
11+
impl Deref for Container {
12+
type Target = DerefTarget;
13+
fn deref(&self) -> &Self::Target {
14+
&self.target
15+
}
16+
}
17+
18+
struct Outer {
19+
container: Container,
20+
}
21+
22+
impl Deref for Outer {
23+
type Target = Container;
24+
fn deref(&self) -> &Self::Target {
25+
&self.container
26+
}
27+
}
28+
29+
impl Outer {
30+
fn bad_borrow(&mut self) {
31+
let first = &self.target_field;
32+
self.container.container_field = true; //~ ERROR E0506
33+
first;
34+
}
35+
}
36+
37+
fn main() {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
2+
--> $DIR/issue-81365-3.rs:32:9
3+
|
4+
LL | let first = &self.target_field;
5+
| ---- borrow of `self.container.container_field` occurs here
6+
LL | self.container.container_field = true;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
8+
LL | first;
9+
| ----- borrow later used here
10+
|
11+
= note: borrow occurs due to deref coercion to `Container`
12+
note: deref defined here
13+
--> $DIR/issue-81365-3.rs:23:5
14+
|
15+
LL | type Target = Container;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0506`.

src/test/ui/borrowck/issue-81365-4.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::ops::Deref;
2+
3+
struct DerefTarget {
4+
target_field: bool,
5+
}
6+
struct Container {
7+
target: DerefTarget,
8+
container_field: bool,
9+
}
10+
11+
impl Deref for Container {
12+
type Target = DerefTarget;
13+
fn deref(&self) -> &Self::Target {
14+
&self.target
15+
}
16+
}
17+
18+
struct Outer {
19+
container: Container,
20+
outer_field: bool,
21+
}
22+
23+
impl Deref for Outer {
24+
type Target = Container;
25+
fn deref(&self) -> &Self::Target {
26+
&self.container
27+
}
28+
}
29+
30+
impl Outer {
31+
fn bad_borrow(&mut self) {
32+
let first = &self.target_field;
33+
self.outer_field = true; //~ ERROR E0506
34+
first;
35+
}
36+
}
37+
38+
fn main() {}
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error[E0506]: cannot assign to `self.outer_field` because it is borrowed
2+
--> $DIR/issue-81365-4.rs:33:9
3+
|
4+
LL | let first = &self.target_field;
5+
| ---- borrow of `self.outer_field` occurs here
6+
LL | self.outer_field = true;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here
8+
LL | first;
9+
| ----- borrow later used here
10+
|
11+
= note: borrow occurs due to deref coercion to `Container`
12+
note: deref defined here
13+
--> $DIR/issue-81365-4.rs:24:5
14+
|
15+
LL | type Target = Container;
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^
17+
18+
error: aborting due to previous error
19+
20+
For more information about this error, try `rustc --explain E0506`.

src/test/ui/borrowck/issue-81365-5.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use std::ops::Deref;
2+
3+
struct DerefTarget {
4+
target_field: bool,
5+
}
6+
7+
impl DerefTarget {
8+
fn get(&self) -> &bool {
9+
&self.target_field
10+
}
11+
}
12+
13+
struct Container {
14+
target: DerefTarget,
15+
container_field: bool,
16+
}
17+
18+
impl Deref for Container {
19+
type Target = DerefTarget;
20+
fn deref(&self) -> &Self::Target {
21+
&self.target
22+
}
23+
}
24+
25+
impl Container {
26+
fn bad_borrow(&mut self) {
27+
let first = self.get();
28+
self.container_field = true; //~ ERROR E0506
29+
first;
30+
}
31+
}
32+
33+
fn main() {}

0 commit comments

Comments
 (0)