diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index a2529261aafc35b2480355fae226bd7c0a3f2de1..70a71f8ad9f3e4b23efd27f7b4d38d2c1c547d5b 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -391,15 +391,7 @@ fn check_for_aliasable_mutable_writes(this: &CheckLoanCtxt, 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 @@ fn check_for_aliasable_mutable_writes(this: &CheckLoanCtxt, 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 2cd2d94b9daf8fdf6429024861a5e2886460b95e..c38677adfbfa5b34488ae97d8f8b1725417354b2 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1146,9 +1146,10 @@ pub fn is_freely_aliasable(&self) -> bool { } pub fn freely_aliasable(&self) -> Option { - //! 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 @@ pub fn freely_aliasable(&self) -> Option { 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 0000000000000000000000000000000000000000..e4a23e74a12f2e2ada202eabff1d1828103eecc8 --- /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 or the MIT license +// , 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() {}