diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index 4abc00cefb68f..61056fab3ed75 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -108,7 +108,7 @@ pub struct InlineAsmCtxt<'a, 'tcx> { get_operand_ty: Box) -> Ty<'tcx> + 'a>, } -impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { +impl<'a, 'tcx: 'a> InlineAsmCtxt<'a, 'tcx> { pub fn new_global_asm(tcx: TyCtxt<'tcx>) -> Self { InlineAsmCtxt { tcx, diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 441dc3c7e888c..d0751be8dbe19 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -335,7 +335,7 @@ pub struct InferCtxt<'tcx> { universe: Cell, normalize_fn_sig_for_diagnostic: - Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, + Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'tcx>>, } /// See the `error_reporting` module for more details. @@ -552,7 +552,7 @@ pub struct InferCtxtBuilder<'tcx> { defining_use_anchor: DefiningAnchor, considering_regions: bool, normalize_fn_sig_for_diagnostic: - Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>>, + Option, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'tcx>>, } pub trait TyCtxtInferExt<'tcx> { @@ -589,7 +589,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { pub fn with_normalize_fn_sig_for_diagnostic( mut self, - fun: Lrc, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx>>, + fun: Lrc, ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'tcx>, ) -> Self { self.normalize_fn_sig_for_diagnostic = Some(fun); self diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs index 14ee9f0519010..ae9281ff2643e 100644 --- a/compiler/rustc_infer/src/infer/outlives/components.rs +++ b/compiler/rustc_infer/src/infer/outlives/components.rs @@ -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 `::Output`. Per the RFC 1214 rules + // for projections, we can use `closure: 'a` to conclude that + // `::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. + // + // 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 diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 14a126951115c..1cfc91c0c73ed 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -76,7 +76,7 @@ where R: Try, { #[inline] - fn enumerate<'a, T, Acc, R>( + fn enumerate<'a, T, Acc, R: 'a>( count: &'a mut usize, mut fold: impl FnMut(Acc, (usize, T)) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index a0afaa326ad63..7edcecf5d75d2 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -37,7 +37,7 @@ fn filter_fold( move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } } -fn filter_try_fold<'a, T, Acc, R: Try>( +fn filter_try_fold<'a, T, Acc, R: Try + 'a>( predicate: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index e0d665c9e12ba..04b9f548be865 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -39,7 +39,7 @@ fn filter_map_fold( } } -fn filter_map_try_fold<'a, T, B, Acc, R: Try>( +fn filter_map_try_fold<'a, T, B, Acc, R: Try + 'a>( f: &'a mut impl FnMut(T) -> Option, mut fold: impl FnMut(Acc, B) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -94,9 +94,9 @@ where #[inline] fn next_back(&mut self) -> Option { #[inline] - fn find( - f: &mut impl FnMut(T) -> Option, - ) -> impl FnMut((), T) -> ControlFlow + '_ { + fn find<'a, T, B: 'a>( + f: &'a mut impl FnMut(T) -> Option, + ) -> impl FnMut((), T) -> ControlFlow + 'a { move |(), x| match f(x) { Some(x) => ControlFlow::Break(x), None => ControlFlow::CONTINUE, diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 307016c269099..388338b33e321 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -334,9 +334,9 @@ where Fold: FnMut(Acc, U) -> Acc, { #[inline] - fn flatten( - fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc + '_ { + fn flatten<'a, T: IntoIterator, Acc: 'a>( + fold: &'a mut impl FnMut(Acc, T::IntoIter) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc + 'a { move |acc, iter| fold(acc, iter.into_iter()) } @@ -365,7 +365,7 @@ where R: Try, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try>( + fn flatten<'a, T: IntoIterator, Acc, R: Try + 'a>( frontiter: &'a mut Option, fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -403,9 +403,9 @@ where Fold: FnMut(Acc, U) -> Acc, { #[inline] - fn flatten( - fold: &mut impl FnMut(Acc, T::IntoIter) -> Acc, - ) -> impl FnMut(Acc, T) -> Acc + '_ { + fn flatten<'a, T: IntoIterator, Acc: 'a>( + fold: &'a mut impl FnMut(Acc, T::IntoIter) -> Acc, + ) -> impl FnMut(Acc, T) -> Acc + 'a { move |acc, iter| fold(acc, iter.into_iter()) } @@ -434,7 +434,7 @@ where R: Try, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try>( + fn flatten<'a, T: IntoIterator, Acc, R: Try + 'a>( backiter: &'a mut Option, fold: &'a mut impl FnMut(Acc, &mut T::IntoIter) -> R, ) -> impl FnMut(Acc, T) -> R + 'a { diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs index 19839fdfe5bc3..23e90c3dfabda 100644 --- a/library/core/src/iter/adapters/inspect.rs +++ b/library/core/src/iter/adapters/inspect.rs @@ -54,7 +54,7 @@ fn inspect_fold( } } -fn inspect_try_fold<'a, T, Acc, R>( +fn inspect_try_fold<'a, T, Acc, R: 'a>( f: &'a mut impl FnMut(&T), mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 9e25dbe462c91..479141531b619 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -84,7 +84,7 @@ fn map_fold( move |acc, elt| g(acc, f(elt)) } -fn map_try_fold<'a, T, B, Acc, R>( +fn map_try_fold<'a, T, B, Acc, R: 'a>( f: &'a mut impl FnMut(T) -> B, mut g: impl FnMut(Acc, B) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs index 80bfd2231241b..6f893783cb450 100644 --- a/library/core/src/iter/adapters/scan.rs +++ b/library/core/src/iter/adapters/scan.rs @@ -58,7 +58,7 @@ where Fold: FnMut(Acc, Self::Item) -> R, R: Try, { - fn scan<'a, T, St, B, Acc, R: Try>( + fn scan<'a, T, St, B, Acc: 'a, R: Try + 'a>( state: &'a mut St, f: &'a mut impl FnMut(&mut St, T) -> Option, mut fold: impl FnMut(Acc, B) -> R + 'a, diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 2962e0104d11d..d70667aae9ac3 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -79,7 +79,7 @@ where Fold: FnMut(Acc, Self::Item) -> R, R: Try, { - fn check<'a, T, Acc, R: Try>( + fn check<'a, T, Acc: 'a, R: Try + 'a>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs index ded216da952a3..62908665460b5 100644 --- a/library/core/src/iter/adapters/take_while.rs +++ b/library/core/src/iter/adapters/take_while.rs @@ -70,7 +70,7 @@ where Fold: FnMut(Acc, Self::Item) -> R, R: Try, { - fn check<'a, T, Acc, R: Try>( + fn check<'a, T, Acc: 'a, R: Try + 'a>( flag: &'a mut bool, p: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index f6e6732b0e391..b9b1979cb4b37 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3848,7 +3848,7 @@ where F: FnMut(A::Item, B::Item) -> ControlFlow, { #[inline] - fn compare<'a, B, X, T>( + fn compare<'a, B, X, T: 'a>( b: &'a mut B, mut f: impl FnMut(X, B::Item) -> ControlFlow + 'a, ) -> impl FnMut(X) -> ControlFlow> + 'a diff --git a/src/test/ui/closures/issue-84366-closure-outlives-ret.rs b/src/test/ui/closures/issue-84366-closure-outlives-ret.rs new file mode 100644 index 0000000000000..6f610a130f366 --- /dev/null +++ b/src/test/ui/closures/issue-84366-closure-outlives-ret.rs @@ -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; +trait Trait { + type Associated; +} + +impl R> Trait for F { + type Associated = R; +} + +fn static_transfers_to_associated( + _: &T, + x: T::Associated, +) -> Box +where + T::Associated: fmt::Display, +{ + Box::new(x) // T::Associated: 'static follows from T: 'static +} + +fn make_static_displayable<'a>(s: &'a str) -> Box { + 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); +} diff --git a/src/test/ui/closures/issue-84366-closure-outlives-ret.stderr b/src/test/ui/closures/issue-84366-closure-outlives-ret.stderr new file mode 100644 index 0000000000000..07656b7d917e0 --- /dev/null +++ b/src/test/ui/closures/issue-84366-closure-outlives-ret.stderr @@ -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 { + | -- - `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`. diff --git a/src/test/ui/generator/issue-84366-generator-outlives-return.rs b/src/test/ui/generator/issue-84366-generator-outlives-return.rs new file mode 100644 index 0000000000000..ee01257156b80 --- /dev/null +++ b/src/test/ui/generator/issue-84366-generator-outlives-return.rs @@ -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> Trait for F { + type Associated = R; +} + +fn static_transfers_to_associated( + _: &T, + x: T::Associated, +) -> Box +where + T::Associated: fmt::Display, +{ + Box::new(x) // T::Associated: 'static follows from T: 'static +} + +fn make_static_displayable<'a>(s: &'a str) -> Box { + 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); +} diff --git a/src/test/ui/generator/issue-84366-generator-outlives-return.stderr b/src/test/ui/generator/issue-84366-generator-outlives-return.stderr new file mode 100644 index 0000000000000..ce198b1db0df4 --- /dev/null +++ b/src/test/ui/generator/issue-84366-generator-outlives-return.stderr @@ -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 { + | -- - `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`. diff --git a/src/test/ui/generator/issue-84366-generator-outlives-yield.rs b/src/test/ui/generator/issue-84366-generator-outlives-yield.rs new file mode 100644 index 0000000000000..7f274140ed8df --- /dev/null +++ b/src/test/ui/generator/issue-84366-generator-outlives-yield.rs @@ -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> Trait for F { + type Associated = R; +} + +fn static_transfers_to_associated( + _: &T, + x: T::Associated, +) -> Box +where + T::Associated: fmt::Display, +{ + Box::new(x) // T::Associated: 'static follows from T: 'static +} + +fn make_static_displayable<'a>(s: &'a str) -> Box { + 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); +} diff --git a/src/test/ui/generator/issue-84366-generator-outlives-yield.stderr b/src/test/ui/generator/issue-84366-generator-outlives-yield.stderr new file mode 100644 index 0000000000000..05d27a449ff3d --- /dev/null +++ b/src/test/ui/generator/issue-84366-generator-outlives-yield.stderr @@ -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 { + | -- - `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`.