Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #9629 -- permit freezing &mut found within an & pointer #10787

Merged
merged 5 commits into from
Dec 11, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
459 changes: 282 additions & 177 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 @@ -118,10 +118,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 @@ -174,30 +190,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(..) => {
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
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// 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 attempt to reborrow an `&mut` pointer in an aliasable
// location yields an error.
//
Expand All @@ -7,7 +17,7 @@ use std::util::swap;

fn foo(t0: & &mut int) {
let t1 = t0;
let p: &int = &**t0; //~ ERROR cannot borrow an `&mut` in a `&` pointer
let p: &int = &**t0;
**t1 = 22; //~ ERROR cannot assign
}

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.
}

pub 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]
}

pub 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], 5);
assert_eq!(data[1], 2);
assert_eq!(data[2], 3);
}