Skip to content

Commit

Permalink
Point out implicit deref coercions in borrow
Browse files Browse the repository at this point in the history
Clean up code
  • Loading branch information
sledgehammervampire committed Feb 8, 2021
1 parent 0e63af5 commit b2eed3a
Show file tree
Hide file tree
Showing 16 changed files with 375 additions and 4 deletions.
37 changes: 33 additions & 4 deletions compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
Expand Up @@ -8,11 +8,10 @@ use rustc_index::vec::Idx;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef,
ProjectionElem, Rvalue, Statement, StatementKind, TerminatorKind, VarBindingForm,
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
};
use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
use rustc_span::source_map::DesugaringKind;
use rustc_span::Span;
use rustc_middle::ty::{self, suggest_constraining_type_param, Instance, Ty};
use rustc_span::{source_map::DesugaringKind, symbol::sym, Span};

use crate::dataflow::drop_flag_effects;
use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
Expand Down Expand Up @@ -1543,6 +1542,36 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
);

let tcx = self.infcx.tcx;
// point out implicit deref coercion
if let (
Some(Terminator { kind: TerminatorKind::Call { from_hir_call: false, .. }, .. }),
Some((method_did, method_substs)),
) = (
&self.body[loan.reserve_location.block].terminator,
crate::util::find_self_call(
tcx,
self.body,
loan.assigned_place.local,
loan.reserve_location.block,
),
) {
if tcx.is_diagnostic_item(sym::deref_method, method_did) {
let deref_target =
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
Instance::resolve(tcx, self.param_env, deref_target, method_substs)
.transpose()
});
if let Some(Ok(instance)) = deref_target {
let deref_target_ty = instance.ty(tcx, self.param_env);
err.note(&format!(
"borrow occurs due to deref coercion to `{}`",
deref_target_ty
));
}
}
}

err.buffer(&mut self.errors_buffer);
}

Expand Down
30 changes: 30 additions & 0 deletions src/test/ui/borrowck/issue-81365-2.rs
@@ -0,0 +1,30 @@
use std::ops::Deref;

struct DerefTarget {
target_field: bool,
}
struct Container {
target: DerefTarget,
container_field: bool,
}

impl Deref for Container {
type Target = DerefTarget;
fn deref(&self) -> &Self::Target {
&self.target
}
}

struct Outer {
container: Container,
}

