Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NLL: Add union justifications to conflicting borrows. #57102

Merged
merged 3 commits into from
Jan 13, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 48 additions & 10 deletions src/librustc_mir/borrow_check/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,10 +329,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
"closure"
};

let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned());
let tcx = self.infcx.tcx;

let first_borrow_desc;
let (desc_place, msg_place, msg_borrow) = if issued_borrow.borrowed_place == *place {
let desc_place = self.describe_place(place).unwrap_or_else(|| "_".to_owned());
(desc_place, "".to_string(), "".to_string())
} else {
let (desc_place, msg_place) = self.describe_place_for_conflicting_borrow(place);
let (_, msg_borrow) = self.describe_place_for_conflicting_borrow(
&issued_borrow.borrowed_place
);
(desc_place, msg_place, msg_borrow)
};

let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None);
let second_borrow_desc = if explanation.is_explained() {
Expand All @@ -342,6 +348,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
};

// FIXME: supply non-"" `opt_via` when appropriate
let tcx = self.infcx.tcx;
let first_borrow_desc;
let mut err = match (
gen_borrow_kind,
"immutable",
Expand All @@ -355,12 +363,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
tcx.cannot_reborrow_already_borrowed(
span,
&desc_place,
"",
&msg_place,
lft,
issued_span,
"it",
rgt,
"",
&msg_borrow,
None,
Origin::Mir,
)
Expand All @@ -370,12 +378,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
tcx.cannot_reborrow_already_borrowed(
span,
&desc_place,
"",
&msg_place,
lft,
issued_span,
"it",
rgt,
"",
&msg_borrow,
None,
Origin::Mir,
)
Expand All @@ -386,9 +394,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
tcx.cannot_mutably_borrow_multiply(
span,
&desc_place,
"",
&msg_place,
issued_span,
"",
&msg_borrow,
None,
Origin::Mir,
)
Expand Down Expand Up @@ -518,6 +526,36 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
err.buffer(&mut self.errors_buffer);
}

/// Returns a description of a place and an associated message for the purposes of conflicting
/// borrow diagnostics.
///
/// If the borrow is of the field `b` of a union `u`, then the return value will be
/// `("u", " (via \`u.b\`)")`. Otherwise, for some variable `a`, the return value will be
/// `("a", "")`.
pub(super) fn describe_place_for_conflicting_borrow(
&self,
place: &Place<'tcx>,
) -> (String, String) {
place.base_local()
davidtwco marked this conversation as resolved.
Show resolved Hide resolved
.filter(|local| {
// Filter out non-unions.
self.mir.local_decls[*local].ty
.ty_adt_def()
.map(|adt| adt.is_union())
.unwrap_or(false)
})
.and_then(|local| {
let desc_base = self.describe_place(&Place::Local(local))
.unwrap_or_else(|| "_".to_owned());
let desc_original = self.describe_place(place)
.unwrap_or_else(|| "_".to_owned());
return Some((desc_base, format!(" (via `{}`)", desc_original)));
})
.unwrap_or_else(|| {
(self.describe_place(place).unwrap_or_else(|| "_".to_owned()), "".to_string())
})
}

/// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
///
/// This means that some data referenced by `borrow` needs to live
Expand Down
Original file line number Diff line number Diff line change
@@ -1,132 +1,121 @@
error[E0502]: cannot borrow `u.a` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-union-borrow.rs:27:23
--> $DIR/borrowck-union-borrow.rs:25:23
|
LL | let ra = &u.a;
| ---- immutable borrow occurs here
LL | let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
LL | let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
| ^^^^^^^^ mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
LL | drop(ra);
| -- immutable borrow later used here

error[E0506]: cannot assign to `u.a` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:33:13
--> $DIR/borrowck-union-borrow.rs:30:13
|
LL | let ra = &u.a;
| ---- borrow of `u.a` occurs here
LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
| ^^^^^^^ assignment to borrowed `u.a` occurs here
LL | //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
LL | drop(ra);
| -- borrow later used here

