Skip to content

Conversation

dianne
Copy link
Contributor

@dianne dianne commented Sep 1, 2025

For convenience of implementation and testing, I've based this on #145838 with #145342's commits cherry-picked in, plus some slight tweaks and additional tests (#145838 (comment)). The real change this PR makes is the final commit.

This implements the temporary lifetime extension semantics I suggested in #145838 (comment), with the goal of making temporary lifetimes and drop order more consistent between extending and non-extending blocks. As a side-effect, this fixes #145784 with hopefully milder regressions than #145838 (in exchange for having much broader surface area).

Roughly, this subjects extending borrows (and super lets) in block tails to extended scopes, using the same rules as let statement initializers. Under this PR,

// This `temp()` is now extended past the block tail in all contexts.
{ &temp() }

now extends the lifetime of temp() to outlive the block tail in Rust 2024 regardless of whether the block is an extending expression in a let statement initializer (in which context it was already extended to outlive the block before this PR). The scoping rules for tails of extending blocks remain the same: extending subexpressions' temporary scopes are extended based on the source of the lifetime extension (e.g. to match the scope of a parent let statement's bindings). For blocks not extended by any other source, extending borrows in the tail expression now share a temporary scope with the result of the block. This can in turn extend nested blocks within blocks' tail expressions:

// This `temp()` is extended past the outer block tail.
// It is now dropped after the reference to it at the `;`.
f({{ &temp() }});

// This context-sensitivity is consistent with `let`:
// This `temp()` was already extended past the outer block.
// It is still dropped after `x` at the end of the block.
let x = {{ &temp() }};

Since this uses the same rules as let, it only applies to extending sub-expressions.

// This `temp()` is still never extended in any context.
{ identity(&temp()) }

I'm opening this as a draft for now to have a separate place to test and discuss it. Before it can be properly reviewed, I think it should have more tests, it should be optimized, it should have a Reference PR to cross-reference, and the commit history should be cleaned up.

@rustbot label +T-lang

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team labels Sep 1, 2025
@rust-log-analyzer

This comment has been minimized.

@rustbot rustbot added the stable-nominated Nominated for backporting to the compiler in the stable channel. label Sep 1, 2025
@dianne
Copy link
Contributor Author

dianne commented Sep 1, 2025

@rustbot label -stable-nominated

I'm not intending to stable-nominate this, at least. Someone else can, but I don't expect it's needed or that it would be accepted.

@rustbot
Copy link
Collaborator

rustbot commented Sep 1, 2025

Error: Label stable-nominated can only be set by Rust team members

Please file an issue on GitHub at triagebot if there's a problem with this bot, or reach out on #triagebot on Zulip.

@rust-log-analyzer

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. stable-nominated Nominated for backporting to the compiler in the stable channel. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

pin!() changed temporary lifetime extension behavior in version 1.88.0 with edition 2024 tail expression temporary scopes
3 participants