Skip to content

Commit 22a14dd

Browse files
committed
Enforce a stricter notion of purity when borrowing. Fixes #3162.
1 parent be2e4ef commit 22a14dd

File tree

3 files changed

+48
-2
lines changed

3 files changed

+48
-2
lines changed

src/rustc/middle/borrowck/check_loans.rs

+24-2
Original file line numberDiff line numberDiff line change
@@ -322,10 +322,32 @@ impl check_loan_ctxt {
322322
// is not visible from the outside
323323
match self.purity(ex.id) {
324324
none => (),
325-
some(pc) => {
326-
if cmt.lp.is_none() {
325+
some(pc @ pc_cmt(_)) => {
326+
// Subtle: Issue #3162. If we are enforcing purity
327+
// because there is a reference to aliasable, mutable data
328+
// that we require to be immutable, we can't allow writes
329+
// even to data owned by the current stack frame. This is
330+
// because that aliasable data might have been located on
331+
// the current stack frame, we don't know.
332+
match cmt.lp {
333+
some(@lp_local(*)) | some(@lp_arg(*)) => {
334+
// it's ok to mutate a local variable, as it is either
335+
// lent our or not. The problem arises when you have
336+
// some subcomponent that might have been lent out
337+
// through an alias on the condition that you ensure
338+
// purity.
339+
}
340+
none | some(@lp_comp(*)) | some(@lp_deref(*)) => {
327341
self.report_purity_error(
328342
pc, ex.span, at.ing_form(self.bccx.cmt_to_str(cmt)));
343+
}
344+
}
345+
}
346+
some(pc_pure_fn) => {
347+
if cmt.lp.is_none() {
348+
self.report_purity_error(
349+
pc_pure_fn, ex.span,
350+
at.ing_form(self.bccx.cmt_to_str(cmt)));
329351
}
330352
}
331353
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn each<T>(x: &[T], op: fn(elem: &T) -> bool) {
2+
uint::range(0, x.len(), |i| op(&x[i]));
3+
}
4+
5+
fn main() {
6+
let x = [{mut a: 0}];
7+
for each(x) |y| {
8+
let z = &y.a; //~ ERROR illegal borrow unless pure
9+
x[0].a = 10; //~ NOTE impure due to assigning to mutable field
10+
log(error, z);
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
fn each<T>(x: &[T], op: fn(elem: &T) -> bool) {
2+
uint::range(0, x.len(), |i| op(&x[i]));
3+
}
4+
5+
fn main() {
6+
let x = ~[{mut a: 0}];
7+
for each(x) |y| {
8+
let z = &y.a; //~ ERROR illegal borrow unless pure
9+
x[0].a = 10; //~ NOTE impure due to assigning to mutable field
10+
log(error, z);
11+
}
12+
}

0 commit comments

Comments
 (0)