Skip to content

Commit

Permalink
Add union justifications to conflicting borrows.
Browse files Browse the repository at this point in the history
This commit adds justifications to error messages for conflicting
borrows of union fields.

Where previously an error message would say
``cannot borrow `u.b` as mutable..``, it now says
``cannot borrow `u` (via `u.b`) as mutable..``.
  • Loading branch information
davidtwco committed Dec 26, 2018
1 parent 79d8a0f commit 69bded2
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 127 deletions.
58 changes: 48 additions & 10 deletions src/librustc_mir/borrow_check/error_reporting.rs
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()
.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
@@ -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`)
--> $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
@@ -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

0 comments on commit 69bded2

Please sign in to comment.