Skip to content

[DO NOT MERGE] Forbid closures that outlive their signature #60332

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/librustc/ty/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
for upvar_ty in substs.upvar_tys(def_id, *self) {
self.compute_components(upvar_ty, out);
}
self.compute_components(substs.closure_sig_ty(def_id, *self), out);
}

ty::Generator(def_id, ref substs, _) => {
Expand All @@ -73,6 +74,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
self.compute_components(upvar_ty, out);
}

self.compute_components(substs.return_ty(def_id, *self), out);
self.compute_components(substs.yield_ty(def_id, *self), out);
// We ignore regions in the generator interior as we don't
// want these to affect region inference
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_metadata/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ impl<'a, 'tcx: 'a, T: Decodable> Lazy<T> {
}
}

impl<'a, 'tcx: 'a, T: Decodable> LazySeq<T> {
impl<'a, 'tcx: 'a, T: Decodable + 'a> LazySeq<T> {
pub fn decode<M: Metadata<'a, 'tcx>>(
self,
meta: M,
Expand Down
4 changes: 2 additions & 2 deletions src/test/incremental/hashes/closure_expressions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ pub fn add_parameter() {
// Change parameter pattern ----------------------------------------------------
#[cfg(cfail1)]
pub fn change_parameter_pattern() {
let _ = |x: &u32| x;
let _ = |x: (u32,)| x;
}

#[cfg(not(cfail1))]
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")]
#[rustc_clean(cfg="cfail3")]
pub fn change_parameter_pattern() {
let _ = |&x: &u32| x;
let _ = |(x,): (u32,)| x;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<'a,'tcx> Foo<'a,'tcx> {

fn elaborate_bounds(
&mut self,
mut mk_cand: Box<for<'b> FnMut(&mut Foo<'b, 'tcx>) -> isize>)
mut mk_cand: Box<for<'b> FnMut(&mut Foo<'b, 'tcx>) -> isize + 'tcx>)
-> isize
{
mk_cand(self)
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/impl-trait/issue-55608-captures-empty-region.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// This used to ICE because it creates an `impl Trait` that captures a
// hidden empty region.

#![feature(conservative_impl_trait)]
// compile-pass

fn server() -> impl FilterBase2 { //~ ERROR [E0700]
fn server() -> impl FilterBase2 {
segment2(|| { loop { } }).map2(|| "")
}

Expand Down
11 changes: 0 additions & 11 deletions src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr

This file was deleted.

3 changes: 1 addition & 2 deletions src/test/ui/issues/issue-40510-1.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// compile-pass
#![allow(unused)]

fn f() {
let mut x: Box<()> = Box::new(());

|| {
&mut x
&mut x //~ ERROR cannot infer
};
}

Expand Down
36 changes: 28 additions & 8 deletions src/test/ui/issues/issue-40510-1.stderr
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
warning: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-1.rs:8:9
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
--> $DIR/issue-40510-1.rs:7:9
|
LL | &mut x
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 6:5...
--> $DIR/issue-40510-1.rs:6:5
|
LL | || {
| - inferred to be a `FnMut` closure
| ^^
note: ...so that closure can access `x`
--> $DIR/issue-40510-1.rs:7:9
|
LL | &mut x
| ^^^^^^ returns a reference to a captured variable which escapes the closure body
| ^^^^^^
note: but, the lifetime must be valid for the expression at 6:5...
--> $DIR/issue-40510-1.rs:6:5
|
LL | / || {
LL | | &mut x
LL | | };
| |_____^
note: ...so type `[closure@$DIR/issue-40510-1.rs:6:5: 8:6 x:&mut std::boxed::Box<()>]` of expression is valid during the expression
--> $DIR/issue-40510-1.rs:6:5
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
LL | / || {
LL | | &mut x
LL | | };
| |_____^

error: aborting due to previous error

3 changes: 1 addition & 2 deletions src/test/ui/issues/issue-40510-3.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
// compile-pass
#![allow(unused)]

fn f() {
let mut x: Vec<()> = Vec::new();

|| {
|| {
|| { //~ ERROR captured variable cannot escape `FnMut` closure body
x.push(())
}
};
Expand Down
8 changes: 4 additions & 4 deletions src/test/ui/issues/issue-40510-3.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
warning: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-3.rs:8:9
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-40510-3.rs:7:9
|
LL | || {
| - inferred to be a `FnMut` closure
Expand All @@ -10,6 +10,6 @@ LL | | }
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future

error: aborting due to previous error

4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-49556.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
fn iter<'a>(data: &'a [usize]) -> impl Iterator<Item = usize> + 'a {
data.iter()
.map(
|x| x // fn(&'a usize) -> &'(ReScope) usize
|x| x // fn(&'a usize) -> &'a usize
)
.map(
|x| *x // fn(&'(ReScope) usize) -> usize
|x| *x // fn(&'a usize) -> usize
)
}

Expand Down
8 changes: 1 addition & 7 deletions src/test/ui/issues/issue-49824.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
#![feature(rustc_attrs)]

// This test checks that a warning occurs with migrate mode.

#[rustc_error]
fn main() {
//~^ ERROR compilation successful
let mut x = 0;
|| {
|| {
//~^ WARNING captured variable cannot escape `FnMut` closure body
//~| WARNING this error has been downgraded to a warning
//~| WARNING this warning will become a hard error in the future
//~^ ERROR captured variable cannot escape `FnMut` closure body
let _y = &mut x;
}
};
Expand Down
20 changes: 2 additions & 18 deletions src/test/ui/issues/issue-49824.stderr
Original file line number Diff line number Diff line change
@@ -1,32 +1,16 @@
warning: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-49824.rs:10:9
error: captured variable cannot escape `FnMut` closure body
--> $DIR/issue-49824.rs:6:9
|
LL | || {
| - inferred to be a `FnMut` closure
LL | / || {
LL | |
LL | |
LL | |
LL | | let _y = &mut x;
LL | | }
| |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
|
= note: `FnMut` closures only have access to their captured variables while they are executing...
= note: ...therefore, they cannot allow references to captured variables to escape
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future

error: compilation successful
--> $DIR/issue-49824.rs:6:1
|
LL | / fn main() {
LL | |
LL | | let mut x = 0;
LL | | || {
... |
LL | | };
LL | | }
| |_^

error: aborting due to previous error

10 changes: 5 additions & 5 deletions src/test/ui/regions/regions-escape-via-trait-or-not.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ LL | with(|o| o)
= note: ...so that the expression is assignable:
expected &isize
found &isize
note: but, the lifetime must be valid for the expression at 18:5...
note: but, the lifetime must be valid for the call at 18:5...
--> $DIR/regions-escape-via-trait-or-not.rs:18:5
|
LL | with(|o| o)
| ^^^^
note: ...so type `fn([closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]) -> isize {with::<&isize, [closure@$DIR/regions-escape-via-trait-or-not.rs:18:10: 18:15]>}` of expression is valid during the expression
--> $DIR/regions-escape-via-trait-or-not.rs:18:5
| ^^^^^^^^^^^
note: ...so that argument is valid for the call
--> $DIR/regions-escape-via-trait-or-not.rs:18:10
|
LL | with(|o| o)
| ^^^^
| ^^^^^

error: aborting due to previous error

Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ fn main() {
// Unboxed closure case
{
let mut x = 0;
let mut f = || &mut x; //~ ERROR cannot infer
let mut f = || &mut x; //~ ERROR borrowed data cannot be stored outside of its closure
let x = f();
let y = f();
}
Expand Down
28 changes: 5 additions & 23 deletions src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.stderr
Original file line number Diff line number Diff line change
@@ -1,29 +1,11 @@
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
error: borrowed data cannot be stored outside of its closure
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
|
LL | let mut f = || &mut x;
| ^^^^^^
|
note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 7:21...
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:21
|
LL | let mut f = || &mut x;
| ^^^^^^^^^
note: ...so that closure can access `x`
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
|
LL | let mut f = || &mut x;
| ^^^^^^
note: but, the lifetime must be valid for the call at 9:17...
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17
|
LL | let y = f();
| ^^^
note: ...so type `&mut i32` of expression is valid during the expression
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17
|
LL | let y = f();
| ^^^
| ----- -- ^^^^^^ cannot be stored outside of its closure
| | |
| | ...because it cannot outlive this closure
| borrowed data cannot be stored into here...

error: aborting due to previous error