Skip to content

Commit 4095838

Browse files
committed
Revise text on built-in macro lifetime extension
Rather than discussing the built-in macros directly in the context of extending expressions, and inspired by our section on implicit borrows, let's instead add a concept of "borrow macro call expressions". We'll then treat extending borrow macro call expressions as extending expressions and extend the temporary scope of operands to extending borrow macro call expression. This seems a bit cleaner and better represents the notion that these macros are only special in that they are a kind of borrow expression.
1 parent 64f24fb commit 4095838

File tree

2 files changed

+42
-22
lines changed

2 files changed

+42
-22
lines changed

src/destructors.md

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -398,11 +398,7 @@ println!("{:?}", C);
398398
```
399399

400400
r[destructors.scope.lifetime-extension.sub-expressions]
401-
If a [borrow][borrow expression], [dereference][dereference expression],
402-
[field][field expression], or [tuple indexing expression] has an extended
403-
temporary scope then so does its operand. If an [indexing expression] has an
404-
extended temporary scope then the indexed expression also has an extended
405-
temporary scope.
401+
If a [borrow], [dereference][dereference expression], [field][field expression], or [tuple indexing expression] has an extended temporary scope then so does its operand. If an [indexing expression] has an extended temporary scope then the indexed expression also has an extended temporary scope.
406402

407403
r[destructors.scope.lifetime-extension.patterns]
408404
#### Extending based on patterns
@@ -479,26 +475,20 @@ For a let statement with an initializer, an *extending expression* is an
479475
expression which is one of the following:
480476

481477
* The initializer expression.
482-
* The operand of an extending [borrow expression].
478+
* The operand of an extending [borrow operator] or [borrow macro] call expression.
483479
* The operand(s) of an extending [array][array expression], [cast][cast
484480
expression], [braced struct][struct expression], or [tuple][tuple expression]
485481
expression.
486482
* The arguments to an extending [tuple struct] or [tuple variant] constructor expression.
487483
* The final expression of an extending [block expression] except for an [async block expression].
488484
* The final expression of an extending [`if`] expression's consequent, `else if`, or `else` block.
489485
* An arm expression of an extending [`match`] expression.
490-
* The argument(s) to an extending [`pin!`] or [`format_args!`] [macro invocation] expression.
491486

492487
So the borrow expressions in `&mut 0`, `(&1, &mut 2)`, and `Some(&mut 3)`
493488
are all extending expressions. The borrows in `&0 + &1` and `f(&mut 0)` are not.
494489

495-
r[destructors.scope.lifetime-extension.exprs.borrow]
496-
The operand of any extending borrow expression has its temporary scope
497-
extended.
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.
490+
r[destructors.scope.lifetime-extension.exprs.borrows]
491+
The operand of any extending [borrow operator] or [borrow macro] call expression has its temporary scope extended.
502492

503493
> [!NOTE]
504494
> `rustc` does not treat [array repeat operands] of extending [array] expressions as extending expressions. Whether it should is an open question.
@@ -510,10 +500,10 @@ Any extending [`pin!`] or [`format_args!`] [macro invocation] expression has an
510500
Here are some examples where expressions have extended temporary scopes:
511501

512502
```rust,edition2024
503+
# use core::pin::pin;
513504
# use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
514-
# use std::pin::pin;
515505
# static X: AtomicU64 = AtomicU64::new(0);
516-
# struct S;
506+
# #[derive(Debug)] struct S;
517507
# impl Drop for S { fn drop(&mut self) { X.fetch_add(1, Relaxed); } }
518508
# const fn temp() -> S { S }
519509
let x = &temp(); // Operand of borrow.
@@ -536,7 +526,10 @@ let x = if true { &temp() } else { &temp() };
536526
# x;
537527
let x = match () { _ => &temp() }; // `match` arm expression.
538528
# x;
539-
let x = pin!(&temp()); // Argument to `pin!`.
529+
let x = pin!(temp()); // Operand of borrow macro call expression.
530+
# x;
531+
# // TODO: This needs <https://github.com/rust-lang/rust/pull/145882>.
532+
let x = format_args!("{:?}", temp()); // As above.
540533
# x;
541534
//
542535
// All of the temporaries above are still live here.
@@ -621,14 +614,14 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
621614

622615
[Assignment]: expressions/operator-expr.md#assignment-expressions
623616
[binding modes]: patterns.md#binding-modes
617+
[borrow macro]: expr.borrow-macros
624618
[closure]: types/closure.md
625619
[destructors]: destructors.md
626620
[expression]: expressions.md
627621
[identifier pattern]: patterns.md#identifier-patterns
628622
[initialized]: glossary.md#initialized
629623
[interior mutability]: interior-mutability.md
630624
[lazy boolean expression]: expressions/operator-expr.md#lazy-boolean-operators
631-
[macro invocation]: macros.md#macro-invocation
632625
[non-unwinding ABI boundary]: items/functions.md#unwinding
633626
[panic]: panic.md
634627
[place context]: expressions.md#place-expressions-and-value-expressions
@@ -658,7 +651,8 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
658651
[array repeat operands]: expr.array.repeat-operand
659652
[async block expression]: expr.block.async
660653
[block expression]: expressions/block-expr.md
661-
[borrow expression]: expressions/operator-expr.md#borrow-operators
654+
[borrow operator]: expr.operator.borrow
655+
[borrow]: expr.operator.borrow
662656
[cast expression]: expressions/operator-expr.md#type-cast-expressions
663657
[dereference expression]: expressions/operator-expr.md#the-dereference-operator
664658
[field expression]: expressions/field-expr.md
@@ -675,6 +669,3 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
675669
[`match`]: expressions/match-expr.md
676670
[`while let`]: expressions/loop-expr.md#while-let-patterns
677671
[`while`]: expressions/loop-expr.md#predicate-loops
678-
679-
[`pin!`]: std::pin::pin
680-
[`format_args!`]: core::format_args

