From 6b23d20452ef7c2d2eb79baf074bcda04fad9a66 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Aug 2013 11:39:17 -0400 Subject: [PATCH] Prohibit assignment to `&mut` pointers that are found in frozen or borrowed locations. Fixes #8625. --- src/librustc/middle/borrowck/check_loans.rs | 15 +++++++-- ...rrowck-assign-to-andmut-in-borrowed-loc.rs | 31 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/test/compile-fail/borrowck-assign-to-andmut-in-borrowed-loc.rs diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 620a1e9efe33..a2529261aafc 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 000000000000..dcef74b6c2bc --- /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 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 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; + } +}