From: David Wood Date: Fri, 4 Jan 2019 21:43:51 +0000 (+0100) Subject: Improve diagnostic labels and add note. X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=c2b477c19af9c5b8241e3d37a9d8a9cf1616750f;p=rust.git Improve diagnostic labels and add note. This commit improves diagnostic labels to mention which field a borrow overlaps with and adds a note explaining that the fields overlap. --- diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 04085387c37..cafb29ed99a 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -557,12 +557,8 @@ pub fn report_error_if_loan_conflicts_with_restriction(&self, 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), diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index aeba56cb7e2..f6a80d7fae3 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -329,12 +329,8 @@ pub(super) fn report_conflicting_borrow( "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() { @@ -516,6 +512,13 @@ pub(super) fn report_conflicting_borrow( ); } + 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); @@ -549,7 +552,7 @@ pub(super) fn describe_place_for_conflicting_borrow( &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 { @@ -600,7 +603,12 @@ pub(super) fn describe_place_for_conflicting_borrow( .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, } @@ -612,7 +620,7 @@ pub(super) fn describe_place_for_conflicting_borrow( // 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()) }) } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs index 5e55bb4a9b6..7ad73aaa3f9 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/src/librustc_mir/util/borrowck_errors.rs @@ -138,13 +138,15 @@ fn cannot_mutably_borrow_multiply( old_load_end_span: Option, 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 { @@ -164,11 +166,11 @@ fn cannot_mutably_borrow_multiply( } 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"); @@ -292,27 +294,46 @@ fn cannot_reborrow_already_borrowed( old_load_end_span: Option, 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) } diff --git a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr index 79dc55bbbae..e116cb70c1c 100644 --- a/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-from-owned-ptr.stderr @@ -138,7 +138,7 @@ error[E0502]: cannot borrow `foo` (via `foo.bar2`) as immutable because `foo` is 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 diff --git a/src/test/ui/borrowck/borrowck-box-insensitivity.ast.stderr b/src/test/ui/borrowck/borrowck-box-insensitivity.ast.stderr index 95b26a5724a..236064da3e8 100644 --- a/src/test/ui/borrowck/borrowck-box-insensitivity.ast.stderr +++ b/src/test/ui/borrowck/borrowck-box-insensitivity.ast.stderr @@ -61,7 +61,7 @@ error[E0502]: cannot borrow `a` (via `a.y`) as immutable because `a` is also bor 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 @@ -72,7 +72,7 @@ error[E0502]: cannot borrow `a` (via `a.y`) as mutable because `a` is also borro 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 diff --git a/src/test/ui/borrowck/borrowck-box-insensitivity.rs b/src/test/ui/borrowck/borrowck-box-insensitivity.rs index 2af97a9fc1d..e72048d0ea4 100644 --- a/src/test/ui/borrowck/borrowck-box-insensitivity.rs +++ b/src/test/ui/borrowck/borrowck-box-insensitivity.rs @@ -83,14 +83,14 @@ fn borrow_after_mut_borrow() { 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() { diff --git a/src/test/ui/borrowck/borrowck-union-borrow.nll.stderr b/src/test/ui/borrowck/borrowck-union-borrow.nll.stderr index ef5dcef04b0..5cba30b43b8 100644 --- a/src/test/ui/borrowck/borrowck-union-borrow.nll.stderr +++ b/src/test/ui/borrowck/borrowck-union-borrow.nll.stderr @@ -24,9 +24,11 @@ error[E0502]: cannot borrow `u` (via `u.b`) as mutable because it is also borrow 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 @@ -84,9 +86,11 @@ error[E0502]: cannot borrow `u` (via `u.b`) as immutable because it is also borr 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 @@ -108,6 +112,8 @@ LL | let rmb2 = &mut u.b; //~ ERROR cannot borrow `u` (via `u.b`) as | ^^^^^^^^ 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 diff --git a/src/test/ui/borrowck/borrowck-union-borrow.stderr b/src/test/ui/borrowck/borrowck-union-borrow.stderr index f9010d3bf08..ef6a331eda0 100644 --- a/src/test/ui/borrowck/borrowck-union-borrow.stderr +++ b/src/test/ui/borrowck/borrowck-union-borrow.stderr @@ -23,7 +23,7 @@ error[E0502]: cannot borrow `u` (via `u.b`) as mutable because `u` is also borro 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 @@ -80,7 +80,7 @@ error[E0502]: cannot borrow `u` (via `u.b`) as immutable because `u` is also bor 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 diff --git a/src/test/ui/issues/issue-17263.ast.stderr b/src/test/ui/issues/issue-17263.ast.stderr index 3d42dcb52f5..823f2c747d6 100644 --- a/src/test/ui/issues/issue-17263.ast.stderr +++ b/src/test/ui/issues/issue-17263.ast.stderr @@ -13,7 +13,7 @@ error[E0502]: cannot borrow `foo` (via `foo.b`) as immutable because `foo` is al --> $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`) ... diff --git a/src/test/ui/issues/issue-45157.stderr b/src/test/ui/issues/issue-45157.stderr index eadbd608699..3b15a8dbd9e 100644 --- a/src/test/ui/issues/issue-45157.stderr +++ b/src/test/ui/issues/issue-45157.stderr @@ -5,10 +5,12 @@ LL | let mref = &mut u.s.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 diff --git a/src/test/ui/nll/issue-57100.stderr b/src/test/ui/nll/issue-57100.stderr index 34dcdfc4947..5d5c86c3487 100644 --- a/src/test/ui/nll/issue-57100.stderr +++ b/src/test/ui/nll/issue-57100.stderr @@ -5,10 +5,12 @@ LL | let mref = &mut r.r2_union.f3_union.s1_leaf.l1_u8; | -------------------------------------- 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 @@ -17,10 +19,12 @@ LL | let mref = &mut r.r2_union.f2_leaf.l1_u8; | ----------------------------- 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 diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr index 4bf3b6286aa..848c3d9bdb0 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.nll.stderr @@ -4,9 +4,11 @@ error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borr 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 @@ -24,9 +26,11 @@ error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borr 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 @@ -44,9 +48,11 @@ error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borr 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 diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.stderr index c5baf82c745..9058707e505 100644 --- a/src/test/ui/union/union-borrow-move-parent-sibling.stderr +++ b/src/test/ui/union/union-borrow-move-parent-sibling.stderr @@ -46,7 +46,7 @@ error[E0502]: cannot borrow `u` (via `u.x`) as immutable because `u` is also bor 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