Skip to content

Commit 22f14fb

Browse files
committed
Issue #9629 -- permit freezing &mut found within an & pointer
1 parent 69186ef commit 22f14fb

File tree

7 files changed

+417
-219
lines changed

7 files changed

+417
-219
lines changed

src/librustc/middle/borrowck/doc.rs

Lines changed: 256 additions & 179 deletions
Large diffs are not rendered by default.

src/librustc/middle/borrowck/gather_loans/restrictions.rs

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,26 @@ impl<'self> RestrictionsContext<'self> {
118118
}
119119

120120
mc::cat_copied_upvar(..) | // FIXME(#2152) allow mutation of upvars
121-
mc::cat_static_item(..) |
122-
mc::cat_deref(_, _, mc::region_ptr(MutImmutable, _)) |
123-
mc::cat_deref(_, _, mc::gc_ptr(MutImmutable)) => {
121+
mc::cat_static_item(..) => {
122+
Safe
123+
}
124+
125+
mc::cat_deref(cmt_base, _, mc::region_ptr(MutImmutable, lt)) => {
124126
// R-Deref-Imm-Borrowed
127+
if !self.bccx.is_subregion_of(self.loan_region, lt) {
128+
self.bccx.report(
129+
BckError {
130+
span: self.span,
131+
cmt: cmt_base,
132+
code: err_borrowed_pointer_too_short(
133+
self.loan_region, lt, restrictions)});
134+
return Safe;
135+
}
136+
Safe
137+
}
138+
139+
mc::cat_deref(_, _, mc::gc_ptr(MutImmutable)) => {
140+
// R-Deref-Imm-Managed
125141
Safe
126142
}
127143

@@ -174,30 +190,19 @@ impl<'self> RestrictionsContext<'self> {
174190
}
175191

176192
mc::cat_deref(cmt_base, _, pk @ mc::region_ptr(MutMutable, lt)) => {
177-
// Because an `&mut` pointer does not inherit its
178-
// mutability, we can only prevent mutation or prevent
179-
// freezing if it is not aliased. Therefore, in such
180-
// cases we restrict aliasing on `cmt_base`.
181-
if restrictions != RESTR_EMPTY {
182-
if !self.bccx.is_subregion_of(self.loan_region, lt) {
183-
self.bccx.report(
184-
BckError {
185-
span: self.span,
186-
cmt: cmt_base,
187-
code: err_mut_pointer_too_short(
188-
self.loan_region, lt, restrictions)});
189-
return Safe;
190-
}
191-
192-
// R-Deref-Mut-Borrowed-1
193-
let result = self.restrict(
194-
cmt_base,
195-
RESTR_ALIAS | RESTR_MUTATE | RESTR_CLAIM);
196-
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
197-
} else {
198-
// R-Deref-Mut-Borrowed-2
199-
Safe
193+
// R-Deref-Mut-Borrowed
194+
if !self.bccx.is_subregion_of(self.loan_region, lt) {
195+
self.bccx.report(
196+
BckError {
197+
span: self.span,
198+
cmt: cmt_base,
199+
code: err_borrowed_pointer_too_short(
200+
self.loan_region, lt, restrictions)});
201+
return Safe;
200202
}
203+
204+
let result = self.restrict(cmt_base, restrictions);
205+
self.extend(result, cmt.mutbl, LpDeref(pk), restrictions)
201206
}
202207

203208
mc::cat_deref(_, _, mc::unsafe_ptr(..)) => {

src/librustc/middle/borrowck/mod.rs

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,8 @@ pub enum bckerr_code {
444444
err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
445445
err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
446446
err_freeze_aliasable_const,
447-
err_mut_pointer_too_short(ty::Region, ty::Region, RestrictionSet), // loan, ptr
447+
err_borrowed_pointer_too_short(
448+
ty::Region, ty::Region, RestrictionSet), // loan, ptr
448449
}
449450

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

679-
let tag = if r.intersects(RESTR_ALIAS) {
680-
"its contents are unique"
681-
} else {
682-
"its contents are not otherwise mutable"
683-
};
684-
685-
format!("lifetime of {} is too short to guarantee {} \
686-
so they can be safely reborrowed",
687-
descr, tag)
680+
format!("lifetime of {} is too short to guarantee \
681+
its contents can be safely reborrowed",
682+
descr)
688683
}
689684
}
690685
}
@@ -761,10 +756,10 @@ impl BorrowckCtxt {
761756
"");
762757
}
763758

