Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a section dedicated to Edition 2024 changes to temporary scopes #1592

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
93 changes: 93 additions & 0 deletions src/destructors.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ smallest scope that contains the expression and is one of the following:
guard.
* The body expression for a match arm.
* The second operand of a [lazy boolean expression].
* *Starting from Edition 2024* the pattern-matching condition and consequent body of [`if let`].
* *Starting from Edition 2024* the entirety of the tail expression of a block.

> **Notes**:
>
Expand Down Expand Up @@ -260,6 +262,97 @@ match PrintOnDrop("Matched value in final expression") {
}
```

#### Changes to temporary scopes by Edition 2024

Edition 2024 introduces two changes to the language regarding temporary scopes.
First, temporary values generated from evaluating the pattern-matching condition
of `if let` will be dropped earlier in general.

```rust,edition2024
struct Droppy(u8);
impl Droppy {
fn get(&self) -> Option<&u8> {
Some(&self.0)
}
}
impl Drop for Droppy {
fn drop(&mut self) {
println!("drop({})", self.0);
}
}

fn call(x: &u8, y: u8, z: &u8) {
println!("call with {x} {y} {z}");
}

let x1 = 0;
let x2 = 3;

call(
if let Some(x) = Droppy(0).get() {
println!("if let consequence");
&x1
} else {
&x2
},
{
let y = Droppy(1);
*y.get().unwrap()
},
Droppy(2).get().unwrap()
);
println!("call ended");
```

This program will print the following.

```text
if let consequence
drop(0)
drop(1)
call with 0 1 2
drop(2)
call ended
```

In other words, `Droppy(0)` is dropped before `Droppy(1)` because its temporary scope is
limited by Edition 2024 to the proper end of the `if let` expression.

Second, temporary values generated from evaluating the tail expression of a block
or a function body will be dropped earlier than the local variable bindings.
The following example demonstrates the Edition 2024 order of events that values
and local variables are dropped.

```rust,edition2024
struct Droppy(u8);
impl Droppy {
fn get(&self) -> Option<&u8> {
Some(&self.0)
}
}
impl Drop for Droppy {
fn drop(&mut self) {
println!("drop({})", self.0);
}
}

fn call() -> u8 {
let x = Droppy(0);
*x.get() + *Droppy(1).get()
}

call();
```

The print-out from this program will be the following.

```text
drop(1)
drop(0)
```

In other words, `Droppy(1)` is dropped earlier than `x`.

### Operands

r[destructors.scope.operands]
Expand Down
Loading