Confusion about lifetime of struct and struct field

Hello all,

I’m struggling in understanding the constraint between lifetime of a struct reference and one of its field. Concretely, why does the following code compile:

#[derive(Debug)]
#[repr(C)]
pub struct Foo<'a>(&'a u8);

struct WrapFoo<'a> {
    inner: &'a Foo<'a>,
}

mod ffi {
    extern "C" {
        pub fn foo(s: &u8, f: *mut *const super::Foo);
    }
}

pub fn foo<'a>(s: &'a u8) -> &'a Foo<'a> {
    unsafe {
        let mut f = std::mem::uninitialized();
        ffi::foo(s, &mut f);
        &*f
    }
}

fn main() {
    let x = 10u8;
    let f; // lifetime 'a
    {
        let ff;  // lifetime 'b
        let wf;
        {
            ff = foo(&x);
            wf = WrapFoo { inner: ff }; // should wf.f have lifetime &'b Foo<'b>?
        }
        f = wf.inner; // because 'a : 'b, how is it possible?
    }
    println!("{:?}", f);

}

The struct WrapFoo contains a reference inner to some Foo<'a>, and this reference has also the lifetime 'a.

There is a reference to f: 'a &Foo<_> and another ff :'b &Foo<_> where 'a: 'b. Using

wf = WrapFoo { inner: ff }

I mean to restrict wf.inner:&'b Foo<'b>`.

But surprisingly, I can leak 'b to the larger lifetime 'a with f = wf.inner, how is it possible?

Many thanks for any help.

I tried to explain this via inline comments:

fn main() {
    let x = 10u8; // 'a lifetime
    let f;
    {
        let ff;
        let wf;
        {
            // by using the unsafe code in foo(), ownership of value return
            // by foo() has lifetime 'static, as in, it needs to be manually
            // freed.
            ff = foo(&x); // ff has reference to lifetime 'a, as per foo signature.
            wf = WrapFoo { f: ff }; // wf.f has reference to lifetime 'a
        }
        // wf.f reference is shared with f, which now has reference to 'a.
        // Note that immutable references can be shared between scopes.
        f = wf.f;
    }
    // it is okay to use f which has reference to lifetime 'a, which is same as lifetime of x.
    println!("{:?}", f);
}

1 Like

Many thanks, I think I was confused between the lifetime of the reference itself, and the lifetime of object which it refer to, is the following analysis correct?

let x = 10u8; // lifetime 'a
{
  ...
  let ff;    // lifetime 'b
  ...
  {
    ff = foo(&x);          // while ff has lifetime 'b, it refers to an object of lifetime 'a
    wf = WrapFoo { f: ff } // so wf.f is <'a>Foo<'a> instead of &'b Foo<'b>
  }
...
}
1 Like

Yes &'_ T has Copy.

1 Like