Skip to content

Commit

Permalink
Rollup merge of #81629 - 1000teslas:issue-81365-fix, r=Aaron1011
Browse files Browse the repository at this point in the history
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`.
  • Loading branch information
Dylan-DPC authored Feb 23, 2021
2 parents 446d453 + 1847a6c commit 18d1284
Show file tree
Hide file tree
Showing 23 changed files with 557 additions and 4 deletions.
41 changes: 37 additions & 4 deletions compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
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,9 +1542,43 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
);

self.explain_deref_coercion(loan, &mut err);

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

fn explain_deref_coercion(&mut self, loan: &BorrowData<'tcx>, err: &mut DiagnosticBuilder<'_>) {
let tcx = self.infcx.tcx;
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.span_note(tcx.def_span(instance.def_id()), "deref defined here");
}
}
}
}

/// Reports an illegal reassignment; for example, an assignment to
/// (part of) a non-`mut` local that occurs potentially after that
/// local has already been initialized. `place` is the path being
Expand Down
26 changes: 26 additions & 0 deletions src/test/ui/borrowck/issue-81365-1.rs
Original file line number Diff line number Diff line change
@@ -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() {}
20 changes: 20 additions & 0 deletions src/test/ui/borrowck/issue-81365-1.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error[E0506]: cannot assign to `self.container_field` because it is borrowed
--> $DIR/issue-81365-1.rs:21:9
|
LL | let first = &self.target_field;
| ---- 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`
note: deref defined here
--> $DIR/issue-81365-1.rs:12:5
|
LL | type Target = 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-10.rs
Original file line number Diff line number Diff line change
@@ -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.deref().target_field;
self.container_field = true; //~ ERROR E0506
first;
}
}

fn main() {}
13 changes: 13 additions & 0 deletions src/test/ui/borrowck/issue-81365-10.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0506]: cannot assign to `self.container_field` because it is borrowed
--> $DIR/issue-81365-10.rs:21:9
|
LL | let first = &self.deref().target_field;
| ---- 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

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
32 changes: 32 additions & 0 deletions src/test/ui/borrowck/issue-81365-11.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::ops::{Deref, DerefMut};

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 DerefMut for Container {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.target
}
}

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

fn main() {}
13 changes: 13 additions & 0 deletions src/test/ui/borrowck/issue-81365-11.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error[E0506]: cannot assign to `self.container_field` because it is borrowed
--> $DIR/issue-81365-11.rs:27:9
|
LL | let first = &mut self.target_field;
| ---- 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

error: aborting due to previous error

For more information about this error, try `rustc --explain E0506`.
30 changes: 30 additions & 0 deletions src/test/ui/borrowck/issue-81365-2.rs
Original file line number Diff line number Diff line change
@@ -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() {}
20 changes: 20 additions & 0 deletions src/test/ui/borrowck/issue-81365-2.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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`
note: deref defined here
--> $DIR/issue-81365-2.rs:12:5
|
LL | type Target = 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
Original file line number Diff line number Diff line change
@@ -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() {}
20 changes: 20 additions & 0 deletions src/test/ui/borrowck/issue-81365-3.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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`
note: deref defined here
--> $DIR/issue-81365-3.rs:23:5
|
LL | type Target = 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
Original file line number Diff line number Diff line change
@@ -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() {}
20 changes: 20 additions & 0 deletions src/test/ui/borrowck/issue-81365-4.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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`
note: deref defined here
--> $DIR/issue-81365-4.rs:24:5
|
LL | type Target = 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
Original file line number Diff line number Diff line change
@@ -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() {}
Loading

0 comments on commit 18d1284

Please sign in to comment.