Auto merge of #47144 - estebank:moved-closure-arg, r=nikomatsakis

Custom error when moving arg outside of its closure

When given the following code:

```rust
fn give_any<F: for<'r> FnOnce(&'r ())>(f: F) {
    f(&());
}

fn main() {
    let mut x = None;
    give_any(|y| x = Some(y));
}
```

provide a custom error:

```
error: borrowed data cannot be moved outside of its closure
 --> file.rs:7:27
  |
6 |     let mut x = None;
  |         ----- borrowed data cannot be moved into here...
7 |     give_any(|y| x = Some(y));
  |              ---          ^ cannot be moved outside of its closure
  |              |
  |              ...because it cannot outlive this closure
```

instead of the generic lifetime error:

```
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
 --> file.rs:7:27
  |
7 |     give_any(|y| x = Some(y));
  |                           ^
  |
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 7:14...
 --> file.rs:7:14
  |
7 |     give_any(|y| x = Some(y));
  |              ^^^^^^^^^^^^^^^
note: ...so that expression is assignable (expected &(), found &())
 --> file.rs:7:27
  |
7 |     give_any(|y| x = Some(y));
  |                           ^
note: but, the lifetime must be valid for the block suffix following statement 0 at 6:5...
 --> file.rs:6:5
  |
6 | /     let mut x = None;
7 | |     give_any(|y| x = Some(y));
8 | | }
  | |_^
note: ...so that variable is valid at time of its declaration
 --> file.rs:6:9
  |
6 |     let mut x = None;
  |         ^^^^^
```

Fix #45983.
This commit is contained in:
bors 2018-01-22 05:30:37 +00:00
commit bc072ed0ca
18 changed files with 352 additions and 21 deletions

View file

@ -0,0 +1,19 @@
// Copyright 2018 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.
fn give_any<F: for<'r> FnOnce(&'r ())>(f: F) {
f(&());
}
fn main() {
let x = None;
give_any(|y| x = Some(y));
//~^ ERROR borrowed data cannot be stored outside of its closure
}

View file

@ -0,0 +1,12 @@
error: borrowed data cannot be stored outside of its closure
--> $DIR/issue-45983.rs:17:27
|
16 | let x = None;
| - borrowed data cannot be stored into here...
17 | give_any(|y| x = Some(y));
| --- ^ cannot be stored outside of its closure
| |
| ...because it cannot outlive this closure
error: aborting due to previous error

View file

@ -0,0 +1,54 @@
// Copyright 2013 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.
pub struct CrateId {
local_path: String,
junk: String
}
impl CrateId {
fn new(s: &str) -> CrateId {
CrateId {
local_path: s.to_string(),
junk: "wutevs".to_string()
}
}
}
pub fn remove_package_from_database() {
let mut lines_to_use: Vec<&CrateId> = Vec::new();
//~^ NOTE cannot infer an appropriate lifetime
let push_id = |installed_id: &CrateId| {
//~^ NOTE borrowed data cannot outlive this closure
//~| NOTE ...so that variable is valid at time of its declaration
lines_to_use.push(installed_id);
//~^ ERROR borrowed data cannot be stored outside of its closure
//~| NOTE cannot be stored outside of its closure
};
list_database(push_id);
for l in &lines_to_use {
println!("{}", l.local_path);
}
}
pub fn list_database<F>(mut f: F) where F: FnMut(&CrateId) {
let stuff = ["foo", "bar"];
for l in &stuff {
f(&CrateId::new(*l));
}
}
pub fn main() {
remove_package_from_database();
}

View file

