Skip to content

Commit b2eed3a

Browse files
Point out implicit deref coercions in borrow
Clean up code
1 parent 0e63af5 commit b2eed3a

16 files changed

+375
-4
lines changed

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

Lines changed: 33 additions & 4 deletions
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,6 +1542,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
15431542
None,
15441543
);
15451544

1545+
let tcx = self.infcx.tcx;
1546+
// point out implicit deref coercion
1547+
if let (
1548+
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
1549+
Some((method_did, method_substs)),
1550+
) = (
1551+
&self.body[loan.reserve_location.block].terminator,
1552+
crate::util::find_self_call(
1553+
tcx,
1554+
self.body,
1555+
loan.assigned_place.local,
1556+
loan.reserve_location.block,
1557+
),
1558+
) {
1559+
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
1560+
let deref_target =
1561+
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
1562+
Instance::resolve(tcx, self.param_env, deref_target, method_substs)
1563+
.transpose()
1564+
});
1565+
if let Some(Ok(instance)) = deref_target {
1566+
let deref_target_ty = instance.ty(tcx, self.param_env);
1567+
err.note(&format!(
1568+
"borrow occurs due to deref coercion to `{}`",
1569+
deref_target_ty
1570+
));
1571+
}
1572+
}
1573+
}
1574+
15461575
err.buffer(&mut self.errors_buffer);
15471576
}
15481577

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

Lines changed: 30 additions & 0 deletions
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() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0506`.

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

Lines changed: 37 additions & 0 deletions
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() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0506`.

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

Lines changed: 38 additions & 0 deletions
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() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0506`.

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

Lines changed: 33 additions & 0 deletions
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() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0506]: cannot assign to `self.container_field` because it is borrowed
2+
--> $DIR/issue-81365-5.rs:28:9
3+
|
4+
LL | let first = self.get();
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+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0506`.

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

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use std::ops::Deref;
2+
3+
struct Container {
4+
target: Vec<()>,
5+
container_field: bool,
6+
}
7+
8+
impl Deref for Container {
9+
type Target = [()];
10+
fn deref(&self) -> &Self::Target {
11+
&self.target
12+
}
13+
}
14+
15+
impl Container {
16+
fn bad_borrow(&mut self) {
17+
let first = &self[0];
18+
self.container_field = true; //~ ERROR E0506
19+
first;
20+
}
21+
}
22+
23+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0506]: cannot assign to `self.container_field` because it is borrowed
2+
--> $DIR/issue-81365-6.rs:18:9
3+
|
4+
LL | let first = &self[0];
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 `[()]`
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0506`.

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
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+
fn bad_borrow(c: &mut Container) {
19+
let first = &c.target_field;
20+
c.container_field = true; //~ ERROR E0506
21+
first;
22+
}
23+
24+
fn main() {}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error[E0506]: cannot assign to `c.container_field` because it is borrowed
2+
--> $DIR/issue-81365-7.rs:20:5
3+
|
4+
LL | let first = &c.target_field;
5+
| - borrow of `c.container_field` occurs here
6+
LL | c.container_field = true;
7+
| ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here
8+
LL | first;
9+
| ----- borrow later used here
10+
|
11+
= note: borrow occurs due to deref coercion to `DerefTarget`
12+
13+
error: aborting due to previous error
14+
15+
For more information about this error, try `rustc --explain E0506`.

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

Lines changed: 26 additions & 0 deletions
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() {}

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

Lines changed: 26 additions & 0 deletions
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() {}

0 commit comments

Comments
 (0)