src/expressions.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ The following contexts are *place expression* contexts:
175175
* The operand of a field expression.
176176
* The indexed operand of an array indexing expression.
177177
* The operand of any [implicit borrow].
178+
* The operand of any [macro borrow expression].
178179
* The initializer of a [let statement].
179180
* The [scrutinee] of an [`if let`], [`match`][match], or [`while let`]
180181
expression.
@@ -286,6 +287,24 @@ Implicit borrows may be taken in the following expressions:
286287
* Operands of [comparison].
287288
* Left operands of the [compound assignment].
288289

290+
r[expr.borrow-macros]
291+
### Borrow macros
292+
293+
r[expr.borrow-macros.intro]
294+
Calls to certain built-in macros act as [borrow expressions] with respect to some or all of the arguments. These [macro invocations] are *borrow macro call expressions*. The arguments borrowed are the *operands* of these borrow macro call expressions. As with other borrow expressions, these operands are [place expression contexts] and their [temporary scopes] are [extended][destructors.scope.lifetime-extension.exprs].
295+
296+
r[expr.borrow-macros.exprs]
297+
The following are borrow macro call expressions:
298+
299+
- Calls to [`addr_of!`], [`addr_of_mut!`], or [`pin!`].
300+
- Calls to [`format_args!`] with at least one argument following the format string.
301+
302+
r[expr.borrow-macros.operands]
303+
The following are operands of borrow macro call expressions:
304+
305+
- The argument to [`addr_of!`], [`addr_of_mut!`], or [`pin!`].
306+
- Any arguments following the format string to [`format_args!`].
307+
289308
r[expr.overload]
290309
## Overloading Traits
291310

@@ -310,14 +329,19 @@ They are never allowed before:
310329

311330
[`Copy`]: special-types-and-traits.md#copy
312331
[`Drop`]: special-types-and-traits.md#drop
332+
[`addr_of!`]: core::ptr::addr_of
333+
[`addr_of_mut!`]: core::ptr::addr_of_mut
313334
[`if let`]: expressions/if-expr.md#if-let-patterns
335+
[`format_args!`]: core::format_args
336+
[`pin!`]: core::pin::pin
314337
[`Sized`]: special-types-and-traits.md#sized
315338
[`while let`]: expressions/loop-expr.md#while-let-patterns
316339
[array expressions]: expressions/array-expr.md
317340
[array indexing]: expressions/array-expr.md#array-and-slice-indexing-expressions
318341
[assign]: expressions/operator-expr.md#assignment-expressions
319342
[block expressions]: expressions/block-expr.md
320343
[borrow]: expressions/operator-expr.md#borrow-operators
344+
[borrow expressions]: expr.operator.borrow
321345
[call expressions]: expressions/call-expr.md
322346
[comparison]: expressions/operator-expr.md#comparison-operators
323347
[compound assignment]: expressions/operator-expr.md#compound-assignment-expressions
@@ -327,14 +351,18 @@ They are never allowed before:
327351
[field]: expressions/field-expr.md
328352
[functional update]: expressions/struct-expr.md#functional-update-syntax
329353
[implicit borrow]: #implicit-borrows
354+
[implicitly borrow]: expr.implicit-borrows
330355
[implicitly mutably borrowed]: #implicit-borrows
331356
[interior mutability]: interior-mutability.md
332357
[let statement]: statements.md#let-statements
358+
[macro borrow expression]: expr.borrow-macros
359+
[macro invocations]: macro.invocation
333360
[match]: expressions/match-expr.md
334361
[method-call]: expressions/method-call-expr.md
335362
[Mutable `static` items]: items/static-items.md#mutable-statics
336363
[Outer attributes]: attributes.md
337364
[paths]: expressions/path-expr.md
365+
[place expression contexts]: expr.place-value
338366
[promoted]: destructors.md#constant-promotion
339367
[Range]: expressions/range-expr.md
340368
[raw borrow]: expressions/operator-expr.md#raw-borrow-operators
@@ -344,6 +372,7 @@ They are never allowed before:
344372
[static variables]: items/static-items.md
345373
[struct]: expressions/struct-expr.md
346374
[Structs]: expr.struct
375+
[temporary scopes]: destructors.scope.temporary
347376
[Temporary values]: #temporaries
348377
[tuple expressions]: expressions/tuple-expr.md
349378
[Tuple structs]: items.struct.tuple

0 commit comments

Comments
 (0)