@ -0,0 +1,16 @@
error: borrowed data cannot be stored outside of its closure
--> $DIR/issue-7573.rs:32:27
|
27 | let mut lines_to_use: Vec<&CrateId> = Vec::new();
| - cannot infer an appropriate lifetime...
28 | //~^ NOTE cannot infer an appropriate lifetime
29 | let push_id = |installed_id: &CrateId| {
| ------- ------------------------ borrowed data cannot outlive this closure
| |
| ...so that variable is valid at time of its declaration
...
32 | lines_to_use.push(installed_id);
| ^^^^^^^^^^^^ cannot be stored outside of its closure
error: aborting due to previous error

View file

@ -0,0 +1,20 @@
// Copyright 2012 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.
fn with_int<F>(f: F) where F: FnOnce(&isize) {
let x = 3;
f(&x);
}
fn main() {
let mut x = None;
with_int(|y| x = Some(y));
//~^ ERROR borrowed data cannot be stored outside of its closure
}

View file

@ -0,0 +1,12 @@
error: borrowed data cannot be stored outside of its closure
--> $DIR/regions-escape-bound-fn-2.rs:18:27
|
17 | let mut x = None;
| ----- borrowed data cannot be stored into here...
18 | with_int(|y| x = Some(y));
| --- ^ cannot be stored outside of its closure
| |
| ...because it cannot outlive this closure
error: aborting due to previous error

View file

@ -0,0 +1,20 @@
// Copyright 2012 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.
fn with_int<F>(f: F) where F: FnOnce(&isize) {
let x = 3;
f(&x);
}
fn main() {
let mut x: Option<&isize> = None;
with_int(|y| x = Some(y));
//~^ ERROR borrowed data cannot be stored outside of its closure
}

View file

@ -0,0 +1,12 @@
error: borrowed data cannot be stored outside of its closure
--> $DIR/regions-escape-bound-fn.rs:18:27
|
17 | let mut x: Option<&isize> = None;
| ----- borrowed data cannot be stored into here...
18 | with_int(|y| x = Some(y));
| --- ^ cannot be stored outside of its closure
| |
| ...because it cannot outlive this closure
error: aborting due to previous error

View file

@ -0,0 +1,18 @@
// Copyright 2012 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.
fn with_int(f: &mut FnMut(&isize)) {
}
fn main() {
let mut x: Option<&isize> = None;
with_int(&mut |y| x = Some(y));
//~^ ERROR borrowed data cannot be stored outside of its closure
}

View file

@ -0,0 +1,12 @@
error: borrowed data cannot be stored outside of its closure
--> $DIR/regions-escape-unboxed-closure.rs:16:32
|
15 | let mut x: Option<&isize> = None;
| ----- borrowed data cannot be stored into here...
16 | with_int(&mut |y| x = Some(y));
| --- ^ cannot be stored outside of its closure
| |
| ...because it cannot outlive this closure
error: aborting due to previous error

View file

@ -0,0 +1,80 @@
// Copyright 2016 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.
#![allow(warnings)]
fn closure_expecting_bound<F>(_: F)
where F: FnOnce(&u32)
{
}
fn closure_expecting_free<'a, F>(_: F)
where F: FnOnce(&'a u32)
{
}
fn expect_bound_supply_nothing() {
// Because `x` is inferred to have a bound region, we cannot allow
// it to escape into `f`:
let mut f: Option<&u32> = None;
closure_expecting_bound(|x| {
f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
});
}
fn expect_bound_supply_bound() {
// Because `x` is inferred to have a bound region, we cannot allow
// it to escape into `f`, even with an explicit type annotation on
// closure:
let mut f: Option<&u32> = None;
closure_expecting_bound(|x: &u32| {
f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
});
}
fn expect_bound_supply_named<'x>() {
let mut f: Option<&u32> = None;
// Here we give a type annotation that `x` should be free. We get
// an error because of that.
closure_expecting_bound(|x: &'x u32| {
//~^ ERROR mismatched types
//~| ERROR mismatched types
// And we still cannot let `x` escape into `f`.
f = Some(x);
//~^ ERROR borrowed data cannot be stored outside of its closure
});
}
fn expect_free_supply_nothing() {
let mut f: Option<&u32> = None;
closure_expecting_free(|x| f = Some(x)); // OK
}
fn expect_free_supply_bound() {
let mut f: Option<&u32> = None;
// Here, even though the annotation `&u32` could be seen as being
// bound in the closure, we permit it to be defined as a free
// region (which is inferred to something in the fn body).
closure_expecting_free(|x: &u32| f = Some(x)); // OK
}
fn expect_free_supply_named<'x>() {
let mut f: Option<&u32> = None;
// Here, even though the annotation `&u32` could be seen as being
// bound in the closure, we permit it to be defined as a free
// region (which is inferred to something in the fn body).
closure_expecting_free(|x: &'x u32| f = Some(x)); // OK
}
fn main() { }

