Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Documentation on lifetime extension is confusing (and in a confusing location) #1605

Open
RalfJung opened this issue Sep 9, 2024 · 0 comments

Comments

@RalfJung
Copy link
Member

RalfJung commented Sep 9, 2024

See here for some context:

The reference says about lifetime extension

If a borrow, dereference, field, or tuple indexing expression has an extended temporary scope then so does its operand. If an indexing expression has an extended temporary scope then the indexed expression also has an extended temporary scope.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant