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
commitd7de4e9affac24c6e96ae068954480bfa763908c (patch)
treee7951b4b444d0e03c47d3eb47cf95c9322427edb
parent159e27aebb940926ccf1bad0b2b12087d36ad903 (diff)
downloadrust-d7de4e9affac24c6e96ae068954480bfa763908c.tar.gz
rust-d7de4e9affac24c6e96ae068954480bfa763908c.zip
Enforce stronger guarantees for mutable borrows
Implement the stronger guarantees for mutable borrows from #12624. This
removes the ability to read from a mutably borrowed path for the
duration of the borrow, and enforces a unique access path for any
mutable borrow, for both reads and writes.

This makes mutable borrows work better with concurrent accesses from
multiple threads, and it opens the door for allowing moves out of
mutably borrowed values, as long as a new value is written before the
mutable borrow ends. This also aligns Rust more closely with academic
languages based on substructural types and separation logic.

The most common situation triggering an error after this change is a
call to a function mutably borrowing self with self.field as one of the
arguments. The workaround is to bind self.field to a temporary, but the
need for these temporaries will hopefully go away after #6268 is fixed.

Another situation that triggers an error is using the head expression of
a match in an arm that binds a variable with a mutable reference. The
use of the head expression needs to be replaced with an expression that
reconstructs it from match-bound variables.

This fixes #12624.

[breaking-change]
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs24
-rw-r--r--src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs2
-rw-r--r--src/test/compile-fail/regions-escape-loop-via-vec.rs4
3 files changed, 25 insertions, 5 deletions
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 2015572133f..2392db63019 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -438,8 +438,7 @@ impl<'a> CheckLoanCtxt<'a> {
             Some(lp) => {
                 let moved_value_use_kind = match mode {
                     euv::Copy => {
-                        // FIXME(#12624) -- If we are copying the value,
-                        // we don't care if it's borrowed.
+                        self.check_for_copy_of_frozen_path(id, span, &*lp);
                         MovedInUse
                     }
                     euv::Move(_) => {
@@ -471,6 +470,27 @@ impl<'a> CheckLoanCtxt<'a> {
         }
     }
 
+    fn check_for_copy_of_frozen_path(&self,
+                                     id: ast::NodeId,
+                                     span: Span,
+                                     copy_path: &LoanPath) {
+        match self.analyze_restrictions_on_use(id, copy_path, ty::ImmBorrow) {
+            UseOk => { }
+            UseWhileBorrowed(loan_path, loan_span) => {
+                self.bccx.span_err(
+                    span,
+                    format!("cannot use `{}` because it was mutably borrowed",
+                            self.bccx.loan_path_to_str(copy_path).as_slice())
+                    .as_slice());
+                self.bccx.span_note(
+                    loan_span,
+                    format!("borrow of `{}` occurs here",
+                            self.bccx.loan_path_to_str(&*loan_path).as_slice())
+                    .as_slice());
+            }
+        }
+    }
+
     fn check_for_move_of_borrowed_path(&self,
                                        id: ast::NodeId,
                                        span: Span,
diff --git a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs
index 393ec8b0b1b..ff029ce624c 100644
--- a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs
+++ b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs
@@ -12,7 +12,7 @@ fn a() {
     let mut v = vec!(1, 2, 3);
     let vb: &mut [int] = v.as_mut_slice();
     match vb {
-        [_a, ..tail] => {
+        [_a, ..tail] => { //~ ERROR cannot use `vb[..]` because it was mutably borrowed
             v.push(tail[0] + tail[1]); //~ ERROR cannot borrow
         }
         _ => {}
diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/compile-fail/regions-escape-loop-via-vec.rs
index 7d9629a5220..89350f16167 100644
--- a/src/test/compile-fail/regions-escape-loop-via-vec.rs
+++ b/src/test/compile-fail/regions-escape-loop-via-vec.rs
@@ -12,8 +12,8 @@
 fn broken() {
     let mut x = 3;
     let mut _y = vec!(&mut x);
-    while x < 10 {
-        let mut z = x;
+    while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed
+        let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
         _y.push(&mut z); //~ ERROR `z` does not live long enough
         x += 1; //~ ERROR cannot assign
     }