about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCameron Zwarich <zwarich@mozilla.com>2014-06-13 20:48:09 -0700
committerCameron Zwarich <zwarich@mozilla.com>2014-06-13 20:48:09 -0700
commit45a1b977643456ceacfc81183e2d5743f7c61ce9 (patch)
tree94e71110ec115abe06df393c2b1000c3f9da4b92
parent8c0e1ce6c9410f4d928923ee93e7b5a4674ae2ed (diff)
downloadrust-45a1b977643456ceacfc81183e2d5743f7c61ce9.tar.gz
rust-45a1b977643456ceacfc81183e2d5743f7c61ce9.zip
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.
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs48
-rw-r--r--src/test/compile-fail/borrowck-field-sensitivity.rs17
-rw-r--r--src/test/run-pass/borrowck-field-sensitivity.rs16
3 files changed, 51 insertions, 30 deletions
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 45d15a9afac..ab004e4a3e9 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -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;
     }
 }
diff --git a/src/test/compile-fail/borrowck-field-sensitivity.rs b/src/test/compile-fail/borrowck-field-sensitivity.rs
index 2fa9067af54..72042b8373d 100644
--- a/src/test/compile-fail/borrowck-field-sensitivity.rs
+++ b/src/test/compile-fail/borrowck-field-sensitivity.rs
@@ -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();
diff --git a/src/test/run-pass/borrowck-field-sensitivity.rs b/src/test/run-pass/borrowck-field-sensitivity.rs
index a297300daf1..33be47e504b 100644
--- a/src/test/run-pass/borrowck-field-sensitivity.rs
+++ b/src/test/run-pass/borrowck-field-sensitivity.rs
@@ -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();