Skip to content

Commit 3b2e90f

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 "macro borrow expressions". We'll then treat extending macro borrow expressions as extending expressions and extend the temporary scope of operands to extending macro borrow 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 3b2e90f

File tree

2 files changed

+41
-22
lines changed

2 files changed

+41
-22
lines changed

src/destructors.md

Lines changed: 12 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] or [macro borrow] 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] or [macro borrow] 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 macro borrow 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.
@@ -628,7 +621,7 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
628621
[initialized]: glossary.md#initialized
629622
[interior mutability]: interior-mutability.md
630623
[lazy boolean expression]: expressions/operator-expr.md#lazy-boolean-operators
631-
[macro invocation]: macros.md#macro-invocation
624+
[macro borrow]: expr.macro-borrows
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,7 @@ 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]: expr.operator.borrow
662655
[cast expression]: expressions/operator-expr.md#type-cast-expressions
663656
[dereference expression]: expressions/operator-expr.md#the-dereference-operator
664657
[field expression]: expressions/field-expr.md
@@ -675,6 +668,3 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
675668
[`match`]: expressions/match-expr.md
676669
[`while let`]: expressions/loop-expr.md#while-let-patterns
677670
[`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.macro-borrows]
291+
### Macro borrow expressions
292+
293+
r[expr.macro-borrows.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 *macro borrow expressions*. The arguments borrowed are the *operands* of these macro borrow 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.macro-borrows.exprs]
297+
The following are macro borrow 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.macro-borrows.operands]
303+
The following are operands of macro borrow 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.macro-borrows
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)