View file

@ -0,0 +1,98 @@
error: borrowed data cannot be stored outside of its closure
--> $DIR/expect-region-supply-region.rs:28:18
|
26 | let mut f: Option<&u32> = None;
| ----- borrowed data cannot be stored into here...
27 | closure_expecting_bound(|x| {
| --- ...because it cannot outlive this closure
28 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
| ^ cannot be stored outside of its closure
error: borrowed data cannot be stored outside of its closure
--> $DIR/expect-region-supply-region.rs:38:18
|
36 | let mut f: Option<&u32> = None;
| ----- borrowed data cannot be stored into here...
37 | closure_expecting_bound(|x: &u32| {
| --------- ...because it cannot outlive this closure
38 | f = Some(x); //~ ERROR borrowed data cannot be stored outside of its closure
| ^ cannot be stored outside of its closure
error[E0308]: mismatched types
--> $DIR/expect-region-supply-region.rs:47:33
|
47 | closure_expecting_bound(|x: &'x u32| {
| ^^^^^^^ lifetime mismatch
|
= note: expected type `&u32`
found type `&'x u32`
note: the anonymous lifetime #2 defined on the body at 47:29...
--> $DIR/expect-region-supply-region.rs:47:29
|
47 | closure_expecting_bound(|x: &'x u32| {
| _____________________________^
48 | | //~^ ERROR mismatched types
49 | | //~| ERROR mismatched types
50 | |
... |
53 | | //~^ ERROR borrowed data cannot be stored outside of its closure
54 | | });
| |_____^
note: ...does not necessarily outlive the lifetime 'x as defined on the function body at 42:1
--> $DIR/expect-region-supply-region.rs:42:1
|
42 | / fn expect_bound_supply_named<'x>() {
43 | | let mut f: Option<&u32> = None;
44 | |
45 | | // Here we give a type annotation that `x` should be free. We get
... |
54 | | });
55 | | }
| |_^
error[E0308]: mismatched types
--> $DIR/expect-region-supply-region.rs:47:33
|
47 | closure_expecting_bound(|x: &'x u32| {
| ^^^^^^^ lifetime mismatch
|
= note: expected type `&u32`
found type `&'x u32`
note: the lifetime 'x as defined on the function body at 42:1...
--> $DIR/expect-region-supply-region.rs:42:1
|
42 | / fn expect_bound_supply_named<'x>() {
43 | | let mut f: Option<&u32> = None;
44 | |
45 | | // Here we give a type annotation that `x` should be free. We get
... |
54 | | });
55 | | }
| |_^
note: ...does not necessarily outlive the anonymous lifetime #2 defined on the body at 47:29
--> $DIR/expect-region-supply-region.rs:47:29
|
47 | closure_expecting_bound(|x: &'x u32| {
| _____________________________^
48 | | //~^ ERROR mismatched types
49 | | //~| ERROR mismatched types
50 | |
... |
53 | | //~^ ERROR borrowed data cannot be stored outside of its closure
54 | | });
| |_____^
error: borrowed data cannot be stored outside of its closure
--> $DIR/expect-region-supply-region.rs:52:18
|
43 | let mut f: Option<&u32> = None;
| ----- borrowed data cannot be stored into here...
...
47 | closure_expecting_bound(|x: &'x u32| {
| ------------ ...because it cannot outlive this closure
...
52 | f = Some(x);
| ^ cannot be stored outside of its closure
error: aborting due to 5 previous errors