Parameter may not live long enough even though everything is static

Playground link.

trait HasStatic<T> {
    fn get_static() -> &'static T;
}

struct Test<T, H>(std::marker::PhantomData<T>, std::marker::PhantomData<H>);

impl<T, H: HasStatic<T>> std::ops::Deref for Test<T, H> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        H::get_static()
    }
}

Error:

error[E0310]: the parameter type `T` may not live long enough
  --> src/lib.rs:10:9
   |
7  | impl<T, H: HasStatic<T>> std::ops::Deref for Test<T, H> {
   |      - help: consider adding an explicit lifetime bound...: `T: 'static`
...
10 |         H::get_static()
   |         ^^^^^^^^^^^^^^^ ...so that the reference type `&'static T` does not outlive the data it points at

I don't understand how there can be a problem -- &Self::Target is going to get the implicit lifetime from &self, which can only be shorter than static because static is forever. The reference returned by get_static is explicitly declared static, so it should be known. Why does this error? I noticed it only happens as long as HasStatic is generic -- if you hard code any specific type it works fine.

You need to tell the compiler that T contains no non-'static references:

impl<T: 'static, H: HasStatic<T>> std::ops::Deref for Test<T, H>

I believe this bound is automatically implied in the definition of trait HasStatic because it explicitly mentions the type &'static T, but such implied bounds are not propagated to other definitions.

4 Likes

I didn't realize that there is some sort of lifetime elision for generic arguments for traits? Does it only work for static? I checked the docs here but it's not clear to me what they discuss about trait objects addresses this case.

I think the source of the implicit bound here is “well-formedness.” Basically it means a type &'static T can only exist if T: 'static, so the use of the former automatically implies the latter.

I don't think well-formedness is documented very much. It’s discussed a bit in RFC 2089 and RFC 1214. Implied bounds are discussed at greater length in the Chalk book (which includes some features that aren’t fully implemented in rustc yet).

I don’t personally know a lot about this, and I might be wrong about how it applies to your code.

1 Like

I don't think it's actually implied, you can go as far as definiing the trait function that supposedly returns &'static T<'nonstatic>. But the compiler stops you from actually using it to do that.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.