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