From 0a25deacbb059f0a099753f4da410b531715b224 Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 26 Aug 2025 09:09:25 -0700 Subject: [PATCH 1/2] clean up and properly test temporary lifetime extension in doctests - Removes an unused trait and impl from the successful tests. - Adds uses following all tests so they test lifetime extension. --- src/destructors.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/destructors.md b/src/destructors.md index 36e0fe1ed..24ed38e2f 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -448,15 +448,18 @@ Here are some examples where expressions have extended temporary scopes: ```rust # fn temp() {} -# trait Use { fn use_temp(&self) -> &Self { self } } -# impl Use for () {} // The temporary that stores the result of `temp()` lives in the same scope // as x in these cases. let x = &temp(); +# x; let x = &temp() as &dyn Send; +# x; let x = (&*&temp(),); +# x; let x = { [Some(&temp()) ] }; +# x; let ref x = temp(); +# x; let ref x = *&temp(); # x; ``` @@ -471,6 +474,7 @@ Here are some examples where expressions don't have extended temporary scopes: // end of the let statement in these cases. let x = std::convert::identity(&temp()); // ERROR +# x; let x = (&temp()).use_temp(); // ERROR # x; ``` From 53de4aeae48d138b96bea3ef5179aab71381a4ae Mon Sep 17 00:00:00 2001 From: dianne Date: Tue, 26 Aug 2025 08:50:57 -0700 Subject: [PATCH 2/2] specify lifetime extension of `pin!` and `format_args!` arguments --- src/destructors.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/destructors.md b/src/destructors.md index 24ed38e2f..d2b4449be 100644 --- a/src/destructors.md +++ b/src/destructors.md @@ -425,6 +425,7 @@ scope of the initializer expression is extended. r[destructors.scope.lifetime-extension.exprs] #### Extending based on expressions +r[destructors.scope.lifetime-extension.exprs.extending] For a let statement with an initializer, an *extending expression* is an expression which is one of the following: @@ -434,19 +435,26 @@ expression which is one of the following: expression], [braced struct][struct expression], or [tuple][tuple expression] expression. * The arguments to an extending [tuple struct] or [tuple variant] constructor expression. +* The argument(s) to an extending [`pin!`] or [`format_args!`] [macro invocation] expression. * The final expression of any extending [block expression]. So the borrow expressions in `&mut 0`, `(&1, &mut 2)`, and `Some(&mut 3)` are all extending expressions. The borrows in `&0 + &1` and `f(&mut 0)` are not. +r[destructors.scope.lifetime-extension.exprs.borrow] The operand of any extending borrow expression has its temporary scope extended. +r[destructors.scope.lifetime-extension.exprs.macros] +The built-in macros [`pin!`] and [`format_args!`] create temporaries. +Any extending [`pin!`] or [`format_args!`] [macro invocation] expression has an extended temporary scope. + #### Examples Here are some examples where expressions have extended temporary scopes: ```rust +# use std::pin::pin; # fn temp() {} // The temporary that stores the result of `temp()` lives in the same scope // as x in these cases. @@ -456,6 +464,8 @@ let x = &temp() as &dyn Send; # x; let x = (&*&temp(),); # x; +let x = pin!(temp()); +# x; let x = { [Some(&temp()) ] }; # x; let ref x = temp(); @@ -510,6 +520,7 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi [initialized]: glossary.md#initialized [interior mutability]: interior-mutability.md [lazy boolean expression]: expressions/operator-expr.md#lazy-boolean-operators +[macro invocation]: macros.md#macro-invocation [non-unwinding ABI boundary]: items/functions.md#unwinding [panic]: panic.md [place context]: expressions.md#place-expressions-and-value-expressions @@ -554,3 +565,6 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi [`match`]: expressions/match-expr.md [`while let`]: expressions/loop-expr.md#while-let-patterns [`while`]: expressions/loop-expr.md#predicate-loops + +[`pin!`]: std::pin::pin +[`format_args!`]: core::format_args