Open
Description
The following code compiles on stable and nightly. I'm not sure it should as it's effectively casting a Struct::<'a>
to a Struct::<'static>
in safe code.
use std::{any::Any, marker::PhantomData};
fn main() {
bad();
}
fn bad<'a>() -> Struct<'static> {
make_static(|| Struct::<'a>(PhantomData))
}
struct Struct<'a>(PhantomData<&'a ()>);
fn make_static<A, B>(a: A) -> B
where
A: FnOnce0 + 'static,
B: 'static,
{
let boxed: Box<dyn Any + 'static> = Box::new(a.call());
*Box::<dyn Any + 'static>::downcast(boxed).unwrap()
}
trait FnOnce0 {
type Output;
fn call(self) -> Self::Output;
}
impl<F, O> FnOnce0 for F
where
F: FnOnce() -> O,
{
type Output = F::Output;
fn call(self) -> Self::Output {
self()
}
}
It seems lifetime and type parameters that are used in the closure don't affect the lifetime of the closure itself. I stumbled upon this after noticing that || T::default()
is 'static
whereas T::default()
is not.
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
jonas-schievink commentedon Oct 22, 2019
Should they, though? The lifetime of a closure is determined by the captured environment it contains.
Also note that it fails to compile when you try to explicitly specify
'a
(citing late-bound lifetimes) or when you try to pass in the non-'static
struct as an argument tobad
. While I don't know the specific rules here (especially about when'a
is treated as late-bound), this doesn't look unsound to me.alecmocatta commentedon Oct 22, 2019
Thanks @jonas-schievink. As far as I'm aware it doesn't enable unsoundness. However the conversion from
Struct<'a>
to aStruct<'static>
was surprising to me, so I thought I'd seek a second opinion.matthewjasper commentedon Oct 22, 2019
I tried fixing this in #60332, but it ends up breaking too much code.
Spoonbender commentedon Oct 17, 2022
triage: no change
(code still compiles)