@@ -474,6 +474,7 @@ let &ref x = &*&temp(); // OK
474474r[ destructors.scope.lifetime-extension.exprs]
475475#### Extending based on expressions
476476
477+ r[ destructors.scope.lifetime-extension.exprs.extending]
477478For a let statement with an initializer, an * extending expression* is an
478479expression which is one of the following:
479480
@@ -486,13 +487,19 @@ expression which is one of the following:
486487* The final expression of an extending [ block expression] except for an [ async block expression] .
487488* The final expression of an extending [ ` if ` ] expression's consequent, ` else if ` , or ` else ` block.
488489* An arm expression of an extending [ ` match ` ] expression.
490+ * The argument(s) to an extending [ ` pin! ` ] or [ ` format_args! ` ] [ macro invocation] expression.
489491
490492So the borrow expressions in ` &mut 0 ` , ` (&1, &mut 2) ` , and ` Some(&mut 3) `
491493are all extending expressions. The borrows in ` &0 + &1 ` and ` f(&mut 0) ` are not.
492494
495+ r[ destructors.scope.lifetime-extension.exprs.borrow]
493496The operand of any extending borrow expression has its temporary scope
494497extended.
495498
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+
496503> [ !NOTE]
497504> ` rustc ` does not treat [ array repeat operands] of extending [ array] expressions as extending expressions. Whether it should is an open question.
498505>
@@ -504,6 +511,7 @@ Here are some examples where expressions have extended temporary scopes:
504511
505512``` rust,edition2024
506513# use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
514+ # use std::pin::pin;
507515# static X: AtomicU64 = AtomicU64::new(0);
508516# struct S;
509517# impl Drop for S { fn drop(&mut self) { X.fetch_add(1, Relaxed); } }
@@ -528,6 +536,8 @@ let x = if true { &temp() } else { &temp() };
528536# x;
529537let x = match () { _ => &temp() }; // `match` arm expression.
530538# x;
539+ let x = pin!(&temp()); // Argument to `pin!`.
540+ # x;
531541//
532542// All of the temporaries above are still live here.
533543# 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
618628[ initialized ] : glossary.md#initialized
619629[ interior mutability ] : interior-mutability.md
620630[ lazy boolean expression ] : expressions/operator-expr.md#lazy-boolean-operators
631+ [ macro invocation ] : macros.md#macro-invocation
621632[ non-unwinding ABI boundary ] : items/functions.md#unwinding
622633[ panic ] : panic.md
623634[ 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
664675[ `match` ] : expressions/match-expr.md
665676[ `while let` ] : expressions/loop-expr.md#while-let-patterns
666677[ `while` ] : expressions/loop-expr.md#predicate-loops
678+
679+ [ `pin!` ] : std::pin::pin
680+ [ `format_args!` ] : core::format_args
0 commit comments