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`.
This commit is contained in:
Dylan DPC 2021-02-23 16:10:20 +01:00 committed by GitHub
commit 18d1284433
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 557 additions and 4 deletions

View File

@ -8,11 +8,10 @@
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};
@ -1543,9 +1542,43 @@ pub(in crate::borrow_check) fn report_illegal_mutation_of_borrowed(
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

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -0,0 +1,20 @@
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`
note: deref defined here
--> $DIR/issue-81365-5.rs:19:5
|
LL | type Target = DerefTarget;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0506`.

View File

@ -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() {}

View File

@ -0,0 +1,20 @@
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 `[()]`
note: deref defined here
--> $DIR/issue-81365-6.rs:9:5
|
LL | type Target = [()];
| ^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0506`.

View File

@ -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() {}

View File

@ -0,0 +1,20 @@
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`
note: deref defined here
--> $DIR/issue-81365-7.rs:12:5
|
LL | type Target = DerefTarget;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0506`.

View File

@ -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() {}

View File

@ -0,0 +1,20 @@
error[E0506]: cannot assign to `self.container_field` because it is borrowed
--> $DIR/issue-81365-8.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-8.rs:12:5
|
LL | type Target = DerefTarget;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0506`.

View File

@ -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 = &Deref::deref(self).target_field;
self.container_field = true; //~ ERROR E0506
first;
}
}
fn main() {}

View File

@ -0,0 +1,13 @@
error[E0506]: cannot assign to `self.container_field` because it is borrowed
--> $DIR/issue-81365-9.rs:21:9
|
LL | let first = &Deref::deref(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`.