impl Outer {
fn bad_borrow(&mut self) {
let first = &self.container.target_field;
self.container.container_field = true; //~ ERROR E0506
first;
}
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/borrowck/issue-81365-2.stderr
@@ -0,0 +1,15 @@
error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
--> $DIR/issue-81365-2.rs:25:9
|
LL | let first = &self.container.target_field;
| -------------- borrow of `self.container.container_field` occurs here
LL | self.container.container_field = true;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
LL | first;
| ----- borrow later used here
|
= note: borrow occurs due to deref coercion to `DerefTarget`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
37 changes: 37 additions & 0 deletions src/test/ui/borrowck/issue-81365-3.rs
@@ -0,0 +1,37 @@
use std::ops::Deref;

struct DerefTarget {
target_field: bool,
}
struct Container {
target: DerefTarget,
container_field: bool,
}

impl Deref for Container {
type Target = DerefTarget;
fn deref(&self) -> &Self::Target {
&self.target
}
}

struct Outer {
container: Container,
}

impl Deref for Outer {
type Target = Container;
fn deref(&self) -> &Self::Target {
&self.container
}
}

impl Outer {
fn bad_borrow(&mut self) {
let first = &self.target_field;
self.container.container_field = true; //~ ERROR E0506
first;
}
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/borrowck/issue-81365-3.stderr
@@ -0,0 +1,15 @@
error[E0506]: cannot assign to `self.container.container_field` because it is borrowed
--> $DIR/issue-81365-3.rs:32:9
|
LL | let first = &self.target_field;
| ---- borrow of `self.container.container_field` occurs here
LL | self.container.container_field = true;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container.container_field` occurs here
LL | first;
| ----- borrow later used here
|
= note: borrow occurs due to deref coercion to `Container`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
38 changes: 38 additions & 0 deletions src/test/ui/borrowck/issue-81365-4.rs
@@ -0,0 +1,38 @@
use std::ops::Deref;

struct DerefTarget {
target_field: bool,
}
struct Container {
target: DerefTarget,
container_field: bool,
}

impl Deref for Container {
type Target = DerefTarget;
fn deref(&self) -> &Self::Target {
&self.target
}
}

struct Outer {
container: Container,
outer_field: bool,
}

impl Deref for Outer {
type Target = Container;
fn deref(&self) -> &Self::Target {
&self.container
}
}

impl Outer {
fn bad_borrow(&mut self) {
let first = &self.target_field;
self.outer_field = true; //~ ERROR E0506
first;
}
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/borrowck/issue-81365-4.stderr
@@ -0,0 +1,15 @@
error[E0506]: cannot assign to `self.outer_field` because it is borrowed
--> $DIR/issue-81365-4.rs:33:9
|
LL | let first = &self.target_field;
| ---- borrow of `self.outer_field` occurs here
LL | self.outer_field = true;
| ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.outer_field` occurs here
LL | first;
| ----- borrow later used here
|
= note: borrow occurs due to deref coercion to `Container`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
33 changes: 33 additions & 0 deletions src/test/ui/borrowck/issue-81365-5.rs
@@ -0,0 +1,33 @@
use std::ops::Deref;

struct DerefTarget {
target_field: bool,
}

impl DerefTarget {
fn get(&self) -> &bool {
&self.target_field
}
}

struct Container {
target: DerefTarget,
container_field: bool,
}

impl Deref for Container {
type Target = DerefTarget;
fn deref(&self) -> &Self::Target {
&self.target
}
}

impl Container {
fn bad_borrow(&mut self) {
let first = self.get();
self.container_field = true; //~ ERROR E0506
first;
}
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/borrowck/issue-81365-5.stderr
@@ -0,0 +1,15 @@
error[E0506]: cannot assign to `self.container_field` because it is borrowed
--> $DIR/issue-81365-5.rs:28:9
|
LL | let first = self.get();
| ---- borrow of `self.container_field` occurs here
LL | self.container_field = true;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
LL | first;
| ----- borrow later used here
|
= note: borrow occurs due to deref coercion to `DerefTarget`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
23 changes: 23 additions & 0 deletions src/test/ui/borrowck/issue-81365-6.rs
@@ -0,0 +1,23 @@
use std::ops::Deref;

struct Container {
target: Vec<()>,
container_field: bool,
}

impl Deref for Container {
type Target = [()];
fn deref(&self) -> &Self::Target {
&self.target
}
}

impl Container {
fn bad_borrow(&mut self) {
let first = &self[0];
self.container_field = true; //~ ERROR E0506
first;
}
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/borrowck/issue-81365-6.stderr
@@ -0,0 +1,15 @@
error[E0506]: cannot assign to `self.container_field` because it is borrowed
--> $DIR/issue-81365-6.rs:18:9
|
LL | let first = &self[0];
| ---- borrow of `self.container_field` occurs here
LL | self.container_field = true;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.container_field` occurs here
LL | first;
| ----- borrow later used here
|
= note: borrow occurs due to deref coercion to `[()]`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
24 changes: 24 additions & 0 deletions src/test/ui/borrowck/issue-81365-7.rs
@@ -0,0 +1,24 @@
use std::ops::Deref;

struct DerefTarget {
target_field: bool,
}
struct Container {
target: DerefTarget,
container_field: bool,
}

impl Deref for Container {
type Target = DerefTarget;
fn deref(&self) -> &Self::Target {
&self.target
}
}

fn bad_borrow(c: &mut Container) {
let first = &c.target_field;
c.container_field = true; //~ ERROR E0506
first;
}

fn main() {}
15 changes: 15 additions & 0 deletions src/test/ui/borrowck/issue-81365-7.stderr
@@ -0,0 +1,15 @@
error[E0506]: cannot assign to `c.container_field` because it is borrowed
--> $DIR/issue-81365-7.rs:20:5
|
LL | let first = &c.target_field;
| - borrow of `c.container_field` occurs here
LL | c.container_field = true;
| ^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `c.container_field` occurs here
LL | first;
| ----- borrow later used here
|
= note: borrow occurs due to deref coercion to `DerefTarget`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
26 changes: 26 additions & 0 deletions src/test/ui/borrowck/issue-81365-8.rs
@@ -0,0 +1,26 @@
use std::ops::Deref;

struct DerefTarget {
target_field: bool,
}
struct Container {
target: DerefTarget,
container_field: bool,
}

impl Deref for Container {
type Target = DerefTarget;
fn deref(&self) -> &Self::Target {
&self.target
}
}

impl Container {
fn bad_borrow(&mut self) {
let first = &(*self).target_field;
self.container_field = true; //~ ERROR E0506
first;
}
}

fn main() {}
26 changes: 26 additions & 0 deletions src/test/ui/borrowck/issue-81365.rs
@@ -0,0 +1,26 @@
use std::ops::Deref;

struct DerefTarget {
target_field: bool,
}
struct Container {
target: DerefTarget,
container_field: bool,
}

impl Deref for Container {
type Target = DerefTarget;
fn deref(&self) -> &Self::Target {
&self.target
}
}

impl Container {
fn bad_borrow(&mut self) {
let first = &self.target_field;
self.container_field = true; //~ ERROR E0506
first;
}
}

fn main() {}

0 comments on commit b2eed3a

Please sign in to comment.