764-
err_mut_pointer_too_short(loan_scope, ptr_scope, _) => {
759+
err_borrowed_pointer_too_short(loan_scope, ptr_scope, _) => {
765760
let descr = match opt_loan_path(err.cmt) {
766761
Some(lp) => format!("`{}`", self.loan_path_to_str(lp)),
767-
None => ~"`&mut` pointer"
762+
None => self.cmt_to_str(err.cmt),
768763
};
769764
note_and_explain_region(
770765
self.tcx,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that attempt to freeze an `&mut` pointer while referent is
12+
// claimed yields an error.
13+
//
14+
// Example from src/middle/borrowck/doc.rs
15+
16+
use std::util::swap;
17+
18+
fn foo<'a>(mut t0: &'a mut int,
19+
mut t1: &'a mut int) {
20+
let p: &mut int = &mut *t0; // Claims `*t0`
21+
let mut t2 = &t0; //~ ERROR cannot borrow `t0`
22+
let q: &int = &*t2; // Freezes `*t0` but not through `*p`
23+
*p += 1; // violates type of `*q`
24+
}
25+
26+
fn main() {
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that attempt to mutably borrow `&mut` pointer while pointee is
12+
// borrowed yields an error.
13+
//
14+
// Example from src/middle/borrowck/doc.rs
15+
16+
use std::util::swap;
17+
18+
fn foo<'a>(mut t0: &'a mut int,
19+
mut t1: &'a mut int) {
20+
let p: &int = &*t0; // Freezes `*t0`
21+
let mut t2 = &mut t0; //~ ERROR cannot borrow `t0`
22+
**t2 += 1; // Mutates `*t0`
23+
}
24+
25+
fn bar<'a>(mut t0: &'a mut int,
26+
mut t1: &'a mut int) {
27+
let p: &mut int = &mut *t0; // Claims `*t0`
28+
let mut t2 = &mut t0; //~ ERROR cannot borrow `t0`
29+
**t2 += 1; // Mutates `*t0` but not through `*p`
30+
}
31+
32+
fn main() {
33+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that freezing an `&mut` pointer while referent is
12+
// frozen is legal.
13+
//
14+
// Example from src/middle/borrowck/doc.rs
15+
16+
fn foo<'a>(mut t0: &'a mut int,
17+
mut t1: &'a mut int) {
18+
let p: &int = &*t0; // Freezes `*t0`
19+
let mut t2 = &t0;
20+
let q: &int = &**t2; // Freezes `*t0`, but that's ok...
21+
let r: &int = &*t0; // ...after all, could do same thing directly.
22+
}
23+
24+
fn main() {
25+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test that a `&mut` inside of an `&` is freezable.
12+
13+
struct MutSlice<'a, T> {
14+
data: &'a mut [T]
15+
}
16+
17+
fn get<'a, T>(ms: &'a MutSlice<'a, T>, index: uint) -> &'a T {
18+
&ms.data[index]
19+
}
20+
21+
fn main() {
22+
let mut data = [1, 2, 3];
23+
{
24+
let slice = MutSlice { data: data };
25+
slice.data[0] += 4;
26+
let index0 = get(&slice, 0);
27+
let index1 = get(&slice, 1);
28+
let index2 = get(&slice, 2);
29+
assert_eq!(*index0, 5);
30+
assert_eq!(*index1, 2);
31+
assert_eq!(*index2, 3);
32+
}
33+
assert_eq!(data[0], 1);
34+
assert_eq!(data[1], 2);
35+
assert_eq!(data[2], 3);
36+
}

0 commit comments

Comments
 (0)