Skip to content

Commit f56c9ae

Browse files
authored
Merge pull request #345 from ehuss/2024-tail-temp-failure
Show tail expression temporary example that fails in 2024
2 parents 3b9194c + 60dd130 commit f56c9ae

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

src/rust-2024/temporary-tail-expr-scope.md

+30-3
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@
22

33
## Summary
44

5-
- Temporary values generated in evaluation of the tail expression of a [function] or closure body, or a [block] are now dropped before local variables.
5+
- Temporary values generated in evaluation of the tail expression of a [function] or closure body, or a [block] may now be dropped before local variables, and are sometimes not extended to the next larger temporary scope.
66

77
[function]: ../../reference/items/functions.html
88
[block]: ../../reference/expressions/block-expr.html
99

1010
## Details
1111

12-
The 2024 Edition changes the drop order of [temporary values] in tail expressions. It often comes as a surprise that, before the 2024 Edition, temporary values in tail expressions are dropped later than the local variable bindings, as in the following example:
12+
The 2024 Edition changes the drop order of [temporary values] in tail expressions. It often comes as a surprise that, before the 2024 Edition, temporary values in tail expressions can live longer than the block itself, and are dropped later than the local variable bindings, as in the following example:
1313

1414
[temporary values]: ../../reference/expressions.html#temporaries
1515

@@ -53,10 +53,37 @@ For more information about this error, try `rustc --explain E0597`.
5353

5454
In 2021 the local variable `c` is dropped before the temporary created by `c.borrow()`. The 2024 Edition changes this so that the temporary value `c.borrow()` is dropped first, followed by dropping the local variable `c`, allowing the code to compile as expected.
5555

56-
See the [temporary scope rules] for more information about how temporary scopes are extended. See the [`if let` temporary scope] chapter for a similar change made to `if let` expressions.
56+
### Temporary scope may be narrowed
57+
58+
When a temporary is created in order to evaluate an expression, the temporary is dropped based on the [temporary scope rules]. Those rules define how long the temporary will be kept alive. Before 2024, temporaries from tail expressions of a block would be extended outside of the block to the next temporary scope boundary. In many cases this would be the end of a statement or function body. In 2024, the temporaries of the tail expression may now be dropped immediately at the end of the block (before any local variables in the block).
59+
60+
This narrowing of the temporary scope may cause programs to fail to compile in 2024. For example:
61+
62+
```rust,edition2024,E0716,compile_fail
63+
// This example works in 2021, but fails to compile in 2024.
64+
fn main() {
65+
let x = { &String::from("1234") }.len();
66+
}
67+
```
68+
69+
In this example, in 2021, the temporary `String` is extended outside of the block, past the call to `len()`, and is dropped at the end of the statement. In 2024, it is dropped immediately at the end of the block, causing a compile error about the temporary being dropped while borrowed.
70+
71+
The solution for these kinds of situations is to lift the block expression out to a local variable so that the temporary lives long enough:
72+
73+
```rust,edition2024
74+
fn main() {
75+
let s = { &String::from("1234") };
76+
let x = s.len();
77+
}
78+
```
79+
80+
This particular example takes advantage of [temporary lifetime extension]. Temporary lifetime extension is a set of specific rules which allow temporaries to live longer than they normally would. Because the `String` temporary is behind a reference, the `String` temporary is extended long enough for the next statement to call `len()` on it.
81+
82+
See the [`if let` temporary scope] chapter for a similar change made to temporary scopes of `if let` expressions.
5783

5884
[`if let` temporary scope]: temporary-if-let-scope.md
5985
[temporary scope rules]: ../../reference/destructors.html#temporary-scopes
86+
[temporary lifetime extension]: ../../reference/destructors.html#temporary-lifetime-extension
6087

6188
## Migration
6289

0 commit comments

Comments
 (0)