Make analyze_move_out_from more field-sensitive

Currently analyze_move_out_from checks all restrictions on all base
paths of the move path, but it only needs to check restrictions from
loans of the base paths, and can disregard restrictions from loans of
extensions of those base paths.
This commit is contained in:
Cameron Zwarich 2014-06-13 20:48:09 -07:00
parent 8c0e1ce6c9
commit 45a1b97764
3 changed files with 51 additions and 30 deletions

View File

@ -871,26 +871,47 @@ impl<'a> CheckLoanCtxt<'a> {
self.tcx().map.node_to_str(expr_id),
move_path.repr(self.tcx()));
// We must check every element of a move path. See
// `borrowck-move-subcomponent.rs` for a test case.
let mut ret = MoveOk;
// First, we check for a restriction on the path P being used. This
// accounts for borrows of P but also borrows of subpaths, like P.a.b.
// Consider the following example:
//
// let x = &mut a.b.c; // Restricts a, a.b, and a.b.c
// let y = a; // Conflicts with restriction
self.each_in_scope_restriction(expr_id, move_path, |loan, _restr| {
// Any restriction prevents moves.
ret = MoveWhileBorrowed(loan.loan_path.clone(), loan.span);
false
});
// Next, we must check for *loans* (not restrictions) on the path P or
// any base path. This rejects examples like the following:
//
// let x = &mut a.b;
// let y = a.b.c;
//
// Limiting this search to *loans* and not *restrictions* means that
// examples like the following continue to work:
//
// let x = &mut a.b;
// let y = a.c;
let mut loan_path = move_path;
loop {
// check for a conflicting loan:
self.each_in_scope_restriction(expr_id, loan_path, |loan, _| {
self.each_in_scope_loan(expr_id, |loan| {
// Any restriction prevents moves.
ret = MoveWhileBorrowed(loan.loan_path.clone(), loan.span);
false
if *loan.loan_path == *loan_path {
ret = MoveWhileBorrowed(loan.loan_path.clone(), loan.span);
false
} else {
true
}
});
if ret != MoveOk {
return ret
}
match *loan_path {
LpVar(_) => {
ret = MoveOk;
break;
}
LpExtend(ref lp_base, _, _) => {
@ -898,6 +919,7 @@ impl<'a> CheckLoanCtxt<'a> {
}
}
}
ret
return ret;
}
}

View File

@ -84,20 +84,6 @@ fn fu_move_after_fu_move() {
// The following functions aren't yet accepted, but they should be.
fn move_after_borrow_correct() {
let x = A { a: 1, b: box 2 };
let p = &x.a;
drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed
drop(*p);
}
fn fu_move_after_borrow_correct() {
let x = A { a: 1, b: box 2 };
let p = &x.a;
let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed
drop(*p);
}
fn copy_after_field_assign_after_uninit() {
let mut x: A;
x.a = 1;
@ -132,9 +118,6 @@ fn main() {
fu_move_after_move();
fu_move_after_fu_move();
move_after_borrow_correct();
fu_move_after_borrow_correct();
copy_after_field_assign_after_uninit();
borrow_after_field_assign_after_uninit();
move_after_field_assign_after_uninit();

View File

@ -73,6 +73,20 @@ fn borrow_after_fu_move() {
drop(*p);
}
fn move_after_borrow() {
let x = A { a: 1, b: box 2 };
let p = &x.a;
drop(x.b);
drop(*p);
}
fn fu_move_after_borrow() {
let x = A { a: 1, b: box 2 };
let p = &x.a;
let _y = A { a: 3, .. x };
drop(*p);
}
fn mut_borrow_after_mut_borrow() {
let mut x = A { a: 1, b: box 2 };
let p = &mut x.a;
@ -225,6 +239,8 @@ fn main() {
borrow_after_move();
borrow_after_fu_move();
move_after_borrow();
fu_move_after_borrow();
mut_borrow_after_mut_borrow();
move_after_move();