about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-08-21 11:39:17 -0400
committerNiko Matsakis <niko@alum.mit.edu>2013-08-21 12:02:21 -0400
commit6b23d20452ef7c2d2eb79baf074bcda04fad9a66 (patch)
tree761f1d4e9cf2ad157af0afa4deb77523e748a602
parent0ea2a20397497a33af4d5d602e51cc50a8e15b4f (diff)
downloadrust-6b23d20452ef7c2d2eb79baf074bcda04fad9a66.tar.gz
rust-6b23d20452ef7c2d2eb79baf074bcda04fad9a66.zip
Prohibit assignment to `&mut` pointers that are found in frozen or borrowed locations.
Fixes #8625.
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs15
-rw-r--r--src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs31
2 files changed, 43 insertions, 3 deletions
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index 620a1e9efe3..a2529261aaf 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -496,6 +496,12 @@ impl<'self> CheckLoanCtxt<'self> {
             // path, and check that the super path was not lent out as
             // mutable or immutable (a const loan is ok).
             //
+            // Mutability of a path can be dependent on the super path
+            // in two ways. First, it might be inherited mutability.
+            // Second, the pointee of an `&mut` pointer can only be
+            // mutated if it is found in an unaliased location, so we
+            // have to check that the owner location is not borrowed.
+            //
             // Note that we are *not* checking for any and all
             // restrictions.  We are only interested in the pointers
             // that the user created, whereas we add restrictions for
@@ -513,9 +519,12 @@ impl<'self> CheckLoanCtxt<'self> {
             let mut loan_path = loan_path;
             loop {
                 match *loan_path {
-                    // Peel back one layer if `loan_path` has
-                    // inherited mutability
-                    LpExtend(lp_base, mc::McInherited, _) => {
+                    // Peel back one layer if, for `loan_path` to be
+                    // mutable, `lp_base` must be mutable. This occurs
+                    // with inherited mutability and with `&mut`
+                    // pointers.
+                    LpExtend(lp_base, mc::McInherited, _) |
+                    LpExtend(lp_base, _, LpDeref(mc::region_ptr(ast::m_mutbl, _))) => {
                         loan_path = lp_base;
                     }
 
diff --git a/src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs b/src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs
new file mode 100644
index 00000000000..dcef74b6c2b
--- /dev/null
+++ b/src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs
@@ -0,0 +1,31 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that assignments to an `&mut` pointer which is found in a
+// borrowed (but otherwise non-aliasable) location is illegal.
+
+struct S<'self> {
+    pointer: &'self mut int
+}
+
+fn copy_borrowed_ptr<'a>(p: &'a mut S<'a>) -> S<'a> {
+    S { pointer: &mut *p.pointer }
+}
+
+fn main() {
+    let mut x = 1;
+
+    {
+        let mut y = S { pointer: &mut x };
+        let z = copy_borrowed_ptr(&mut y);
+        *y.pointer += 1; //~ ERROR cannot assign
+        *z.pointer += 1;
+    }
+}