Skip to content

Commit 054ffe1

Browse files
committed
Forbid closures that outlive their signature
* This prevents the AST borrow checker from incorrectly accepting closures that return references to local variables and that are never called. * This also ensures that existential types don't end up containing any `ReScope`s
1 parent 597f432 commit 054ffe1

16 files changed

+59
-89
lines changed

src/librustc/ty/outlives.rs

+3
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
6565
for upvar_ty in substs.upvar_tys(def_id, *self) {
6666
self.compute_components(upvar_ty, out);
6767
}
68+
self.compute_components(substs.closure_sig_ty(def_id, *self), out);
6869
}
6970

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

77+
self.compute_components(substs.return_ty(def_id, *self), out);
78+
self.compute_components(substs.yield_ty(def_id, *self), out);
7679
// We ignore regions in the generator interior as we don't
7780
// want these to affect region inference
7881
}

src/librustc_metadata/decoder.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl<'a, 'tcx: 'a, T: Decodable> Lazy<T> {
135135
}
136136
}
137137

138-
impl<'a, 'tcx: 'a, T: Decodable> LazySeq<T> {
138+
impl<'a, 'tcx: 'a, T: Decodable + 'a> LazySeq<T> {
139139
pub fn decode<M: Metadata<'a, 'tcx>>(
140140
self,
141141
meta: M,

src/test/incremental/hashes/closure_expressions.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@ pub fn add_parameter() {
4949
// Change parameter pattern ----------------------------------------------------
5050
#[cfg(cfail1)]
5151
pub fn change_parameter_pattern() {
52-
let _ = |x: &u32| x;
52+
let _ = |x: (u32,)| x;
5353
}
5454

5555
#[cfg(not(cfail1))]
5656
#[rustc_clean(cfg="cfail2", except="HirBody, mir_built, typeck_tables_of")]
5757
#[rustc_clean(cfg="cfail3")]
5858
pub fn change_parameter_pattern() {
59-
let _ = |&x: &u32| x;
59+
let _ = |(x,): (u32,)| x;
6060
}
6161

6262

src/test/run-pass/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ impl<'a,'tcx> Foo<'a,'tcx> {
4444

4545
fn elaborate_bounds(
4646
&mut self,
47-
mut mk_cand: Box<for<'b> FnMut(&mut Foo<'b, 'tcx>) -> isize>)
47+
mut mk_cand: Box<for<'b> FnMut(&mut Foo<'b, 'tcx>) -> isize + 'tcx>)
4848
-> isize
4949
{
5050
mk_cand(self)

src/test/ui/impl-trait/issue-55608-captures-empty-region.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// This used to ICE because it creates an `impl Trait` that captures a
22
// hidden empty region.
33

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

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

src/test/ui/impl-trait/issue-55608-captures-empty-region.stderr

-11
This file was deleted.

src/test/ui/issues/issue-40510-1.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
// compile-pass
21
#![allow(unused)]
32

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

76
|| {
8-
&mut x
7+
&mut x //~ ERROR cannot infer
98
};
109
}
1110

+28-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,33 @@
1-
warning: captured variable cannot escape `FnMut` closure body
2-
--> $DIR/issue-40510-1.rs:8:9
1+
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
2+
--> $DIR/issue-40510-1.rs:7:9
3+
|
4+
LL | &mut x
5+
| ^^^^^^
6+
|
7+
note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 6:5...
8+
--> $DIR/issue-40510-1.rs:6:5
39
|
410
LL | || {
5-
| - inferred to be a `FnMut` closure
11+
| ^^
12+
note: ...so that closure can access `x`
13+
--> $DIR/issue-40510-1.rs:7:9
14+
|
615
LL | &mut x
7-
| ^^^^^^ returns a reference to a captured variable which escapes the closure body
16+
| ^^^^^^
17+
note: but, the lifetime must be valid for the expression at 6:5...
18+
--> $DIR/issue-40510-1.rs:6:5
19+
|
20+
LL | / || {
21+
LL | | &mut x
22+
LL | | };
23+
| |_____^
24+
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
25+
--> $DIR/issue-40510-1.rs:6:5
826
|
9-
= note: `FnMut` closures only have access to their captured variables while they are executing...
10-
= note: ...therefore, they cannot allow references to captured variables to escape
11-
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
12-
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
27+
LL | / || {
28+
LL | | &mut x
29+
LL | | };
30+
| |_____^
31+
32+
error: aborting due to previous error
1333

src/test/ui/issues/issue-40510-3.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
// compile-pass
21
#![allow(unused)]
32

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

76
|| {
8-
|| {
7+
|| { //~ ERROR captured variable cannot escape `FnMut` closure body
98
x.push(())
109
}
1110
};
+4-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
warning: captured variable cannot escape `FnMut` closure body
2-
--> $DIR/issue-40510-3.rs:8:9
1+
error: captured variable cannot escape `FnMut` closure body
2+
--> $DIR/issue-40510-3.rs:7:9
33
|
44
LL | || {
55
| - inferred to be a `FnMut` closure
@@ -10,6 +10,6 @@ LL | | }
1010
|
1111
= note: `FnMut` closures only have access to their captured variables while they are executing...
1212
= note: ...therefore, they cannot allow references to captured variables to escape
13-
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
14-
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
13+
14+
error: aborting due to previous error
1515

src/test/ui/issues/issue-49556.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
fn iter<'a>(data: &'a [usize]) -> impl Iterator<Item = usize> + 'a {
33
data.iter()
44
.map(
5-
|x| x // fn(&'a usize) -> &'(ReScope) usize
5+
|x| x // fn(&'a usize) -> &'a usize
66
)
77
.map(
8-
|x| *x // fn(&'(ReScope) usize) -> usize
8+
|x| *x // fn(&'a usize) -> usize
99
)
1010
}
1111

src/test/ui/issues/issue-49824.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
1-
#![feature(rustc_attrs)]
2-
31
// This test checks that a warning occurs with migrate mode.
42

5-
#[rustc_error]
63
fn main() {
7-
//~^ ERROR compilation successful
84
let mut x = 0;
95
|| {
106
|| {
11-
//~^ WARNING captured variable cannot escape `FnMut` closure body
12-
//~| WARNING this error has been downgraded to a warning
13-
//~| WARNING this warning will become a hard error in the future
7+
//~^ ERROR captured variable cannot escape `FnMut` closure body
148
let _y = &mut x;
159
}
1610
};

src/test/ui/issues/issue-49824.stderr

+2-18
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,16 @@
1-
warning: captured variable cannot escape `FnMut` closure body
2-
--> $DIR/issue-49824.rs:10:9
1+
error: captured variable cannot escape `FnMut` closure body
2+
--> $DIR/issue-49824.rs:6:9
33
|
44
LL | || {
55
| - inferred to be a `FnMut` closure
66
LL | / || {
77
LL | |
8-
LL | |
9-
LL | |
108
LL | | let _y = &mut x;
119
LL | | }
1210
| |_________^ returns a closure that contains a reference to a captured variable, which then escapes the closure body
1311
|
1412
= note: `FnMut` closures only have access to their captured variables while they are executing...
1513
= note: ...therefore, they cannot allow references to captured variables to escape
16-
= warning: this error has been downgraded to a warning for backwards compatibility with previous releases
17-
= warning: this represents potential undefined behavior in your code and this warning will become a hard error in the future
18-
19-
error: compilation successful
20-
--> $DIR/issue-49824.rs:6:1
21-
|
22-
LL | / fn main() {
23-
LL | |
24-
LL | | let mut x = 0;
25-
LL | | || {
26-
... |
27-
LL | | };
28-
LL | | }
29-
| |_^
3014

3115
error: aborting due to previous error
3216

src/test/ui/regions/regions-escape-via-trait-or-not.stderr

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,16 @@ LL | with(|o| o)
1212
= note: ...so that the expression is assignable:
1313
expected &isize
1414
found &isize
15-
note: but, the lifetime must be valid for the expression at 18:5...
15+
note: but, the lifetime must be valid for the call at 18:5...
1616
--> $DIR/regions-escape-via-trait-or-not.rs:18:5
1717
|
1818
LL | with(|o| o)
19-
| ^^^^
20-
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
21-
--> $DIR/regions-escape-via-trait-or-not.rs:18:5
19+
| ^^^^^^^^^^^
20+
note: ...so that argument is valid for the call
21+
--> $DIR/regions-escape-via-trait-or-not.rs:18:10
2222
|
2323
LL | with(|o| o)
24-
| ^^^^
24+
| ^^^^^
2525

2626
error: aborting due to previous error
2727

src/test/ui/regions/regions-return-ref-to-upvar-issue-17403.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ fn main() {
44
// Unboxed closure case
55
{
66
let mut x = 0;
7-
let mut f = || &mut x; //~ ERROR cannot infer
7+
let mut f = || &mut x; //~ ERROR borrowed data cannot be stored outside of its closure
88
let x = f();
99
let y = f();
1010
}
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,11 @@
1-
error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
1+
error: borrowed data cannot be stored outside of its closure
22
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
33
|
44
LL | let mut f = || &mut x;
5-
| ^^^^^^
6-
|
7-
note: first, the lifetime cannot outlive the lifetime '_ as defined on the body at 7:21...
8-
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:21
9-
|
10-
LL | let mut f = || &mut x;
11-
| ^^^^^^^^^
12-
note: ...so that closure can access `x`
13-
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:7:24
14-
|
15-
LL | let mut f = || &mut x;
16-
| ^^^^^^
17-
note: but, the lifetime must be valid for the call at 9:17...
18-
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17
19-
|
20-
LL | let y = f();
21-
| ^^^
22-
note: ...so type `&mut i32` of expression is valid during the expression
23-
--> $DIR/regions-return-ref-to-upvar-issue-17403.rs:9:17
24-
|
25-
LL | let y = f();
26-
| ^^^
5+
| ----- -- ^^^^^^ cannot be stored outside of its closure
6+
| | |
7+
| | ...because it cannot outlive this closure
8+
| borrowed data cannot be stored into here...
279

2810
error: aborting due to previous error
2911

0 commit comments

Comments
 (0)