error[E0502]: cannot borrow `u.b` as mutable because it is also borrowed as immutable
--> $DIR/borrowck-union-borrow.rs:50:23
error[E0502]: cannot borrow `u` (via `u.b`) as mutable because it is also borrowed as immutable (via `u.a`)
davidtwco marked this conversation as resolved.
Show resolved Hide resolved
--> $DIR/borrowck-union-borrow.rs:46:23
|
LL | let ra = &u.a;
| ---- immutable borrow occurs here
LL | let rmb = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
| ^^^^^^^^ mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable
| ---- immutable borrow occurs here (via `u.a`)
LL | let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
| ^^^^^^^^ mutable borrow occurs here (via `u.b`)
LL | drop(ra);
| -- immutable borrow later used here

error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:56:13
--> $DIR/borrowck-union-borrow.rs:51:13
|
LL | let ra = &u.a;
| ---- borrow of `u.b` occurs here
LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
| ^^^^^^^ assignment to borrowed `u.b` occurs here
LL | //[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
LL | drop(ra);
| -- borrow later used here

error[E0502]: cannot borrow `u.a` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-union-borrow.rs:63:22
--> $DIR/borrowck-union-borrow.rs:57:22
|
LL | let rma = &mut u.a;
| -------- mutable borrow occurs here
LL | let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
LL | let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
| ^^^^ immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
LL | drop(rma);
| --- mutable borrow later used here

error[E0503]: cannot use `u.a` because it was mutably borrowed
--> $DIR/borrowck-union-borrow.rs:69:21
--> $DIR/borrowck-union-borrow.rs:62:21
|
LL | let ra = &mut u.a;
| -------- borrow of `u.a` occurs here
LL | let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
LL | let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
| ^^^ use of borrowed `u.a`
LL | //[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed
LL | drop(ra);
| -- borrow later used here

error[E0499]: cannot borrow `u.a` as mutable more than once at a time
--> $DIR/borrowck-union-borrow.rs:75:24
--> $DIR/borrowck-union-borrow.rs:67:24
|
LL | let rma = &mut u.a;
| -------- first mutable borrow occurs here
LL | let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time
LL | let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
| ^^^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time
LL | drop(rma);
| --- first borrow later used here

error[E0506]: cannot assign to `u.a` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:81:13
--> $DIR/borrowck-union-borrow.rs:72:13
|
LL | let rma = &mut u.a;
| -------- borrow of `u.a` occurs here
LL | u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
LL | u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
| ^^^^^^^ assignment to borrowed `u.a` occurs here
LL | //[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
LL | drop(rma);
| --- borrow later used here

error[E0502]: cannot borrow `u.b` as immutable because it is also borrowed as mutable
--> $DIR/borrowck-union-borrow.rs:88:22
error[E0502]: cannot borrow `u` (via `u.b`) as immutable because it is also borrowed as mutable (via `u.a`)
--> $DIR/borrowck-union-borrow.rs:78:22
|
LL | let rma = &mut u.a;
| -------- mutable borrow occurs here
LL | let rb = &u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
| ^^^^ immutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable
| -------- mutable borrow occurs here (via `u.a`)
LL | let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
| ^^^^ immutable borrow occurs here (via `u.b`)
LL | drop(rma);
| --- mutable borrow later used here

error[E0503]: cannot use `u.b` because it was mutably borrowed
--> $DIR/borrowck-union-borrow.rs:94:21
--> $DIR/borrowck-union-borrow.rs:83:21
|
LL | let ra = &mut u.a;
| -------- borrow of `u.a` occurs here
LL | let b = u.b; //[ast]~ ERROR cannot use `u.b` because it was mutably borrowed
LL | let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed
| ^^^ use of borrowed `u.a`
...
LL |
LL | drop(ra);
| -- borrow later used here

error[E0499]: cannot borrow `u.b` as mutable more than once at a time
--> $DIR/borrowck-union-borrow.rs:101:24
error[E0499]: cannot borrow `u` (via `u.b`) as mutable more than once at a time
--> $DIR/borrowck-union-borrow.rs:89:24
|
LL | let rma = &mut u.a;
| -------- first mutable borrow occurs here
LL | let rmb2 = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
| ^^^^^^^^ second mutable borrow occurs here
LL | //[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time
| -------- first mutable borrow occurs here (via `u.a`)
LL | let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
| ^^^^^^^^ second mutable borrow occurs here (via `u.b`)
LL | drop(rma);
| --- first borrow later used here

