Code change:
Bug originally found by , which I've then reduced. I tried this code: I expected to see this happen: Instead, this happened: code compiles successfully and onwards modify labels: +I-unsound +regression-from-stable-to-stable -regression-untriaged This does not occur if the implied-lifetime-bounds array is in closure parameter position; so it looks like a bug w.r.t. not properly checking the closure output type implied bounds?does not help (as of )
Bisected to nightly-2022-08-10: <- looks maybe interesting
you beat me by one minute :) cc for being possible cause of this unsoundness?
WG-prioritization assigning priority (). label -I-prioritize +P-high +T-compiler -needs-triage
Oh, neat it did turn out to be a new soundness bug instead of a dupe of . Thanks for figuring out this was a regression,
for we have a terminator calling , i.e. a function which returns . This does not include the implied bounds. Checking that is WF requires proving which succeeds without checking the usable implied bounds of the trait-ref. edit: there's a bit more to this than I thought
This soundness bug is effectively only reproducible via the traits because the impls for it are builtin and so a little screwy. An attempt to write an explicit impl for the builtin impls would require an explicit bound that holds which is not present on the builtin impl. There is an assumption that all it takes for an assoc type to be wf is the where clauses on it and the impl hold, and that all arguments in the traitref are wf. The builtin impls violate this by not having the required implied bound on the impl so we end up with being able to be proven wf without proving the implied bounds. When calling we check that the fn sig of is wf which is . Before we would check the normalized signature is wf so the return type would be which would cause us to prove . Now that we check the unnormalized_ signature is wf we end up never seeing the normalized form with the which introduces the implied bound. It is generally an invariant of the type system that holding should imply also holds. The fact that can be well formed but is not, is concerning. In an ideal world proving the traits would require also proving all the implied bounds hold but right now that is not possible afaik. A simple fix (albeit hacky until we make implied bounds desugared to actual bounds) would be to make us also check not just .

Related discussion:
text: <ins> // <https://github.com/rust-lang/rust/issues/114936> fn whoops( s: String, f: impl for<'s> FnOnce(&'s str) -> (&'static str, [&'static &'s (); 0]), ) -> &'static str { f(&s).0 //~^ ERROR `s` does not live long enough } // <https://github.com/rust-lang/rust/issues/118876> fn extend<T>(input: &T) -> &'static T { struct Bounded<'a, 'b: 'static, T>(&'a T, [&'b (); 0]); let n: Box<dyn FnOnce(&T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, [])); n(input).0 //~^ ERROR borrowed data escapes outside of function } // <https://github.com/rust-lang/rust/issues/118876> fn extend_mut<'a, T>(input: &'a mut T) -> &'static mut T { struct Bounded<'a, 'b: 'static, T>(&'a mut T, [&'b (); 0]); let mut n: Box<dyn FnMut(&mut T) -> Bounded<'static, '_, T>> = Box::new(|x| Bounded(x, [])); n(input).0 //~^ ERROR borrowed data escapes outside of function } fn main() {} </ins>