Skip to content

Commit 02c6ebd

Browse files
committed
Change the use of moved value error to be more accurate
Previously it output `partially moved` to eagerly. This updates it to be more accurate and output `collaterally moved` for use of values that were invalidated by moves out of different fields in the same struct. Closes #15630.
1 parent 35ff2de commit 02c6ebd

File tree

6 files changed

+62
-22
lines changed

6 files changed

+62
-22
lines changed

src/librustc/middle/borrowck/mod.rs

+48-11
Original file line numberDiff line numberDiff line change
@@ -461,24 +461,58 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
461461
MovedInCapture => "capture",
462462
};
463463

464-
match the_move.kind {
464+
let (ol, moved_lp_msg) = match the_move.kind {
465465
move_data::Declared => {
466466
self.tcx.sess.span_err(
467467
use_span,
468468
format!("{} of possibly uninitialized variable: `{}`",
469469
verb,
470470
self.loan_path_to_string(lp)).as_slice());
471+
(self.loan_path_to_string(moved_lp),
472+
String::new())
471473
}
472474
_ => {
473-
let partially = if lp == moved_lp {""} else {"partially "};
475+
// If moved_lp is something like `x.a`, and lp is something like `x.b`, we would
476+
// normally generate a rather confusing message:
477+
//
478+
// error: use of moved value: `x.b`
479+
// note: `x.a` moved here...
480+
//
481+
// What we want to do instead is get the 'common ancestor' of the two moves and
482+
// use that for most of the message instead, giving is something like this:
483+
//
484+
// error: use of moved value: `x`
485+
// note: `x` moved here (through moving `x.a`)...
486+
487+
let common = moved_lp.common(lp);
488+
let has_common = common.is_some();
489+
let has_fork = moved_lp.has_fork(lp);
490+
let (nl, ol, moved_lp_msg) =
491+
if has_fork && has_common {
492+
let nl = self.loan_path_to_string(&common.unwrap());
493+
let ol = nl.clone();
494+
let moved_lp_msg = format!(" (through moving `{}`)",
495+
self.loan_path_to_string(moved_lp));
496+
(nl, ol, moved_lp_msg)
497+
} else {
498+
(self.loan_path_to_string(lp),
499+
self.loan_path_to_string(moved_lp),
500+
String::new())
501+
};
502+
503+
let partial = moved_lp.depth() > lp.depth();
504+
let msg = if !has_fork && partial { "partially " }
505+
else if has_fork && !has_common { "collaterally "}
506+
else { "" };
474507
self.tcx.sess.span_err(
475508
use_span,
476509
format!("{} of {}moved value: `{}`",
477510
verb,
478-
partially,
479-
self.loan_path_to_string(lp)).as_slice());
511+
msg,
512+
nl).as_slice());
513+
(ol, moved_lp_msg)
480514
}
481-
}
515+
};
482516

483517
match the_move.kind {
484518
move_data::Declared => {}
@@ -501,19 +535,21 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
501535
"moved by default (use `copy` to override)");
502536
self.tcx.sess.span_note(
503537
expr_span,
504-
format!("`{}` moved here because it has type `{}`, which is {}",
505-
self.loan_path_to_string(moved_lp),
538+
format!("`{}` moved here{} because it has type `{}`, which is {}",
539+
ol,
540+
moved_lp_msg,
506541
expr_ty.user_string(self.tcx),
507542
suggestion).as_slice());
508543
}
509544

510545
move_data::MovePat => {
511546
let pat_ty = ty::node_id_to_type(self.tcx, the_move.id);
512547
self.tcx.sess.span_note(self.tcx.map.span(the_move.id),
513-
format!("`{}` moved here because it has type `{}`, \
548+
format!("`{}` moved here{} because it has type `{}`, \
514549
which is moved by default (use `ref` to \
515550
override)",
516-
self.loan_path_to_string(moved_lp),
551+
ol,
552+
moved_lp_msg,
517553
pat_ty.user_string(self.tcx)).as_slice());
518554
}
519555

@@ -536,9 +572,10 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
536572
capture that instead to override)");
537573
self.tcx.sess.span_note(
538574
expr_span,
539-
format!("`{}` moved into closure environment here because it \
575+
format!("`{}` moved into closure environment here{} because it \
540576
has type `{}`, which is {}",
541-
self.loan_path_to_string(moved_lp),
577+
ol,
578+
moved_lp_msg,
542579
expr_ty.user_string(self.tcx),
543580
suggestion).as_slice());
544581
}

