about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2013-08-27 15:44:55 -0400
committerNiko Matsakis <niko@alum.mit.edu>2013-08-27 15:45:19 -0400
commit35a41775505b9c7bb7b5ad9bfe1b7b7a6afb27b8 (patch)
tree73cb65a1c09e9edf43055c4b5443173f869b8f08
parent6b23d20452ef7c2d2eb79baf074bcda04fad9a66 (diff)
downloadrust-35a41775505b9c7bb7b5ad9bfe1b7b7a6afb27b8.tar.gz
rust-35a41775505b9c7bb7b5ad9bfe1b7b7a6afb27b8.zip
Extend aliasability check to uncover `& &mut &mut` and the like
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs56
-rw-r--r--src/librustc/middle/mem_categorization.rs19
-rw-r--r--src/test/compile-fail/borrowck-assign-to-andmut-in-aliasable-loc.rs30
3 files changed, 87 insertions, 18 deletions
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index a2529261aaf..70a71f8ad9f 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -391,15 +391,7 @@ impl<'self> CheckLoanCtxt<'self> {
                 mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => {
                     // Statically prohibit writes to `&mut` when aliasable
 
-                    match b.freely_aliasable() {
-                        None => {}
-                        Some(cause) => {
-                            this.bccx.report_aliasability_violation(
-                                expr.span,
-                                MutabilityViolation,
-                                cause);
-                        }
-                    }
+                    check_for_aliasability_violation(this, expr, b);
                 }
 
                 mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => {
@@ -419,6 +411,52 @@ impl<'self> CheckLoanCtxt<'self> {
             return true; // no errors reported
         }
 
+        fn check_for_aliasability_violation(this: &CheckLoanCtxt,
+                                            expr: @ast::expr,
+                                            cmt: mc::cmt) -> bool {
+            let mut cmt = cmt;
+
+            loop {
+                match cmt.cat {
+                    mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) |
+                    mc::cat_downcast(b) |
+                    mc::cat_stack_upvar(b) |
+                    mc::cat_deref(b, _, mc::uniq_ptr) |
+                    mc::cat_interior(b, _) |
+                    mc::cat_discr(b, _) => {
+                        // Aliasability depends on base cmt
+                        cmt = b;
+                    }
+
+                    mc::cat_copied_upvar(_) |
+                    mc::cat_rvalue(*) |
+                    mc::cat_local(*) |
+                    mc::cat_arg(_) |
+                    mc::cat_self(*) |
+                    mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
+                    mc::cat_static_item(*) |
+                    mc::cat_implicit_self(*) |
+                    mc::cat_deref(_, _, mc::gc_ptr(_)) |
+                    mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
+                    mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) => {
+                        // Aliasability is independent of base cmt
+                        match cmt.freely_aliasable() {
+                            None => {
+                                return true;
+                            }
+                            Some(cause) => {
+                                this.bccx.report_aliasability_violation(
+                                    expr.span,
+                                    MutabilityViolation,
+                                    cause);
+                                return false;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
         fn check_for_assignment_to_restricted_or_frozen_location(
             this: &CheckLoanCtxt,
             expr: @ast::expr,
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 2cd2d94b9da..c38677adfbf 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -1146,9 +1146,10 @@ impl cmt_ {
     }
 
     pub fn freely_aliasable(&self) -> Option<AliasableReason> {
-        //! True if this lvalue resides in an area that is
-        //! freely aliasable, meaning that rustc cannot track
-        //! the alias//es with precision.
+        /*!
+         * Returns `Some(_)` if this lvalue represents a freely aliasable
+         * pointer type.
+         */
 
         // Maybe non-obvious: copied upvars can only be considered
         // non-aliasable in once closures, since any other kind can be
@@ -1180,12 +1181,12 @@ impl cmt_ {
                 Some(AliasableBorrowed(m))
             }
 
-            cat_downcast(b) |
-            cat_stack_upvar(b) |
-            cat_deref(b, _, uniq_ptr) |
-            cat_interior(b, _) |
-            cat_discr(b, _) => {
-                b.freely_aliasable()
+            cat_downcast(*) |
+            cat_stack_upvar(*) |
+            cat_deref(_, _, uniq_ptr) |
+            cat_interior(*) |
+            cat_discr(*) => {
+                None
             }
         }
     }
diff --git a/src/test/compile-fail/borrowck-assign-to-andmut-in-aliasable-loc.rs b/src/test/compile-fail/borrowck-assign-to-andmut-in-aliasable-loc.rs
new file mode 100644
index 00000000000..e4a23e74a12
--- /dev/null
+++ b/src/test/compile-fail/borrowck-assign-to-andmut-in-aliasable-loc.rs
@@ -0,0 +1,30 @@
+// 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 a(s: &S) {
+    *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn b(s: &mut S) {
+    *s.pointer += 1;
+}
+
+fn c(s: & &mut S) {
+    *s.pointer += 1; //~ ERROR cannot assign
+}
+
+fn main() {}