From b784bf605e4a35dd0dcfe6562796d403e854442c Mon Sep 17 00:00:00 2001 From: TonalidadeHidrica <47710717+TonalidadeHidrica@users.noreply.github.com> Date: Mon, 17 Feb 2025 19:08:42 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=E3=80=8C=E6=9C=AB=E5=B0=BE=E5=BC=8F?= =?UTF-8?q?=E3=81=AE=E4=B8=80=E6=99=82=E3=82=B9=E3=82=B3=E3=83=BC=E3=83=97?= =?UTF-8?q?=E3=80=8D=E3=82=92=E9=80=94=E4=B8=AD=E3=81=BE=E3=81=A7=E7=BF=BB?= =?UTF-8?q?=E8=A8=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rust-2024/temporary-tail-expr-scope.md | 213 +++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 src/rust-2024/temporary-tail-expr-scope.md diff --git a/src/rust-2024/temporary-tail-expr-scope.md b/src/rust-2024/temporary-tail-expr-scope.md new file mode 100644 index 0000000..0cb7989 --- /dev/null +++ b/src/rust-2024/temporary-tail-expr-scope.md @@ -0,0 +1,213 @@ + + +# 末尾式の一時スコープ + + + +## 概要 + + + +- [関数]・クロージャ本体・[ブロック]の末尾式の評価で生成される一時値は、ローカル変数より先にドロップされるようになり、外側の一時スコープまで生き延びない場合があります。 + + + +[関数]: https://doc.rust-lang.org/reference/items/functions.html +[ブロック]: https://doc.rust-lang.org/reference/expressions/block-expr.html + + + +## 詳細 + + + +2024 エディションから、[末尾式] [^1]のドロップ順序が変わります。 +2024 エディションより前の直感的でない挙動として、以下のように、末尾式内の一時値がブロックそのものより長生きして、ローカル変数束縛よりも長生きするというものがありました。 + + + +[末尾式]: https://doc.rust-lang.org/reference/expressions.html#temporaries + + + +```rust,edition2021,compile_fail,E0597 +// 2024 より前 +# use std::cell::RefCell; +fn f() -> usize { + let c = RefCell::new(".."); + c.borrow().len() // error[E0597]: `c` does not live long enough + // 訳: [E0597]: `c` は十分に長生きしません +} +``` + +[^1] 訳注: 関数・クロージャ・ブロックの `{ }` の末尾にある、セミコロン `;` を伴わない式のこと。 + + + +2021 エディションでは以下のようなエラーになりました。 + +```text +error[E0597]: `c` does not live long enough +(訳: エラー[E0597]: `c` は十分に長生きしません) + --> src/lib.rs:4:5 + | +3 | let c = RefCell::new(".."); + | - binding `c` declared here + (訳: 束縛 `c` はここで定義されています) +4 | c.borrow().len() // error[E0597]: `c` does not live long enough + | ^--------- + | | + | borrowed value does not live long enough + (訳: ここで借用される値が十分に長生きしません) + | a temporary with access to the borrow is created here ... + (訳: 値を借用する一時値がここで生成されていますが、…) +5 | } + | - + | | + | `c` dropped here while still borrowed + (訳: `c` が借用中にここでドロップされています) + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, &str>` + | + (訳: …ここでその一時値がドロップされて `Ref<'_, &str>` 型のデストラクタが実行されるとき、借用が使用中である可能性があります) + = note: the temporary is part of an expression at the end of a block; + (訳: 注: この一時値は、ブロック末尾の式の一部です。) + consider forcing this temporary to be dropped sooner, before the block's local variables are dropped + (訳: 当該の一時値がドロップされるタイミングが、ブロック内のローカル変数がドロップされる前になるようにするとよいかもしれません) +help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block +(訳: ヘルプ: 例えば、式の値を一旦新しいローカル変数 `x` に格納し、それをブロック末尾の式とするとよいです) + + | +4 | let x = c.borrow().len(); x // error[E0597]: `c` does not live long enough + | +++++++ +++ + +For more information about this error, try `rustc --explain E0597`. +(訳: 詳細に関しては `rustc --explain E0597` をご参照ください。) +``` + + + +2021 では、ローカル変数 `c` よりも `c.borrow()` で作られた一時値の方が先にドロップされます。 +2024 エディションでこの挙動は変わり、一時値 `c.borrow()` が先にドロップされてからローカル変数 `c` がドロップされるようになり、コードが期待通りコンパイルされるよになりました。 + + + +### 一時スコープ縮小の可能性 + + + +式の評価のために一時値が作られるとき、一時値は[一時スコープのルール]に則ってドロップされます。 +このルールは一時値の生存期間を規定するものです。 +2024 より前では、ブロックの末尾式における一時値は次のスコープ境界まで、もっぱら文・関数の末尾まで生存していました。 +2024 以降では、末尾式内の一時値はブロック終了時に即座に(ブロック内のローカル変数より前に)ドロップされます。 + + + +このように一時スコープが縮小することにより、以下のように 2024 でコンパイルが通らなくなる場合があります。 + + + +```rust,edition2024,E0716,compile_fail +// 2021 ではコンパイルが通るが 2024 だと通らない +fn main() { + let x = { &String::from("1234") }.len(); +} +``` + + + +このコードだと、2021 では一時値 `String` はブロックの外側と `len()` の呼び出しを超えて生存し、文の末尾でドロップされます。2024 ではブロック末尾で即座にドロップされるため、一時値が借用中にドロップされる旨のコンパイルエラーが出ます。 + + + +対処法は、ブロック式をローカル変数に格上げして、一時値が十分長生きするようにすることです。 + +```rust,edition2024 +fn main() { + let s = { &String::from("1234") }; + let x = s.len(); +} +``` + + + + +このコードでは特に、特定の状況下で一時値を本来よりも延命させる、[一時値の延命]ルールを活用しています。 +一時値の `String` が、参照 `&` 下にあるために延命され、次の文で `len()` が呼び出せるようになっています。 + + + +[`if let` の一時スコープ]の節では、`if let` 式の一時スコープによる同様の変更について説明しています。 + + + +[`if let` temporary scope]: temporary-if-let-scope.md +[temporary scope rules]: https://doc.rust-lang.org/reference/destructors.html#temporary-scopes +[temporary lifetime extension]: https://doc.rust-lang.org/reference/destructors.html#temporary-lifetime-extension + +## Migration + +Unfortunately, there are no semantics-preserving rewrites to shorten the lifetime for temporary values in tail expressions[^RFC3606]. The [`tail_expr_drop_order`] lint detects if a temporary value with a custom, non-trivial `Drop` destructor is generated in a tail expression. Warnings from this lint will appear when running `cargo fix --edition`, but will otherwise not automatically make any changes. It is recommended to manually inspect the warnings and determine whether or not you need to make any adjustments. + +If you want to manually inspect these warnings without performing the edition migration, you can enable the lint with: + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(tail_expr_drop_order)] +``` + +[^RFC3606]: Details are documented at [RFC 3606](https://github.com/rust-lang/rfcs/pull/3606) + +[`tail_expr_drop_order`]: ../../rustc/lints/listing/allowed-by-default.html#tail-expr-drop-order From aa4aa58a0e2e4c9b0010fd04c73bca4ae7b9a00b Mon Sep 17 00:00:00 2001 From: TonalidadeHidrica <47710717+TonalidadeHidrica@users.noreply.github.com> Date: Mon, 17 Feb 2025 19:49:40 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E7=BF=BB=E8=A8=B3=E3=82=92=E5=AE=8C?= =?UTF-8?q?=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/rust-2024/temporary-tail-expr-scope.md | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/rust-2024/temporary-tail-expr-scope.md b/src/rust-2024/temporary-tail-expr-scope.md index 0cb7989..5442d99 100644 --- a/src/rust-2024/temporary-tail-expr-scope.md +++ b/src/rust-2024/temporary-tail-expr-scope.md @@ -197,17 +197,47 @@ See the [`if let` temporary scope] chapter for a similar change made to temporar [temporary scope rules]: https://doc.rust-lang.org/reference/destructors.html#temporary-scopes [temporary lifetime extension]: https://doc.rust-lang.org/reference/destructors.html#temporary-lifetime-extension + + +## 移行 + + +残念ながら、コードの意味合いを変えずに末尾式中の一時値の生存期間を短くする書き換え方はありません[^RFC3606]。 +[`tail_expr_drop_order`]リントは、末尾式中の一時値が独自の非自明な `Drop` デストラクタをもつことを検出します。 +`cargo fix --edition` を実行すると警告がでますが、特段の書き換えはなされません。 +プログラマ自身が警告内容を確認し、変更が必要かどうか判断する必要があります。 + + +エディション移行を行わずに警告箇所を確認したい場合は、以下のように記述するとリントを有効化できます。 + +```rust +// クレートのトップレベルに以下を追加すると手動移行できる +#![warn(tail_expr_drop_order)] +``` + + + +[^RFC3606]: 詳細は [RFC 3606](https://github.com/rust-lang/rfcs/pull/3606) に説明されています。 + + +[`tail_expr_drop_order`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#tail-expr-drop-order From 70d90c61b2a660be357aabaac689c4d08adad445 Mon Sep 17 00:00:00 2001 From: TonalidadeHidrica <47710717+TonalidadeHidrica@users.noreply.github.com> Date: Tue, 18 Feb 2025 00:14:38 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=E7=BF=BB=E8=A8=B3=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/SUMMARY.md | 2 +- src/rust-2024/temporary-tail-expr-scope.md | 47 +++++++++++----------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index ab10822..2ce79ce 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -116,7 +116,7 @@ - [Language](rust-2024/language.md) - [RPIT lifetime capture rules](rust-2024/rpit-lifetime-capture.md) - [`if let` temporary scope](rust-2024/temporary-if-let-scope.md) - - [Tail expression temporary scope](rust-2024/temporary-tail-expr-scope.md) + - [末尾式の一時スコープ](rust-2024/temporary-tail-expr-scope.md) - [Match ergonomics reservations](rust-2024/match-ergonomics.md) - [Unsafe `extern` blocks](rust-2024/unsafe-extern.md) - [Unsafe attributes](rust-2024/unsafe-attributes.md) diff --git a/src/rust-2024/temporary-tail-expr-scope.md b/src/rust-2024/temporary-tail-expr-scope.md index 5442d99..edf885c 100644 --- a/src/rust-2024/temporary-tail-expr-scope.md +++ b/src/rust-2024/temporary-tail-expr-scope.md @@ -14,7 +14,7 @@ - Temporary values generated in evaluation of the tail expression of a [function] or closure body, or a [block] may now be dropped before local variables, and are sometimes not extended to the next larger temporary scope. --> -- [関数]・クロージャ本体・[ブロック]の末尾式の評価で生成される一時値は、ローカル変数より先にドロップされるようになり、外側の一時スコープまで生き延びない場合があります。 +- [関数]・クロージャ本体・[ブロック]の末尾式の評価中に生成される一時値は、ローカル変数より先にドロップされるようになり、外側の一時スコープまで生き延びない場合があります。 2024 エディションから、[末尾式] [^1]のドロップ順序が変わります。 -2024 エディションより前の直感的でない挙動として、以下のように、末尾式内の一時値がブロックそのものより長生きして、ローカル変数束縛よりも長生きするというものがありました。 +それ以前の非直感的な挙動として、以下のように、末尾式内の一時値がブロックそのものより長生きして、ローカル変数束縛より後にドロップされるというものがありました。 -2021 エディションでは以下のようなエラーになりました。 +このコードは、2021 エディションでは以下のようなエラーになりました。 ```text error[E0597]: `c` does not live long enough -(訳: エラー[E0597]: `c` は十分に長生きしません) +((訳)エラー[E0597]: `c` は十分に長生きしません) --> src/lib.rs:4:5 | 3 | let c = RefCell::new(".."); | - binding `c` declared here - (訳: 束縛 `c` はここで定義されています) + ((訳)束縛 `c` はここで定義されています) 4 | c.borrow().len() // error[E0597]: `c` does not live long enough | ^--------- | | | borrowed value does not live long enough - (訳: ここで借用される値が十分に長生きしません) + ((訳)ここで借用される値が十分に長生きしません) | a temporary with access to the borrow is created here ... - (訳: 値を借用する一時値がここで生成されていますが、…) + ((訳)値を借用する一時値がここで生成されていますが、...) 5 | } | - | | | `c` dropped here while still borrowed - (訳: `c` が借用中にここでドロップされています) + ((訳) `c` が借用中にここでドロップされています) | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, &str>` | - (訳: …ここでその一時値がドロップされて `Ref<'_, &str>` 型のデストラクタが実行されるとき、借用が使用中である可能性があります) + ((訳)...ここでその一時値がドロップされて `Ref<'_, &str>` 型のデストラクタが実行されるとき、借用が使用中である可能性があります) = note: the temporary is part of an expression at the end of a block; - (訳: 注: この一時値は、ブロック末尾の式の一部です。) + ((訳)注: この一時値は、ブロック末尾の式の一部です。) consider forcing this temporary to be dropped sooner, before the block's local variables are dropped - (訳: 当該の一時値がドロップされるタイミングが、ブロック内のローカル変数がドロップされる前になるようにするとよいかもしれません) + ((訳)当該の一時値が、ブロック内のローカル変数より前にドロップされるようにするとよいかもしれません) help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block -(訳: ヘルプ: 例えば、式の値を一旦新しいローカル変数 `x` に格納し、それをブロック末尾の式とするとよいです) +((訳)ヘルプ: 例えば、式の値を一旦新しいローカル変数 `x` に格納し、それをブロック末尾の式とするとよいです) | 4 | let x = c.borrow().len(); x // error[E0597]: `c` does not live long enough | +++++++ +++ For more information about this error, try `rustc --explain E0597`. -(訳: 詳細に関しては `rustc --explain E0597` をご参照ください。) +((訳)詳細に関しては `rustc --explain E0597` をご参照ください。) ``` @@ -129,14 +129,14 @@ When a temporary is created in order to evaluate an expression, the temporary is 式の評価のために一時値が作られるとき、一時値は[一時スコープのルール]に則ってドロップされます。 このルールは一時値の生存期間を規定するものです。 -2024 より前では、ブロックの末尾式における一時値は次のスコープ境界まで、もっぱら文・関数の末尾まで生存していました。 +2024 より前では、ブロックの末尾式における一時値はそのブロックに収まらず次のスコープ境界まで、もっぱら文・関数の末尾まで生存していました。 2024 以降では、末尾式内の一時値はブロック終了時に即座に(ブロック内のローカル変数より前に)ドロップされます。 -このように一時スコープが縮小することにより、以下のように 2024 でコンパイルが通らなくなる場合があります。 +このような一時スコープの縮小により、以下のように 2024 でコンパイルが通らなくなる場合があります。 - -このコードでは特に、特定の状況下で一時値を本来よりも延命させる、[一時値の延命]ルールを活用しています。 +特にこの例では、特定の状況下で一時値を本来よりも延命させる、[一時値の延命]ルールを活用しています。 一時値の `String` が、参照 `&` 下にあるために延命され、次の文で `len()` が呼び出せるようになっています。 -[`if let` temporary scope]: temporary-if-let-scope.md -[temporary scope rules]: https://doc.rust-lang.org/reference/destructors.html#temporary-scopes -[temporary lifetime extension]: https://doc.rust-lang.org/reference/destructors.html#temporary-lifetime-extension +[`if let` の一時スコープ]: temporary-if-let-scope.md +[一時スコープのルール]: https://doc.rust-lang.org/reference/destructors.html#temporary-scopes +[一時値の延命]: https://doc.rust-lang.org/reference/destructors.html#temporary-lifetime-extension