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:
commit
bc072ed0ca
18 changed files with 352 additions and 21 deletions
19
src/test/ui/borrowck/issue-45983.rs
Normal file
19
src/test/ui/borrowck/issue-45983.rs
Normal 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
|
||||
}
|
||||
12
src/test/ui/borrowck/issue-45983.stderr
Normal file
12
src/test/ui/borrowck/issue-45983.stderr
Normal 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
|
||||
|
||||
54
src/test/ui/borrowck/issue-7573.rs
Normal file
54
src/test/ui/borrowck/issue-7573.rs
Normal 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();
|
||||
}
|
||||
16
src/test/ui/borrowck/issue-7573.stderr
Normal file
16
src/test/ui/borrowck/issue-7573.stderr
Normal 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
|
||||
|
||||
20
src/test/ui/borrowck/regions-escape-bound-fn-2.rs
Normal file
20
src/test/ui/borrowck/regions-escape-bound-fn-2.rs
Normal 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
|
||||
}
|
||||
12
src/test/ui/borrowck/regions-escape-bound-fn-2.stderr
Normal file
12
src/test/ui/borrowck/regions-escape-bound-fn-2.stderr
Normal 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
|
||||
|
||||
20
src/test/ui/borrowck/regions-escape-bound-fn.rs
Normal file
20
src/test/ui/borrowck/regions-escape-bound-fn.rs
Normal 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
|
||||
}
|
||||
12
src/test/ui/borrowck/regions-escape-bound-fn.stderr
Normal file
12
src/test/ui/borrowck/regions-escape-bound-fn.stderr
Normal 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
|
||||
|
||||
18
src/test/ui/borrowck/regions-escape-unboxed-closure.rs
Normal file
18
src/test/ui/borrowck/regions-escape-unboxed-closure.rs
Normal 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
|
||||
}
|
||||
12
src/test/ui/borrowck/regions-escape-unboxed-closure.stderr
Normal file
12
src/test/ui/borrowck/regions-escape-unboxed-closure.stderr
Normal 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
|
||||
|
||||
|
|
@ -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() { }
|
||||
|
|
@ -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
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue