How to correctly understand the lifetime of the variable dropped by `StorageDead`

Consider this example Rust Playground

struct W<'a,T>{
	s:&'a T
}
// impl<'a,T> Drop for W<'a,T>{
// 	fn drop(&mut self) {
		
// 	}
// }
fn new<'a,T>(s:&'a T)->W<'a,T>{
	W{s}
}
fn main() {
	let t;
	let i = 0;
	t = new(&i);
}

The drop order of t and i is i first then t according to Destructors - The Rust Reference. t has type W<'c,i32> where i should keep alive until t is dropped.

However, StorageDead(i) should be invoked before drop(t). In this perspective, when we calculate the relevant borrowing for the shallow write of StorageDead(i), &'c i is considered, and such two actions conflict. However, the compiler does not emit any error. What does the compiler specially handle here?

If we uncomment the Drop for W<'a,T>, the expected error will be reported. Logically, whether implementing Drop for W does not affect the destructor order of t and i. How do we interpret this phenomenon?

Some interpretations are that the compiler knows we cannot explicitly reference i when W<'a,T> is dropped because it does not have a nominated Drop implementation, hence the compiler says it's safe to compile this.

However, this interpretation does not start from the perspective of NIL. Is there any more formal interpretation for this example?

Exactly Drop Check - The Rustonomicon . Especially

For a generic type to soundly implement drop, its generics arguments must strictly outlive it.

Rustc knows the drop behavior for concrete types, but not for generic types, which means stricter rules are taken for soundness reason. To relax the limit, see the escape hatch in the link.

1 Like

StorageDead doesn't "use" the lifetime, where as non-trivial destructors do use the lifetime.[1] So the lifetime within the type can end before the StorageDead. (The compiler knows that W's no-op destructor can't examine the borrow. It's analogous to the may_dangle escape hatch @vague referenced.)

I think this is implicit (if not explicit) in the NLL RFC, but I'm not going to go reread it this moment.


  1. For this example anyway, I'm not sure as to particulars of the actual implementation. ↩ī¸Ž

2 Likes

What does this sentence mean? I think W<'a,i32>:'a is true and 'a:'a is true, doesn't it mean 'a outlives 'a?

They mean something like "lifetimes of the type of a value must be valid when Drop::drop runs on said value". However,

  • The statement could be expanded to account for drop glue (non-trivial destructors generally)
  • When W<'a, i32> doesn't have a Drop implementation, it has a trivial (no-op) destructor
    • StorageDead can occur outside of a lifetime in such cases
  • There's also the may_dangle escape hatch

I agree it's oddly worded from a formal point-of-view. Trait-bound wise, it's always the case that TypeConstructor<..>: 'a only if GenericParameter: 'a for all generic parameters. Probably it's some conflation between Rust lifetimes and value liveness.

1 Like

I think this may be a plausible interpretation. However, layer-3-accommodating-dropck does not say too much