Skip to content

Commit 45a1b97

Browse files
author
Cameron Zwarich
committed
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.
1 parent 8c0e1ce commit 45a1b97

File tree

3 files changed

+51
-30
lines changed

3 files changed

+51
-30
lines changed

src/librustc/middle/borrowck/check_loans.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -871,33 +871,55 @@ impl<'a> CheckLoanCtxt<'a> {
871871
self.tcx().map.node_to_str(expr_id),
872872
move_path.repr(self.tcx()));
873873

874-
// We must check every element of a move path. See
875-
// `borrowck-move-subcomponent.rs` for a test case.
876-
877874
let mut ret = MoveOk;
875+
876+
// First, we check for a restriction on the path P being used. This
877+
// accounts for borrows of P but also borrows of subpaths, like P.a.b.
878+
// Consider the following example:
879+
//
880+
// let x = &mut a.b.c; // Restricts a, a.b, and a.b.c
881+
// let y = a; // Conflicts with restriction
882+
883+
self.each_in_scope_restriction(expr_id, move_path, |loan, _restr| {
884+
// Any restriction prevents moves.
885+
ret = MoveWhileBorrowed(loan.loan_path.clone(), loan.span);
886+
false
887+
});
888+
889+
// Next, we must check for *loans* (not restrictions) on the path P or
890+
// any base path. This rejects examples like the following:
891+
//
892+
// let x = &mut a.b;
893+
// let y = a.b.c;
894+
//
895+
// Limiting this search to *loans* and not *restrictions* means that
896+
// examples like the following continue to work:
897+
//
898+
// let x = &mut a.b;
899+
// let y = a.c;
900+
878901
let mut loan_path = move_path;
879902
loop {
880-
// check for a conflicting loan:
881-
self.each_in_scope_restriction(expr_id, loan_path, |loan, _| {
903+
self.each_in_scope_loan(expr_id, |loan| {
882904
// Any restriction prevents moves.
883-
ret = MoveWhileBorrowed(loan.loan_path.clone(), loan.span);
884-
false
905+
if *loan.loan_path == *loan_path {
906+
ret = MoveWhileBorrowed(loan.loan_path.clone(), loan.span);
907+
false
908+
} else {
909+
true
910+
}
885911
});
886912

887-
if ret != MoveOk {
888-
return ret
889-
}
890-
891913
match *loan_path {
892914
LpVar(_) => {
893-
ret = MoveOk;
894915
break;
895916
}
896917
LpExtend(ref lp_base, _, _) => {
897918
loan_path = &**lp_base;
898919
}
899920
}
900921
}
901-
ret
922+
923+
return ret;
902924
}
903925
}

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

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -84,20 +84,6 @@ fn fu_move_after_fu_move() {
8484

8585
// The following functions aren't yet accepted, but they should be.
8686

87-
fn move_after_borrow_correct() {
88-
let x = A { a: 1, b: box 2 };
89-
let p = &x.a;
90-
drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed
91-
drop(*p);
92-
}
93-
94-
fn fu_move_after_borrow_correct() {
95-
let x = A { a: 1, b: box 2 };
96-
let p = &x.a;
97-
let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed
98-
drop(*p);
99-
}
100-
10187
fn copy_after_field_assign_after_uninit() {
10288
let mut x: A;
10389
x.a = 1;
@@ -132,9 +118,6 @@ fn main() {
132118
fu_move_after_move();
133119
fu_move_after_fu_move();
134120

135-
move_after_borrow_correct();
136-
fu_move_after_borrow_correct();
137-
138121
copy_after_field_assign_after_uninit();
139122
borrow_after_field_assign_after_uninit();
140123
move_after_field_assign_after_uninit();

src/test/run-pass/borrowck-field-sensitivity.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ fn borrow_after_fu_move() {
7373
drop(*p);
7474
}
7575

76+
fn move_after_borrow() {
77+
let x = A { a: 1, b: box 2 };
78+
let p = &x.a;
79+
drop(x.b);
80+
drop(*p);
81+
}
82+
83+
fn fu_move_after_borrow() {
84+
let x = A { a: 1, b: box 2 };
85+
let p = &x.a;
86+
let _y = A { a: 3, .. x };
87+
drop(*p);
88+
}
89+
7690
fn mut_borrow_after_mut_borrow() {
7791
let mut x = A { a: 1, b: box 2 };
7892
let p = &mut x.a;
@@ -225,6 +239,8 @@ fn main() {
225239

226240
borrow_after_move();
227241
borrow_after_fu_move();
242+
move_after_borrow();
243+
fu_move_after_borrow();
228244
mut_borrow_after_mut_borrow();
229245

230246
move_after_move();

0 commit comments

Comments
 (0)