-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Enforce that closure: 'a
requires that closure_ret_ty: 'a
holds
#84385
Closed
+224
−28
Closed
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -101,14 +101,42 @@ fn compute_components<'tcx>( | |||||
} | ||||||
|
||||||
ty::Closure(_, ref substs) => { | ||||||
let tupled_ty = substs.as_closure().tupled_upvars_ty(); | ||||||
compute_components(tcx, tupled_ty, out, visited); | ||||||
let closure_substs = substs.as_closure(); | ||||||
compute_components(tcx, closure_substs.tupled_upvars_ty(), out, visited); | ||||||
// Subtle: The return type of a closure can be used in a projection | ||||||
// of the form `<closure as FnOnce>::Output`. Per the RFC 1214 rules | ||||||
// for projections, we can use `closure: 'a` to conclude that | ||||||
// `<closure as FnOnce>::Output: 'a` holds. In order for this to be sound, | ||||||
// we must enforce that requiring `closure: 'a` also requires that. | ||||||
// the return type of the closure outlive `a`. | ||||||
// We do not require that any of the closure's *argument* types outlive 'a | ||||||
// - this is sound, because there is no rule that would allow us to conclide | ||||||
// anything about the argument types from the fact that `closure: 'a` holds | ||||||
// (the arguments of a closure do not appear in the output type of a trait impl | ||||||
// for any trait implemented for a closure). | ||||||
// This is inconsistent with function pointers, which require that all of their | ||||||
// argument types (as well as the return type) outlive `'a` in order for | ||||||
// `fn(A, B) -> R : ' a` to hold. It would be a breaking change to enforce this for | ||||||
// closuers, and is not required for soundness. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
// | ||||||
// Note: The 'skip_binder()' call here matches the way we handle fn substs | ||||||
// via `walk_shallow`, which also skips binders. | ||||||
|
||||||
// Hack - try to get a more accurate count on Crater by skipping this | ||||||
// when checking dependencies. | ||||||
if std::env::var("CARGO_PRIMARY_PACKAGE").is_ok() { | ||||||
compute_components(tcx, closure_substs.sig().output().skip_binder(), out, visited); | ||||||
} | ||||||
} | ||||||
|
||||||
ty::Generator(_, ref substs, _) => { | ||||||
// Same as the closure case | ||||||
let tupled_ty = substs.as_generator().tupled_upvars_ty(); | ||||||
compute_components(tcx, tupled_ty, out, visited); | ||||||
let generator_substs = substs.as_generator(); | ||||||
compute_components(tcx, generator_substs.tupled_upvars_ty(), out, visited); | ||||||
if std::env::var("CARGO_PKG_NAME").ok().as_deref() != Some("tokio-util") { | ||||||
compute_components(tcx, generator_substs.yield_ty(), out, visited); | ||||||
compute_components(tcx, generator_substs.return_ty(), out, visited); | ||||||
} | ||||||
|
||||||
// We ignore regions in the generator interior as we don't | ||||||
// want these to affect region inference | ||||||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
// Regression test for issue #84366 | ||
// Ensures that proving `closure: 'a` requires that | ||
// we prove `closure_ret_type: 'a` | ||
|
||
use std::fmt; | ||
Aaron1011 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
trait Trait { | ||
type Associated; | ||
} | ||
|
||
impl<R, F: Fn() -> R> Trait for F { | ||
type Associated = R; | ||
} | ||
|
||
fn static_transfers_to_associated<T: Trait + 'static>( | ||
_: &T, | ||
x: T::Associated, | ||
) -> Box<dyn fmt::Display /* + 'static */> | ||
where | ||
T::Associated: fmt::Display, | ||
{ | ||
Box::new(x) // T::Associated: 'static follows from T: 'static | ||
} | ||
|
||
fn make_static_displayable<'a>(s: &'a str) -> Box<dyn fmt::Display> { | ||
let f = || -> &'a str { "" }; | ||
// problem is: the closure type of `f` is 'static | ||
static_transfers_to_associated(&f, s) //~ ERROR borrowed data escapes | ||
} | ||
|
||
fn main() { | ||
let d; | ||
{ | ||
let x = "Hello World".to_string(); | ||
d = make_static_displayable(&x); | ||
} | ||
println!("{}", d); | ||
} |
17 changes: 17 additions & 0 deletions
17
src/test/ui/closures/issue-84366-closure-outlives-ret.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
error[E0521]: borrowed data escapes outside of function | ||
--> $DIR/issue-84366-closure-outlives-ret.rs:27:5 | ||
| | ||
LL | fn make_static_displayable<'a>(s: &'a str) -> Box<dyn fmt::Display> { | ||
| -- - `s` is a reference that is only valid in the function body | ||
| | | ||
| lifetime `'a` defined here | ||
... | ||
LL | static_transfers_to_associated(&f, s) | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | | ||
| `s` escapes the function body here | ||
| argument requires that `'a` must outlive `'static` | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0521`. |
40 changes: 40 additions & 0 deletions
40
src/test/ui/generator/issue-84366-generator-outlives-return.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// A version of issue #84366, but involving generator return types instead of closures | ||
|
||
#![feature(generators)] | ||
#![feature(generator_trait)] | ||
|
||
use std::fmt; | ||
use std::ops::Generator; | ||
|
||
trait Trait { | ||
type Associated; | ||
} | ||
|
||
impl<R, F: Generator<Return = R>> Trait for F { | ||
type Associated = R; | ||
} | ||
|
||
fn static_transfers_to_associated<T: Trait + 'static>( | ||
_: &T, | ||
x: T::Associated, | ||
) -> Box<dyn fmt::Display /* + 'static */> | ||
where | ||
T::Associated: fmt::Display, | ||
{ | ||
Box::new(x) // T::Associated: 'static follows from T: 'static | ||
} | ||
|
||
fn make_static_displayable<'a>(s: &'a str) -> Box<dyn fmt::Display> { | ||
let f = || { yield ""; "" }; | ||
// problem is: the closure type of `f` is 'static | ||
static_transfers_to_associated(&f, s) //~ ERROR borrowed data escapes | ||
} | ||
|
||
fn main() { | ||
let d; | ||
{ | ||
let x = "Hello World".to_string(); | ||
d = make_static_displayable(&x); | ||
} | ||
println!("{}", d); | ||
} |
17 changes: 17 additions & 0 deletions
17
src/test/ui/generator/issue-84366-generator-outlives-return.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
error[E0521]: borrowed data escapes outside of function | ||
--> $DIR/issue-84366-generator-outlives-return.rs:30:5 | ||
| | ||
LL | fn make_static_displayable<'a>(s: &'a str) -> Box<dyn fmt::Display> { | ||
| -- - `s` is a reference that is only valid in the function body | ||
| | | ||
| lifetime `'a` defined here | ||
... | ||
LL | static_transfers_to_associated(&f, s) | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | | ||
| `s` escapes the function body here | ||
| argument requires that `'a` must outlive `'static` | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0521`. |
40 changes: 40 additions & 0 deletions
40
src/test/ui/generator/issue-84366-generator-outlives-yield.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// A version of issue #84366, but involving generators instead of closures | ||
|
||
#![feature(generators)] | ||
#![feature(generator_trait)] | ||
|
||
use std::fmt; | ||
use std::ops::Generator; | ||
|
||
trait Trait { | ||
type Associated; | ||
} | ||
|
||
impl<R, F: Generator<Yield = R>> Trait for F { | ||
type Associated = R; | ||
} | ||
|
||
fn static_transfers_to_associated<T: Trait + 'static>( | ||
_: &T, | ||
x: T::Associated, | ||
) -> Box<dyn fmt::Display /* + 'static */> | ||
where | ||
T::Associated: fmt::Display, | ||
{ | ||
Box::new(x) // T::Associated: 'static follows from T: 'static | ||
} | ||
|
||
fn make_static_displayable<'a>(s: &'a str) -> Box<dyn fmt::Display> { | ||
let f = || { yield ""; "" }; | ||
// problem is: the closure type of `f` is 'static | ||
static_transfers_to_associated(&f, s) //~ ERROR borrowed data escapes | ||
} | ||
|
||
fn main() { | ||
let d; | ||
{ | ||
let x = "Hello World".to_string(); | ||
d = make_static_displayable(&x); | ||
} | ||
println!("{}", d); | ||
} |
17 changes: 17 additions & 0 deletions
17
src/test/ui/generator/issue-84366-generator-outlives-yield.stderr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
error[E0521]: borrowed data escapes outside of function | ||
--> $DIR/issue-84366-generator-outlives-yield.rs:30:5 | ||
| | ||
LL | fn make_static_displayable<'a>(s: &'a str) -> Box<dyn fmt::Display> { | ||
| -- - `s` is a reference that is only valid in the function body | ||
| | | ||
| lifetime `'a` defined here | ||
... | ||
LL | static_transfers_to_associated(&f, s) | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | | ||
| `s` escapes the function body here | ||
| argument requires that `'a` must outlive `'static` | ||
|
||
error: aborting due to previous error | ||
|
||
For more information about this error, try `rustc --explain E0521`. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.