src/test/compile-fail/borrowck-box-insensitivity.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,22 @@ struct D {
3131
fn copy_after_move() {
3232
let a = box A { x: box 0, y: 1 };
3333
let _x = a.x;
34-
let _y = a.y; //~ ERROR use of partially moved
34+
let _y = a.y; //~ ERROR use of moved
35+
//~^^ NOTE `a` moved here (through moving `a.x`)
3536
}
3637

3738
fn move_after_move() {
3839
let a = box B { x: box 0, y: box 1 };
3940
let _x = a.x;
40-
let _y = a.y; //~ ERROR use of partially moved
41+
let _y = a.y; //~ ERROR use of moved
42+
//~^^ NOTE `a` moved here (through moving `a.x`)
4143
}
4244

4345
fn borrow_after_move() {
4446
let a = box A { x: box 0, y: 1 };
4547
let _x = a.x;
46-
let _y = &a.y; //~ ERROR use of partially moved
48+
let _y = &a.y; //~ ERROR use of moved
49+
//~^^ NOTE `a` moved here (through moving `a.x`)
4750
}
4851

4952
fn move_after_borrow() {
@@ -79,19 +82,19 @@ fn mut_borrow_after_borrow() {
7982
fn copy_after_move_nested() {
8083
let a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
8184
let _x = a.x.x;
82-
let _y = a.y; //~ ERROR use of partially moved
85+
let _y = a.y; //~ ERROR use of collaterally moved
8386
}
8487

8588
fn move_after_move_nested() {
8689
let a = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
8790
let _x = a.x.x;
88-
let _y = a.y; //~ ERROR use of partially moved
91+
let _y = a.y; //~ ERROR use of collaterally moved
8992
}
9093

9194
fn borrow_after_move_nested() {
9295
let a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
9396
let _x = a.x.x;
94-
let _y = &a.y; //~ ERROR use of partially moved
97+
let _y = &a.y; //~ ERROR use of collaterally moved
9598
}
9699

97100
fn move_after_borrow_nested() {

src/test/compile-fail/borrowck-field-sensitivity.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ struct A { a: int, b: Box<int> }
1313
fn deref_after_move() {
1414
let x = A { a: 1, b: box 2 };
1515
drop(x.b);
16-
drop(*x.b); //~ ERROR use of partially moved value: `*x.b`
16+
drop(*x.b); //~ ERROR use of moved value: `*x.b`
1717
}
1818

1919
fn deref_after_fu_move() {
2020
let x = A { a: 1, b: box 2 };
2121
let y = A { a: 3, .. x };
22-
drop(*x.b); //~ ERROR use of partially moved value: `*x.b`
22+
drop(*x.b); //~ ERROR use of moved value: `*x.b`
2323
}
2424

2525
fn borrow_after_move() {

src/test/compile-fail/liveness-use-after-move.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ extern crate debug;
1313
fn main() {
1414
let x = box 5i;
1515
let y = x;
16-
println!("{:?}", *x); //~ ERROR use of partially moved value: `*x`
16+
println!("{:?}", *x); //~ ERROR use of moved value: `*x`
1717
y.clone();
1818
}

src/test/compile-fail/use-after-move-self-based-on-type.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ impl Drop for S {
1919
impl S {
2020
pub fn foo(self) -> int {
2121
self.bar();
22-
return self.x; //~ ERROR use of partially moved value: `self.x`
22+
return self.x; //~ ERROR use of moved value: `self.x`
2323
}
2424

2525
pub fn bar(self) {}

src/test/compile-fail/use-after-move-self.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ struct S {
1616
impl S {
1717
pub fn foo(self) -> int {
1818
self.bar();
19-
return *self.x; //~ ERROR use of partially moved value: `*self.x`
19+
return *self.x; //~ ERROR use of moved value: `*self.x`
2020
}
2121

2222
pub fn bar(self) {}

0 commit comments

Comments
 (0)