Skip to content

Commit c367664

Browse files
committed
Revise and extend text on extending expressions
In particular, let's note that the final expression of an async block expression is not extending; we need to say that as we otherwise say that the final expression of a block expression is extending, and async blocks are ostensibly blocks in our ontology. Let's build the pass tests with Rust 2024 to ensure that we're not relying on the old edition tail expression rule. When talking about an arm of an extending match expression, let's be clear that we're talking about the arm expression. Let's break apart all of the failure tests; otherwise we can't be sure that they're all failing, and let's mark the expected error code for each failure. For each test, let's note the applicable rule for the outermost part of the expression. Let's add some tests to show that the operand of `break` is not extending, as that might be a bit surprising. Let's demonstrate explicitly that raw borrows count as borrows.
1 parent 48587c7 commit c367664

File tree

1 file changed

+71
-20
lines changed

1 file changed

+71
-20
lines changed

src/destructors.md

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,9 @@ expression which is one of the following:
434434
expression], [braced struct][struct expression], or [tuple][tuple expression]
435435
expression.
436436
* The arguments to an extending [tuple struct] or [tuple variant] constructor expression.
437-
* The final expression of any extending [block expression].
438-
* The arm(s) of an extending [`match`] expression.
439-
* The final expressions of an extending [`if`] expression's consequent, `else if`, and `else` blocks.
437+
* The final expression of an extending [block expression] except for an [async block expression].
438+
* The final expression of an extending [`if`] expression's consequent, `else if`, or `else` block.
439+
* An arm expression of an extending [`match`] expression.
440440

441441
So the borrow expressions in `&mut 0`, `(&1, &mut 2)`, and `Some(&mut 3)`
442442
are all extending expressions. The borrows in `&0 + &1` and `f(&mut 0)` are not.
@@ -448,42 +448,92 @@ extended.
448448

449449
Here are some examples where expressions have extended temporary scopes:
450450

451-
```rust
452-
# fn temp() {}
453-
// The temporary that stores the result of `temp()` lives in the same scope
454-
// as x in these cases.
455-
let x = &temp();
451+
```rust,edition2024
452+
# use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
453+
# static X: AtomicU64 = AtomicU64::new(0);
454+
# struct S;
455+
# impl Drop for S { fn drop(&mut self) { X.fetch_add(1, Relaxed); } }
456+
# const fn temp() -> S { S }
457+
let x = &temp(); // Operand of borrow.
456458
# x;
457-
let x = &temp() as &dyn Send;
459+
let x = &raw const *&temp(); // Operand of raw borrow.
460+
# assert_eq!(X.load(Relaxed), 0);
461+
let x = &temp() as &dyn Send; // Operand of cast.
458462
# x;
459-
let x = (&*&temp(),);
463+
let x = (&*&temp(),); // Operand of tuple constructor.
460464
# x;
461-
let x = { [Some(&temp()) ] };
465+
let x = { [Some(&temp())] }; // Final expr of block.
462466
# x;
463-
let x = match () { _ => &temp() };
467+
let x = const { &temp() }; // Final expr of `const` block.
468+
# x;
469+
let x = unsafe { &temp() }; // Final expr of `unsafe` block.
464470
# x;
465471
let x = if true { &temp() } else { &temp() };
472+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
473+
// Final exprs of `if`/`else` blocks.
474+
# x;
475+
let x = match () { _ => &temp() }; // `match` arm expression.
466476
# x;
467-
let ref x = temp();
477+
let ref x = temp(); // Initializer expression.
468478
# x;
469-
let ref x = *&temp();
479+
let ref x = *&temp(); // Initializer expression.
470480
# x;
481+
//
482+
// All of the temporaries above are still live here.
483+
# assert_eq!(X.load(Relaxed), 0);
471484
```
472485

473486
Here are some examples where expressions don't have extended temporary scopes:
474487

475-
```rust,compile_fail
488+
```rust,compile_fail,E0716
489+
# fn temp() {}
490+
// Arguments to function calls are not extending expressions. The
491+
// temporary is dropped at the semicolon.
492+
let x = core::convert::identity(&temp()); // ERROR
493+
# x;
494+
```
495+
496+
```rust,compile_fail,E0716
476497
# fn temp() {}
477498
# trait Use { fn use_temp(&self) -> &Self { self } }
478499
# impl Use for () {}
479-
// The temporary that stores the result of `temp()` only lives until the
480-
// end of the let statement in these cases.
500+
// Receivers of method calls are not extending expressions.
501+
let x = (&temp()).use_temp(); // ERROR
502+
# x;
503+
```
504+
505+
```rust,compile_fail,E0716
506+
# fn temp() {}
507+
// Scrutinees of match expressions are not extending expressions.
508+
let x = match &temp() { x => x }; // ERROR
509+
# x;
510+
```
481511

482-
let x = std::convert::identity(&temp()); // ERROR
512+
```rust,compile_fail,E0515
513+
# fn temp() {}
514+
// Final expressions of `async` blocks are not extending expressions.
515+
let x = async { &temp() }; // ERROR
483516
# x;
484-
let x = (&temp()).use_temp(); // ERROR
517+
```
518+
519+
```rust,compile_fail,E0515
520+
# fn temp() {}
521+
// Final expressions of closures are not extending expressions.
522+
let x = || &temp(); // ERROR
485523
# x;
486-
let x = match &temp() { x => x }; // ERROR
524+
```
525+
526+
```rust,compile_fail,E0716
527+
# fn temp() {}
528+
// Operands of loop breaks are not extending expressions.
529+
let x = loop { break &temp() }; // ERROR
530+
# x;
531+
```
532+
533+
```rust,compile_fail,E0716
534+
# fn temp() {}
535+
// Operands of breaks to labels are not extending expressions.
536+
let x = 'a: { break 'a &temp() }; // ERROR
487537
# x;
488538
```
489539

@@ -544,6 +594,7 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
544594
[tuple variant]: type.enum.declaration
545595

546596
[array expression]: expressions/array-expr.md#array-expressions
597+
[async block expression]: expr.block.async
547598
[block expression]: expressions/block-expr.md
548599
[borrow expression]: expressions/operator-expr.md#borrow-operators
549600
[cast expression]: expressions/operator-expr.md#type-cast-expressions

0 commit comments

Comments
 (0)