@@ -474,6 +474,7 @@ let &ref x = &*&temp(); // OK
474
474
r[ destructors.scope.lifetime-extension.exprs]
475
475
#### Extending based on expressions
476
476
477
+ r[ destructors.scope.lifetime-extension.exprs.extending]
477
478
For a let statement with an initializer, an * extending expression* is an
478
479
expression which is one of the following:
479
480
@@ -486,13 +487,19 @@ expression which is one of the following:
486
487
* The final expression of an extending [ block expression] except for an [ async block expression] .
487
488
* The final expression of an extending [ ` if ` ] expression's consequent, ` else if ` , or ` else ` block.
488
489
* An arm expression of an extending [ ` match ` ] expression.
490
+ * The argument(s) to an extending [ ` pin! ` ] or [ ` format_args! ` ] [ macro invocation] expression.
489
491
490
492
So the borrow expressions in ` &mut 0 ` , ` (&1, &mut 2) ` , and ` Some(&mut 3) `
491
493
are all extending expressions. The borrows in ` &0 + &1 ` and ` f(&mut 0) ` are not.
492
494
495
+ r[ destructors.scope.lifetime-extension.exprs.borrow]
493
496
The operand of any extending borrow expression has its temporary scope
494
497
extended.
495
498
499
+ r[ destructors.scope.lifetime-extension.exprs.macros]
500
+ The built-in macros [ ` pin! ` ] and [ ` format_args! ` ] create temporaries.
501
+ Any extending [ ` pin! ` ] or [ ` format_args! ` ] [ macro invocation] expression has an extended temporary scope.
502
+
496
503
> [ !NOTE]
497
504
> ` rustc ` does not treat [ array repeat operands] of extending [ array] expressions as extending expressions. Whether it should is an open question.
498
505
>
@@ -504,6 +511,7 @@ Here are some examples where expressions have extended temporary scopes:
504
511
505
512
``` rust,edition2024
506
513
# use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
514
+ # use std::pin::pin;
507
515
# static X: AtomicU64 = AtomicU64::new(0);
508
516
# struct S;
509
517
# impl Drop for S { fn drop(&mut self) { X.fetch_add(1, Relaxed); } }
@@ -528,6 +536,8 @@ let x = if true { &temp() } else { &temp() };
528
536
# x;
529
537
let x = match () { _ => &temp() }; // `match` arm expression.
530
538
# x;
539
+ let x = pin!(&temp()); // Argument to `pin!`.
540
+ # x;
531
541
//
532
542
// All of the temporaries above are still live here.
533
543
# assert_eq!(0, X.load(Relaxed));
@@ -618,6 +628,7 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
618
628
[ initialized ] : glossary.md#initialized
619
629
[ interior mutability ] : interior-mutability.md
620
630
[ lazy boolean expression ] : expressions/operator-expr.md#lazy-boolean-operators
631
+ [ macro invocation ] : macros.md#macro-invocation
621
632
[ non-unwinding ABI boundary ] : items/functions.md#unwinding
622
633
[ panic ] : panic.md
623
634
[ place context ] : expressions.md#place-expressions-and-value-expressions
@@ -664,3 +675,6 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
664
675
[ `match` ] : expressions/match-expr.md
665
676
[ `while let` ] : expressions/loop-expr.md#while-let-patterns
666
677
[ `while` ] : expressions/loop-expr.md#predicate-loops
678
+
679
+ [ `pin!` ] : std::pin::pin
680
+ [ `format_args!` ] : core::format_args
0 commit comments