Temporary lifetime extension for blocks by dianne · Pull Request #146098 · rust-lang/rust (original) (raw)
This implements a revised version of 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 consequence, this undoes the breaking change introduced by #145838 (but in exchange has a much larger surface area).
The change this PR hopes to enforce is a general rule: any expression's temporaries should have the same relative drop order regardless of whether the expression is in an extending context or not: let _ = <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">;</mo><mi mathvariant="normal">‘</mi><mi>a</mi><mi>n</mi><mi>d</mi><mi mathvariant="normal">‘</mi><mi>d</mi><mi>r</mi><mi>o</mi><mi>p</mi><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">expr; and drop(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">;</span><span class="mspace" style="margin-right:0.1667em;"></span><span class="mord">‘</span><span class="mord mathnormal">an</span><span class="mord mathnormal">d</span><span class="mord">‘</span><span class="mord mathnormal">d</span><span class="mord mathnormal">ro</span><span class="mord mathnormal">p</span><span class="mopen">(</span></span></span></span>expr); should have the same drop order. To achieve that, this PR applies lifetime extension rules bottom-up, starting from borrow expressions and super let, rather than top-down from let statements and consts/statics. For example:
// 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.
// It is still dropped after x at the end of its scope.
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.
// In Rust 2024, it is dropped at the end of the block tail.
{ identity(&temp()) }
This also applies to if expressions' blocks and to match arms in all editions, since lifetime extension applies to both of them as well and they both drop their non-extended temporaries. This is where breakage from #145838 was observed:
if cond { &temp() } else { &temp() }
now extends temp() to have the same temporary scope as the result of the if expression.
As a further consequence, this makes super let in if expressions' blocks more consistent with block expressions:
if cond() { super let x = temp(); &temp } else { super let x = temp(); &temp }
previously only worked in extending contexts (since the super lets would be extended), and now it works everywhere.
Reference PR: rust-lang/reference#2051
Edition Guide PR: rust-lang/edition-guide#379
@rustbot label +T-lang