rust/src/test/compile-fail/borrowck-call-is-borrow-issue-12224.rs
Alex Crichton 159a10da4c rustc: Tweak the borrow on closure invocations
This alters the borrow checker's requirements on invoking closures from
requiring an immutable borrow to requiring a unique immutable borrow. This means
that it is illegal to invoke a closure through a `&` pointer because there is no
guarantee that is not aliased. This does not mean that a closure is required to
be in a mutable location, but rather a location which can be proven to be
unique (often through a mutable pointer).

For example, the following code is unsound and is no longer allowed:

    type Fn<'a> = ||:'a;

    fn call(f: |Fn|) {
        f(|| {
            f(|| {})
        });
    }

    fn main() {
        call(|a| {
            a();
        });
    }

There is no replacement for this pattern. For all closures which are stored in
structures, it was previously allowed to invoke the closure through `&self` but
it now requires invocation through `&mut self`.

The standard library has a good number of violations of this new rule, but the
fixes will be separated into multiple breaking change commits.

Closes #12224

[breaking-change]
2014-04-23 10:03:43 -07:00

65 lines
1.3 KiB
Rust

// 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.
// Ensure that invoking a closure counts as a unique immutable borrow
type Fn<'a> = ||:'a;
struct Test<'a> {
f: ||: 'a
}
fn call(f: |Fn|) {
f(|| {
//~^ ERROR: closure requires unique access to `f` but it is already borrowed
f(|| {})
});
}
fn test1() {
call(|a| {
a();
});
}
fn test2(f: &||) {
(*f)(); //~ ERROR: closure invocation in a `&` reference
}
fn test3(f: &mut ||) {
(*f)();
}
fn test4(f: &Test) {
(f.f)() //~ ERROR: closure invocation in a `&` reference
}
fn test5(f: &mut Test) {
(f.f)()
}
fn test6() {
let f = || {};
(|| {
f();
})();
}
fn test7() {
fn foo(_: |g: |int|, b: int|) {}
let f = |g: |int|, b: int| {};
f(|a| { //~ ERROR: cannot borrow `f` as immutable because previous closure
foo(f); //~ ERROR: cannot move out of captured outer variable
}, 3);
}
fn main() {}