Skip to content

Commit

Permalink
auto merge of #10787 : nikomatsakis/rust/issue-9629-freeze-andmut, r=…
Browse files Browse the repository at this point in the history
…pnkfelix

See #9629 for details.

r? @pnkfelix
  • Loading branch information
bors committed Dec 8, 2013
2 parents a6310f6 + 22f14fb commit cef2842
Show file tree
Hide file tree
Showing 7 changed files with 417 additions and 219 deletions.
435 changes: 256 additions & 179 deletions src/librustc/middle/borrowck/doc.rs

Large diffs are not rendered by default.

57 changes: 31 additions & 26 deletions src/librustc/middle/borrowck/gather_loans/restrictions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,26 @@ impl<'self> RestrictionsContext<'self> {
}

mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars
mc::cat_static_item(..) |
mc::cat_deref(_, _, mc::region_ptr(MutImmutable, _)) |
mc::cat_deref(_, _, mc::gc_ptr(MutImmutable)) => {
mc::cat_static_item(..) => {
Safe
}

mc::cat_deref(cmt_base, _, mc::region_ptr(MutImmutable, lt)) => {
// R-Deref-Imm-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
BckError {
span: self.span,
cmt: cmt_base,
code: err_borrowed_pointer_too_short(
self.loan_region, lt, restrictions)});
return Safe;
}
Safe
}

mc::cat_deref(_, _, mc::gc_ptr(MutImmutable)) => {
// R-Deref-Imm-Managed
Safe
}

Expand Down Expand Up @@ -170,30 +186,19 @@ impl<'self> RestrictionsContext<'self> {
}

mc::cat_deref(cmt_base, _, pk @ mc::region_ptr(MutMutable, lt)) => {
// Because an `&mut` pointer does not inherit its
// mutability, we can only prevent mutation or prevent
// freezing if it is not aliased. Therefore, in such
// cases we restrict aliasing on `cmt_base`.
if restrictions != RESTR_EMPTY {
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
BckError {
span: self.span,
cmt: cmt_base,
code: err_mut_pointer_too_short(
self.loan_region, lt, restrictions)});
return Safe;
}

// R-Deref-Mut-Borrowed-1
let result = self.restrict(
cmt_base,
RESTR_ALIAS | RESTR_MUTATE | RESTR_CLAIM);
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
} else {
// R-Deref-Mut-Borrowed-2
Safe
// R-Deref-Mut-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
BckError {
span: self.span,
cmt: cmt_base,
code: err_borrowed_pointer_too_short(
self.loan_region, lt, restrictions)});
return Safe;
}

let result = self.restrict(cmt_base, restrictions);
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
}

mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {
Expand Down
23 changes: 9 additions & 14 deletions src/librustc/middle/borrowck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,8 @@ pub enum bckerr_code {
err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
err_freeze_aliasable_const,
err_mut_pointer_too_short(ty::Region, ty::Region, RestrictionSet), // loan, ptr
err_borrowed_pointer_too_short(
ty::Region, ty::Region, RestrictionSet), // loan, ptr
}

// Combination of an error code and the categorization of the expression
Expand Down Expand Up @@ -670,21 +671,15 @@ impl BorrowckCtxt {
// supposed to be going away.
format!("unsafe borrow of aliasable, const value")
}
err_mut_pointer_too_short(_, _, r) => {
err_borrowed_pointer_too_short(_, _, r) => {
let descr = match opt_loan_path(err.cmt) {
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
None => ~"`&mut` pointer"
None => self.cmt_to_str(err.cmt),
};

let tag = if r.intersects(RESTR_ALIAS) {
"its contents are unique"
} else {
"its contents are not otherwise mutable"
};

format!("lifetime of {} is too short to guarantee {} \
so they can be safely reborrowed",
descr, tag)
format!("lifetime of {} is too short to guarantee \
its contents can be safely reborrowed",
descr)
}
}
}
Expand Down Expand Up @@ -761,10 +756,10 @@ impl BorrowckCtxt {
"");
}

err_mut_pointer_too_short(loan_scope, ptr_scope, _) => {
err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
let descr = match opt_loan_path(err.cmt) {
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
None => ~"`&mut` pointer"
None => self.cmt_to_str(err.cmt),
};
note_and_explain_region(
self.tcx,
Expand Down
27 changes: 27 additions & 0 deletions src/test/compile-fail/borrowck-borrow-of-mut-base-ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2013 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 attempt to freeze an `&mut` pointer while referent is
// claimed yields an error.
//
// Example from src/middle/borrowck/doc.rs

use std::util::swap;

fn foo<'a>(mut t0: &'a mut int,
mut t1: &'a mut int) {
let p: &mut int = &mut *t0; // Claims `*t0`
let mut t2 = &t0; //~ ERROR cannot borrow `t0`
let q: &int = &*t2; // Freezes `*t0` but not through `*p`
*p += 1; // violates type of `*q`
}

fn main() {
}
33 changes: 33 additions & 0 deletions src/test/compile-fail/borrowck-mut-borrow-of-mut-base-ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2013 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 attempt to mutably borrow `&mut` pointer while pointee is
// borrowed yields an error.
//
// Example from src/middle/borrowck/doc.rs

use std::util::swap;

fn foo<'a>(mut t0: &'a mut int,
mut t1: &'a mut int) {
let p: &int = &*t0; // Freezes `*t0`
let mut t2 = &mut t0; //~ ERROR cannot borrow `t0`
**t2 += 1; // Mutates `*t0`
}

fn bar<'a>(mut t0: &'a mut int,
mut t1: &'a mut int) {
let p: &mut int = &mut *t0; // Claims `*t0`
let mut t2 = &mut t0; //~ ERROR cannot borrow `t0`
**t2 += 1; // Mutates `*t0` but not through `*p`
}

fn main() {
}
25 changes: 25 additions & 0 deletions src/test/run-pass/borrowck-borrow-of-mut-base-ptr-safe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2013 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 freezing an `&mut` pointer while referent is
// frozen is legal.
//
// Example from src/middle/borrowck/doc.rs

fn foo<'a>(mut t0: &'a mut int,
mut t1: &'a mut int) {
let p: &int = &*t0; // Freezes `*t0`
let mut t2 = &t0;
let q: &int = &**t2; // Freezes `*t0`, but that's ok...
let r: &int = &*t0; // ...after all, could do same thing directly.
}

fn main() {
}
36 changes: 36 additions & 0 deletions src/test/run-pass/borrowck-freeze-frozen-mut.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2012-2013 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 a `&mut` inside of an `&` is freezable.

struct MutSlice<'a, T> {
data: &'a mut [T]
}

fn get<'a, T>(ms: &'a MutSlice<'a, T>, index: uint) -> &'a T {
&ms.data[index]
}

fn main() {
let mut data = [1, 2, 3];
{
let slice = MutSlice { data: data };
slice.data[0] += 4;
let index0 = get(&slice, 0);
let index1 = get(&slice, 1);
let index2 = get(&slice, 2);
assert_eq!(*index0, 5);
assert_eq!(*index1, 2);
assert_eq!(*index2, 3);
}
assert_eq!(data[0], 1);
assert_eq!(data[1], 2);
assert_eq!(data[2], 3);
}

0 comments on commit cef2842

Please sign in to comment.