Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion docs/authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ See <https://rust-lang.github.io/mdBook/format/theme/syntax-highlighting.html#su

Rust examples are tested via rustdoc, and should include the appropriate annotations:

* `edition2015` or `edition2018` --- If it is edition-specific (see `book.toml` for the default).
* `edition2015`, `edition2018`, etc. --- If it is edition-specific (see `book.toml` for the default).
* `no_run` --- The example should compile successfully, but should not be executed.
* `should_panic` --- The example should compile and run, but produce a panic.
* `compile_fail` --- The example is expected to fail to compile.
* `ignore` --- The example shouldn't be built or tested. This should be avoided if possible. Usually this is only necessary when the testing framework does not support it (such as external crates or modules, or a proc-macro), or it contains pseudo-code which is not valid Rust. An HTML comment such as `<!-- ignore: requires extern crate -->` should be placed before the example to explain why it is ignored.
* `Exxxx` --- If the example is expected to fail to compile with a specific error code, include that code so that rustdoc will check that the expected code is used.

When demonstrating success cases, many such cases may be included in a single code block. For failure cases, however, each example must appear in a separate code block so that the tests can ensure that each case indeed fails and fails with the appropriate error code or codes.

See the [rustdoc documentation] for more detail.

[rustdoc documentation]: https://doc.rust-lang.org/rustdoc/documentation-tests.html
Expand Down
97 changes: 81 additions & 16 deletions src/destructors.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,48 +434,111 @@ 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 final expression of any extending [block expression].
* The final expression of an extending [block expression] except for an [async block expression].
* The final expression of an extending [`if`] expression's consequent, `else if`, or `else` block.
* An arm expression of an extending [`match`] 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.

The operand of any extending borrow expression has its temporary scope
extended.

> [!NOTE]
> `rustc` does not treat [array repeat operands] of extending [array] expressions as extending expressions. Whether it should is an open question.
>
> For details, see [Rust issue #146092](https://github.com/rust-lang/rust/issues/146092).

#### Examples

Here are some examples where expressions have extended temporary scopes:

```rust
# fn temp() {}
// The temporary that stores the result of `temp()` lives in the same scope
// as x in these cases.
let x = &temp();
```rust,edition2024
# use core::sync::atomic::{AtomicU64, Ordering::Relaxed};
# static X: AtomicU64 = AtomicU64::new(0);
# struct S;
# impl Drop for S { fn drop(&mut self) { X.fetch_add(1, Relaxed); } }
# const fn temp() -> S { S }
let x = &temp(); // Operand of borrow.
# x;
let x = &raw const *&temp(); // Operand of raw borrow.
# assert_eq!(X.load(Relaxed), 0);
let x = &temp() as &dyn Send; // Operand of cast.
# x;
let x = (&*&temp(),); // Operand of tuple constructor.
# x;
let x = { [Some(&temp())] }; // Final expr of block.
# x;
let x = const { &temp() }; // Final expr of `const` block.
# x;
let x = &temp() as &dyn Send;
let x = unsafe { &temp() }; // Final expr of `unsafe` block.
# x;
let x = (&*&temp(),);
let x = if true { &temp() } else { &temp() };
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Final exprs of `if`/`else` blocks.
# x;
let x = { [Some(&temp()) ] };
let x = match () { _ => &temp() }; // `match` arm expression.
# x;
let ref x = temp();
let ref x = temp(); // Initializer expression.
# x;
let ref x = *&temp();
let ref x = *&temp(); // Initializer expression.
# x;
//
// All of the temporaries above are still live here.
# assert_eq!(X.load(Relaxed), 0);
```

Here are some examples where expressions don't have extended temporary scopes:

```rust,compile_fail
```rust,compile_fail,E0716
# fn temp() {}
// Arguments to function calls are not extending expressions. The
// temporary is dropped at the semicolon.
let x = core::convert::identity(&temp()); // ERROR
# x;
```

```rust,compile_fail,E0716
# fn temp() {}
# trait Use { fn use_temp(&self) -> &Self { self } }
# impl Use for () {}
// The temporary that stores the result of `temp()` only lives until the
// end of the let statement in these cases.
// Receivers of method calls are not extending expressions.
let x = (&temp()).use_temp(); // ERROR
# x;
```

let x = std::convert::identity(&temp()); // ERROR
```rust,compile_fail,E0716
# fn temp() {}
// Scrutinees of match expressions are not extending expressions.
let x = match &temp() { x => x }; // ERROR
# x;
let x = (&temp()).use_temp(); // ERROR
```

```rust,compile_fail,E0515
# fn temp() {}
// Final expressions of `async` blocks are not extending expressions.
let x = async { &temp() }; // ERROR
# x;
```

```rust,compile_fail,E0515
# fn temp() {}
// Final expressions of closures are not extending expressions.
let x = || &temp(); // ERROR
# x;
```

```rust,compile_fail,E0716
# fn temp() {}
// Operands of loop breaks are not extending expressions.
let x = loop { break &temp() }; // ERROR
# x;
```

```rust,compile_fail,E0716
# fn temp() {}
// Operands of breaks to labels are not extending expressions.
let x = 'a: { break 'a &temp() }; // ERROR
# x;
```

Expand Down Expand Up @@ -536,6 +599,8 @@ There is one additional case to be aware of: when a panic reaches a [non-unwindi
[tuple variant]: type.enum.declaration

[array expression]: expressions/array-expr.md#array-expressions
[array repeat operands]: expr.array.repeat-operand
[async block expression]: expr.block.async
[block expression]: expressions/block-expr.md
[borrow expression]: expressions/operator-expr.md#borrow-operators
[cast expression]: expressions/operator-expr.md#type-cast-expressions
Expand Down