diff --git a/src/rustc/middle/borrowck/check_loans.rs b/src/rustc/middle/borrowck/check_loans.rs index 4c596a343544f779df87d7780f98c58ecadc37e7..301c78aa109449780413319f582ce2c7a05bfb73 100644 --- a/src/rustc/middle/borrowck/check_loans.rs +++ b/src/rustc/middle/borrowck/check_loans.rs @@ -322,10 +322,32 @@ fn check_assignment(at: assignment_type, ex: @ast::expr) { // is not visible from the outside match self.purity(ex.id) { none => (), - some(pc) => { - if cmt.lp.is_none() { + some(pc @ pc_cmt(_)) => { + // Subtle: Issue #3162. If we are enforcing purity + // because there is a reference to aliasable, mutable data + // that we require to be immutable, we can't allow writes + // even to data owned by the current stack frame. This is + // because that aliasable data might have been located on + // the current stack frame, we don't know. + match cmt.lp { + some(@lp_local(*)) | some(@lp_arg(*)) => { + // it's ok to mutate a local variable, as it is either + // lent our or not. The problem arises when you have + // some subcomponent that might have been lent out + // through an alias on the condition that you ensure + // purity. + } + none | some(@lp_comp(*)) | some(@lp_deref(*)) => { self.report_purity_error( pc, ex.span, at.ing_form(self.bccx.cmt_to_str(cmt))); + } + } + } + some(pc_pure_fn) => { + if cmt.lp.is_none() { + self.report_purity_error( + pc_pure_fn, ex.span, + at.ing_form(self.bccx.cmt_to_str(cmt))); } } } diff --git a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-b.rs b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-b.rs new file mode 100644 index 0000000000000000000000000000000000000000..3c0a53130b1d61e48a38bd36158ac085098c78b4 --- /dev/null +++ b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-b.rs @@ -0,0 +1,12 @@ +fn each(x: &[T], op: fn(elem: &T) -> bool) { + uint::range(0, x.len(), |i| op(&x[i])); +} + +fn main() { + let x = [{mut a: 0}]; + for each(x) |y| { + let z = &y.a; //~ ERROR illegal borrow unless pure + x[0].a = 10; //~ NOTE impure due to assigning to mutable field + log(error, z); + } +} diff --git a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162.rs b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162.rs new file mode 100644 index 0000000000000000000000000000000000000000..fa31ca4340be010f689cb954ccffe0fc1f457773 --- /dev/null +++ b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162.rs @@ -0,0 +1,12 @@ +fn each(x: &[T], op: fn(elem: &T) -> bool) { + uint::range(0, x.len(), |i| op(&x[i])); +} + +fn main() { + let x = ~[{mut a: 0}]; + for each(x) |y| { + let z = &y.a; //~ ERROR illegal borrow unless pure + x[0].a = 10; //~ NOTE impure due to assigning to mutable field + log(error, z); + } +}