4

I have the following code:

#[derive(Debug)]
pub enum List<'a> {
    Nil,
    Cons(i32, &'a List<'a>)
}

{
    let x = Cons(1, &Cons(2, &Nil));
    println!("{:?}", x);
}

It works fine. I don't understand why this code doesn't report any error, isn't the Cons(2, &Nil) dropped before constructing Cons(1, _) ?

Moreover, after I added an empty impl Drop for List, the above code doesn't work any more:

impl<'a> Drop for List<'a> {
    fn drop(&mut self) {

    }
}

It reports errors that borrowed value does not live long enough for Cons(2, _) and Nil.

Why is there such difference between before and after adding impl Drop ?

amlo
  • 105
  • 1
  • 8

1 Answers1

3

Isn't the Cons(2, &Nil) dropped before constructing Cons(1, _)?

If you bind a reference to a temporary, Rust extends the lifetime of the temporary as needed for the binding; see this answer for details.

Why is there such difference between before and after adding impl Drop?

See this comment. The extended lifetime of the temporary matches the lifetime of x in your example. When a struct containing references has no Drop implementation,

it’s permissible for reference and referent to have identical lifetimes: the reference can’t be used unsafely. Introducing a Drop impl to the situation requires the referent to strictly outlive the reference, to ensure there is a clear order in which to run drop methods.

Daniel S.
  • 312
  • 1
  • 8
  • The answer to the first question is incorrect. In the given context there is no [lifetime extension](https://doc.rust-lang.org/1.48.0/reference/destructors.html#temporary-lifetime-extension). The reason this works anyway is [constant promotion](https://doc.rust-lang.org/1.48.0/reference/destructors.html#constant-promotion) – `Nil` gets promoted to a static constant, so the reference has static lifetime. – Sven Marnach Sep 17 '21 at 08:51