@@ -434,9 +434,9 @@ expression which is one of the following:
434
434
expression] , [ braced struct] [ struct expression ] , or [ tuple] [ tuple expression ]
435
435
expression.
436
436
* 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.
440
440
441
441
So the borrow expressions in ` &mut 0 ` , ` (&1, &mut 2) ` , and ` Some(&mut 3) `
442
442
are all extending expressions. The borrows in ` &0 + &1 ` and ` f(&mut 0) ` are not.
@@ -448,42 +448,92 @@ extended.
448
448
449
449
Here are some examples where expressions have extended temporary scopes:
450
450
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.
456
458
# 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.
458
462
# x;
459
- let x = (& * & temp (),);
463
+ let x = (&*&temp(),); // Operand of tuple constructor.
460
464
# x;
461
- let x = { [Some (& temp ()) ] };
465
+ let x = { [Some(&temp())] }; // Final expr of block.
462
466
# 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.
464
470
# x;
465
471
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.
466
476
# x;
467
- let ref x = temp ();
477
+ let ref x = temp(); // Initializer expression.
468
478
# x;
469
- let ref x = * & temp ();
479
+ let ref x = *&temp(); // Initializer expression.
470
480
# x;
481
+ //
482
+ // All of the temporaries above are still live here.
483
+ # assert_eq!(X.load(Relaxed), 0);
471
484
```
472
485
473
486
Here are some examples where expressions don't have extended temporary scopes:
474
487
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
476
497
# fn temp() {}
477
498
# trait Use { fn use_temp(&self) -> &Self { self } }
478
499
# 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
+ ```
481
511
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
483
516
# 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
485
523
# 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
487
537
# x;
488
538
```
489
539
@@ -544,6 +594,7 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
544
594
[ tuple variant ] : type.enum.declaration
545
595
546
596
[ array expression ] : expressions/array-expr.md#array-expressions
597
+ [ async block expression ] : expr.block.async
547
598
[ block expression ] : expressions/block-expr.md
548
599
[ borrow expression ] : expressions/operator-expr.md#borrow-operators
549
600
[ cast expression ] : expressions/operator-expr.md#type-cast-expressions
0 commit comments