error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:107:13
--> $DIR/borrowck-union-borrow.rs:94:13
|
LL | let rma = &mut u.a;
| -------- borrow of `u.b` occurs here
LL | u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
LL | u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
| ^^^^^^^ assignment to borrowed `u.b` occurs here
LL | //[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
LL | drop(rma);
| --- borrow later used here

Expand Down
38 changes: 12 additions & 26 deletions src/test/ui/borrowck/borrowck-union-borrow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// ignore-tidy-linelength
// revisions: ast mir
//[mir]compile-flags: -Z borrowck=mir

#[derive(Clone, Copy)]
union U {
Expand All @@ -24,14 +22,12 @@ fn main() {
}
{
let ra = &u.a;
let rma = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
//[mir]~^ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
let rma = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable because it is also borrowed as immutable
drop(ra);
}
{
let ra = &u.a;
u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
drop(ra);
}
// Imm borrow, other field
Expand All @@ -47,65 +43,55 @@ fn main() {
}
{
let ra = &u.a;
let rmb = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
//[mir]~^ ERROR cannot borrow `u.b` as mutable because it is also borrowed as immutable
let rmb = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable because `u` is also borrowed as immutable (via `u.a`)
drop(ra);
}
{
let ra = &u.a;
u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
drop(ra);
}
// Mut borrow, same field
{
let rma = &mut u.a;
let ra = &u.a; //[ast]~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
//[mir]~^ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
let ra = &u.a; //~ ERROR cannot borrow `u.a` as immutable because it is also borrowed as mutable
drop(rma);
}
{
let ra = &mut u.a;
let a = u.a; //[ast]~ ERROR cannot use `u.a` because it was mutably borrowed
//[mir]~^ ERROR cannot use `u.a` because it was mutably borrowed
let a = u.a; //~ ERROR cannot use `u.a` because it was mutably borrowed
drop(ra);
}
{
let rma = &mut u.a;
let rma2 = &mut u.a; //[ast]~ ERROR cannot borrow `u.a` as mutable more than once at a time
//[mir]~^ ERROR cannot borrow `u.a` as mutable more than once at a time
let rma2 = &mut u.a; //~ ERROR cannot borrow `u.a` as mutable more than once at a time
drop(rma);
}
{
let rma = &mut u.a;
u.a = 1; //[ast]~ ERROR cannot assign to `u.a` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.a` because it is borrowed
u.a = 1; //~ ERROR cannot assign to `u.a` because it is borrowed
drop(rma);
}
// Mut borrow, other field
{
let rma = &mut u.a;
let rb = &u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
//[mir]~^ ERROR cannot borrow `u.b` as immutable because it is also borrowed as mutable
let rb = &u.b; //~ ERROR cannot borrow `u` (via `u.b`) as immutable because `u` is also borrowed as mutable (via `u.a`)
drop(rma);
}
{
let ra = &mut u.a;
let b = u.b; //[ast]~ ERROR cannot use `u.b` because it was mutably borrowed
//[mir]~^ ERROR cannot use `u.b` because it was mutably borrowed
let b = u.b; //~ ERROR cannot use `u.b` because it was mutably borrowed

drop(ra);
}
{
let rma = &mut u.a;
let rmb2 = &mut u.b; //[ast]~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
//[mir]~^ ERROR cannot borrow `u.b` as mutable more than once at a time
let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as mutable more than once at a time
drop(rma);
}
{
let rma = &mut u.a;
u.b = 1; //[ast]~ ERROR cannot assign to `u.b` because it is borrowed
//[mir]~^ ERROR cannot assign to `u.b` because it is borrowed
u.b = 1; //~ ERROR cannot assign to `u.b` because it is borrowed
drop(rma);
}
}
Expand Down
Loading