Skip to content

Commit

Permalink
librustc: Record unique immutable borrows in the restrictions table.
Browse files Browse the repository at this point in the history
This fixes borrow checking for closures. Code like this will break:

    struct Foo {
        x: int,
    }

    pub fn main() {
        let mut this = &mut Foo {
            x: 1,
        };
        let r = || {
            let p = &this.x;
            &mut this.x;
        };
        r()
    }

Change this code to not take multiple mutable references to the same value. For
example:

    struct Foo {
        x: int,
    }

    pub fn main() {
        let mut this = &mut Foo {
            x: 1,
        };
        let r = || {
            &mut this.x;
        };
        r()
    }

Closes rust-lang#16361.

[breaking-change]
  • Loading branch information
pcwalton committed Aug 12, 2014
1 parent e2273d9 commit f1799fd
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 4 deletions.
2 changes: 2 additions & 0 deletions src/librustc/middle/borrowck/gather_loans/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ impl<'a> GatherLoanCtxt<'a> {
self.bccx, borrow_span, cause,
cmt.clone(), loan_region);

debug!("guarantee_valid(): restrictions={:?}", restr);

// Create the loan record (if needed).
let loan = match restr {
restrictions::Safe => {
Expand Down
8 changes: 4 additions & 4 deletions src/librustc/middle/borrowck/gather_loans/restrictions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,7 @@ impl<'a> RestrictionsContext<'a> {
}

mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::ImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::BorrowedPtr(ty::UniqueImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) |
mc::cat_deref(cmt_base, _, mc::Implicit(ty::UniqueImmBorrow, lt)) => {
mc::cat_deref(cmt_base, _, mc::Implicit(ty::ImmBorrow, lt)) => {
// R-Deref-Imm-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
Expand All @@ -142,7 +140,9 @@ impl<'a> RestrictionsContext<'a> {
mc::cat_deref(cmt_base, _, pk) => {
match pk {
mc::BorrowedPtr(ty::MutBorrow, lt) |
mc::Implicit(ty::MutBorrow, lt) => {
mc::BorrowedPtr(ty::UniqueImmBorrow, lt) |
mc::Implicit(ty::MutBorrow, lt) |
mc::Implicit(ty::UniqueImmBorrow, lt) => {
// R-Deref-Mut-Borrowed
if !self.bccx.is_subregion_of(self.loan_region, lt) {
self.bccx.report(
Expand Down
25 changes: 25 additions & 0 deletions src/test/compile-fail/borrowck-closures-unique-imm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2014 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.

struct Foo {
x: int,
}

pub fn main() {
let mut this = &mut Foo {
x: 1,
};
let r = || {
let p = &this.x;
&mut this.x; //~ ERROR cannot borrow
};
r()
}

1 comment on commit f1799fd

@nikomatsakis
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+

Please sign in to comment.