if new_loan.loan_path.has_fork(&old_loan.loan_path) && common.is_some() {
let nl = self.bccx.loan_path_to_string(&common.unwrap());
let ol = nl.clone();
- let new_loan_msg = format!(" (via `{}`)",
- self.bccx.loan_path_to_string(
- &new_loan.loan_path));
- let old_loan_msg = format!(" (via `{}`)",
- self.bccx.loan_path_to_string(
- &old_loan.loan_path));
+ let new_loan_msg = self.bccx.loan_path_to_string(&new_loan.loan_path);
+ let old_loan_msg = self.bccx.loan_path_to_string(&old_loan.loan_path);
(nl, ol, new_loan_msg, old_loan_msg)
} else {
(self.bccx.loan_path_to_string(&new_loan.loan_path),
"closure"
};
- let (desc_place, msg_place, msg_borrow) = self.describe_place_for_conflicting_borrow(
- place, &issued_borrow.borrowed_place,
- );
- let via = |msg: String| if msg.is_empty() { msg } else { format!(" (via `{}`)", msg) };
- let msg_place = via(msg_place);
- let msg_borrow = via(msg_borrow);
+ let (desc_place, msg_place, msg_borrow, union_type_name) =
+ self.describe_place_for_conflicting_borrow(place, &issued_borrow.borrowed_place);
let explanation = self.explain_why_borrow_contains_point(context, issued_borrow, None);
let second_borrow_desc = if explanation.is_explained() {
);
}
+ if union_type_name != "" {
+ err.note(&format!(
+ "`{}` is a field of the union `{}`, so it overlaps the field `{}`",
+ msg_place, union_type_name, msg_borrow,
+ ));
+ }
+
explanation
.add_explanation_to_diagnostic(self.infcx.tcx, self.mir, &mut err, first_borrow_desc);
&self,
first_borrowed_place: &Place<'tcx>,
second_borrowed_place: &Place<'tcx>,
- ) -> (String, String, String) {
+ ) -> (String, String, String, String) {
// Define a small closure that we can use to check if the type of a place
// is a union.
let is_union = |place: &Place<'tcx>| -> bool {
.unwrap_or_else(|| "_".to_owned());
let desc_second = self.describe_place(second_borrowed_place)
.unwrap_or_else(|| "_".to_owned());
- return Some((desc_base, desc_first, desc_second));
+
+ // Also compute the name of the union type, eg. `Foo` so we
+ // can add a helpful note with it.
+ let ty = base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx);
+
+ return Some((desc_base, desc_first, desc_second, ty.to_string()));
},
_ => current = base,
}
// only return the description of the first place.
let desc_place = self.describe_place(first_borrowed_place)
.unwrap_or_else(|| "_".to_owned());
- (desc_place, "".to_string(), "".to_string())
+ (desc_place, "".to_string(), "".to_string(), "".to_string())
})
}
old_load_end_span: Option<Span>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
+ let via = |msg: &str|
+ if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
let mut err = struct_span_err!(
self,
new_loan_span,
E0499,
"cannot borrow `{}`{} as mutable more than once at a time{OGN}",
desc,
- opt_via,
+ via(opt_via),
OGN = o
);
if old_loan_span == new_loan_span {
} else {
err.span_label(
old_loan_span,
- format!("first mutable borrow occurs here{}", old_opt_via),
+ format!("first mutable borrow occurs here{}", via(old_opt_via)),
);
err.span_label(
new_loan_span,
- format!("second mutable borrow occurs here{}", opt_via),
+ format!("second mutable borrow occurs here{}", via(opt_via)),
);
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, "first borrow ends here");
old_load_end_span: Option<Span>,
o: Origin,
) -> DiagnosticBuilder<'cx> {
+ let via = |msg: &str|
+ if msg.is_empty() { msg.to_string() } else { format!(" (via `{}`)", msg) };
let mut err = struct_span_err!(
self,
span,
E0502,
- "cannot borrow `{}`{} as {} because {} is also borrowed as {}{}{OGN}",
+ "cannot borrow `{}`{} as {} because {} is also borrowed \
+ as {}{}{OGN}",
desc_new,
- msg_new,
+ via(msg_new),
kind_new,
noun_old,
kind_old,
- msg_old,
+ via(msg_old),
OGN = o
);
- err.span_label(span, format!("{} borrow occurs here{}", kind_new, msg_new));
- err.span_label(
- old_span,
- format!("{} borrow occurs here{}", kind_old, msg_old),
- );
+
+ if msg_new == "" {
+ // If `msg_new` is empty, then this isn't a borrow of a union field.
+ err.span_label(span, format!("{} borrow occurs here", kind_new));
+ err.span_label(old_span, format!("{} borrow occurs here", kind_old));
+ } else {
+ // If `msg_new` isn't empty, then this a borrow of a union field.
+ err.span_label(
+ span,
+ format!(
+ "{} borrow of `{}` -- which overlaps with `{}` -- occurs here",
+ kind_new, msg_new, msg_old,
+ )
+ );
+ err.span_label(
+ old_span,
+ format!("{} borrow occurs here{}", kind_old, via(msg_old)),
+ );
+ }
+
if let Some(old_load_end_span) = old_load_end_span {
err.span_label(old_load_end_span, format!("{} borrow ends here", kind_old));
}
+
self.cancel_if_wrong_origin(err, o)
}
LL | let bar1 = &mut foo.bar1;
| -------- mutable borrow occurs here (via `foo.bar1`)
LL | let _foo1 = &foo.bar2; //~ ERROR cannot borrow
- | ^^^^^^^^ immutable borrow occurs here (via `foo.bar2`)
+ | ^^^^^^^^ immutable borrow of `foo.bar2` -- which overlaps with `foo.bar1` -- occurs here
LL | *bar1;
LL | }
| - mutable borrow ends here
LL | let _x = &mut a.x;
| --- mutable borrow occurs here (via `a.x`)
LL | let _y = &a.y; //[ast]~ ERROR cannot borrow
- | ^^^ immutable borrow occurs here (via `a.y`)
+ | ^^^ immutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
...
LL | }
| - mutable borrow ends here
LL | let _x = &a.x;
| --- immutable borrow occurs here (via `a.x`)
LL | let _y = &mut a.y; //[ast]~ ERROR cannot borrow
- | ^^^ mutable borrow occurs here (via `a.y`)
+ | ^^^ mutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
...
LL | }
| - immutable borrow ends here
let mut a: Box<_> = box A { x: box 0, y: 1 };
let _x = &mut a.x;
let _y = &a.y; //[ast]~ ERROR cannot borrow
- //[ast]~^ immutable borrow occurs here (via `a.y`)
+ //[ast]~^ immutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
use_mut(_x);
}
fn mut_borrow_after_borrow() {
let mut a: Box<_> = box A { x: box 0, y: 1 };
let _x = &a.x;
let _y = &mut a.y; //[ast]~ ERROR cannot borrow
- //[ast]~^ mutable borrow occurs here (via `a.y`)
+ //[ast]~^ mutable borrow of `a.y` -- which overlaps with `a.x` -- occurs here
use_imm(_x);
}
fn copy_after_move_nested() {
LL | let ra = &u.a;
| ---- 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`)
+ | ^^^^^^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
LL | drop(ra);
| -- immutable borrow later used here
+ |
+ = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:51:13
LL | let rma = &mut u.a;
| -------- 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`)
+ | ^^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
LL | drop(rma);
| --- mutable borrow later used here
+ |
+ = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
error[E0503]: cannot use `u.b` because it was mutably borrowed
--> $DIR/borrowck-union-borrow.rs:83:21
| ^^^^^^^^ second mutable borrow occurs here (via `u.b`)
LL | drop(rma);
| --- first borrow later used here
+ |
+ = note: `u.b` is a field of the union `U`, so it overlaps the field `u.a`
error[E0506]: cannot assign to `u.b` because it is borrowed
--> $DIR/borrowck-union-borrow.rs:94:13
LL | let ra = &u.a;
| --- 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`)
+ | ^^^ mutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
LL | drop(ra);
LL | }
| - immutable borrow ends here
LL | let rma = &mut u.a;
| --- 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`)
+ | ^^^ immutable borrow of `u.b` -- which overlaps with `u.a` -- occurs here
LL | drop(rma);
LL | }
| - mutable borrow ends here
--> $DIR/issue-17263.rs:21:32
|
LL | let (c, d) = (&mut foo.a, &foo.b);
- | ----- ^^^^^ immutable borrow occurs here (via `foo.b`)
+ | ----- ^^^^^ immutable borrow of `foo.b` -- which overlaps with `foo.a` -- occurs here
| |
| mutable borrow occurs here (via `foo.a`)
...
| ---------- mutable borrow occurs here (via `u.s.a`)
...
LL | let nref = &u.z.c;
- | ^^^^^^ immutable borrow occurs here (via `u.z.c`)
+ | ^^^^^^ immutable borrow of `u.z.c` -- which overlaps with `u.s.a` -- occurs here
LL | //~^ ERROR cannot borrow `u` (via `u.z.c`) as immutable because it is also borrowed as mutable (via `u.s.a`) [E0502]
LL | println!("{} {}", mref, nref)
| ---- mutable borrow later used here
+ |
+ = note: `u.z.c` is a field of the union `U`, so it overlaps the field `u.s.a`
error: aborting due to previous error
| -------------------------------------- mutable borrow occurs here (via `r.r2_union.f3_union.s1_leaf.l1_u8`)
...
LL | let nref = &r.r2_union.f3_union.s2_leaf.l1_u8;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here (via `r.r2_union.f3_union.s2_leaf.l1_u8`)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow of `r.r2_union.f3_union.s2_leaf.l1_u8` -- which overlaps with `r.r2_union.f3_union.s1_leaf.l1_u8` -- occurs here
...
LL | println!("{} {}", mref, nref)
| ---- mutable borrow later used here
+ |
+ = note: `r.r2_union.f3_union.s2_leaf.l1_u8` is a field of the union `Second`, so it overlaps the field `r.r2_union.f3_union.s1_leaf.l1_u8`
error[E0502]: cannot borrow `r.r2_union` (via `r.r2_union.f1_leaf.l1_u8`) as immutable because it is also borrowed as mutable (via `r.r2_union.f2_leaf.l1_u8`)
--> $DIR/issue-57100.rs:62:20
| ----------------------------- mutable borrow occurs here (via `r.r2_union.f2_leaf.l1_u8`)
...
LL | let nref = &r.r2_union.f1_leaf.l1_u8;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow occurs here (via `r.r2_union.f1_leaf.l1_u8`)
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ immutable borrow of `r.r2_union.f1_leaf.l1_u8` -- which overlaps with `r.r2_union.f2_leaf.l1_u8` -- occurs here
...
LL | println!("{} {}", mref, nref)
| ---- mutable borrow later used here
+ |
+ = note: `r.r2_union.f1_leaf.l1_u8` is a field of the union `First`, so it overlaps the field `r.r2_union.f2_leaf.l1_u8`
error: aborting due to 2 previous errors
LL | let a = &mut u.x.0;
| ---------- mutable borrow occurs here (via `u.x.0`)
LL | let b = &u.y; //~ ERROR cannot borrow `u.y`
- | ^^^^ immutable borrow occurs here (via `u.y`)
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here
LL | use_borrow(a);
| - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:22:13
LL | let a = &mut (u.x.0).0;
| -------------- mutable borrow occurs here (via `u.x.0.0`)
LL | let b = &u.y; //~ ERROR cannot borrow `u.y`
- | ^^^^ immutable borrow occurs here (via `u.y`)
+ | ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here
LL | use_borrow(a);
| - mutable borrow later used here
+ |
+ = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:35:13
LL | let a = &mut *u.y;
| --------- mutable borrow occurs here (via `*u.y`)
LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
- | ^^^^ immutable borrow occurs here (via `u.x`)
+ | ^^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here
LL | use_borrow(a);
| - mutable borrow later used here
+ |
+ = note: `u.x` is a field of the union `U`, so it overlaps the field `*u.y`
error[E0382]: use of moved value: `u`
--> $DIR/union-borrow-move-parent-sibling.rs:48:13
LL | let a = &mut *u.y;
| ---- mutable borrow occurs here (via `*u.y`)
LL | let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
- | ^^^ immutable borrow occurs here (via `u.x`)
+ | ^^^ immutable borrow of `u.x` -- which overlaps with `*u.y` -- occurs here
LL | use_borrow(a);
LL | }
| - mutable borrow ends here