I read this 5 times and still didn't know what it was supposed to tell me. Thankfully, @m-ou-se came to the rescue. :)
Temporary lifetime extension today always involves: a let statement, a & borrow expression in there, a temporary (e.g. temp()) inside of that.
trivial example is let a = &temp();
There is a set of operations that you can put between the let and &: borrow, cast, tuple expression, braced struct expression, array expression, or block expression. e.g. let a = {[(&temp() as _,)]}; will extend temp().
There is a set of operations that you can put between the & and the temporary: borrow, dereference, field, tuple index, or index expression. e.g. let a = &temp().field.0[1]; will extend temp().
combined example is let a = Some { 0: &temp().field };
So the algorithm is: from the initializer expression, traverse through borrows, cast, tuple, braced struct, array, block until we hit an &. Then traverse further through place projections. Then extend that.
The docs currently describe the inner part first. Also it is not clear what it means that "if a field expression has extended scope then so does its operand" -- really it's the operand that gets lifetime extended, and then the field of course inherits the lifetime from its base place.
And finally I think the location in the docs where this is discussed is confusing: this is explained in the page about destructors, but lifetime extension is relevant even without drop -- like when one creates a raw pointer to some memory and then later needs to be sure the memory the pointer points to is still live.
See here for some context:
The reference says about lifetime extension
I read this 5 times and still didn't know what it was supposed to tell me. Thankfully, @m-ou-se came to the rescue. :)
So the algorithm is: from the initializer expression, traverse through borrows, cast, tuple, braced struct, array, block until we hit an
&
. Then traverse further through place projections. Then extend that.The docs currently describe the inner part first. Also it is not clear what it means that "if a field expression has extended scope then so does its operand" -- really it's the operand that gets lifetime extended, and then the field of course inherits the lifetime from its base place.
And finally I think the location in the docs where this is discussed is confusing: this is explained in the page about destructors, but lifetime extension is relevant even without
drop
-- like when one creates a raw pointer to some memory and then later needs to be sure the memory the pointer points to is still live.