diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 5c12430..9d66515 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -1,7 +1,7 @@ -# エディションガイド +# Rust エディションガイド - [Rust 2021](rust-2021/index.md) @@ -68,5 +70,77 @@ - [クロージャはフィールドごとにキャプチャする](rust-2021/disjoint-capture-in-closures.md) - [panic マクロの一貫性](rust-2021/panic-macro-consistency.md) - [構文の予約](rust-2021/reserving-syntax.md) + - [Raw lifetimes](rust-2021/raw-lifetimes.md) - [警告からエラーへの格上げ](rust-2021/warnings-promoted-to-error.md) - [マクロ規則における OR パターン](rust-2021/or-patterns-macro-rules.md) + - [C-string literals](rust-2021/c-string-literals.md) + +## Rust 2024 + + + +- [Rust 2024](rust-2024/index.md) + - [言語](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) + - [Match ergonomics reservations](rust-2024/match-ergonomics.md) + - [Unsafe `extern` blocks](rust-2024/unsafe-extern.md) + - [Unsafe attributes](rust-2024/unsafe-attributes.md) + - [`unsafe_op_in_unsafe_fn` warning](rust-2024/unsafe-op-in-unsafe-fn.md) + - [Disallow references to `static mut`](rust-2024/static-mut-references.md) + - [Never type fallback change](rust-2024/never-type-fallback.md) + - [Macro fragment specifiers](rust-2024/macro-fragment-specifiers.md) + - [Missing macro fragment specifiers](rust-2024/missing-macro-fragment-specifiers.md) + - [`gen` keyword](rust-2024/gen-keyword.md) + - [Reserved syntax](rust-2024/reserved-syntax.md) + - [標準ライブラリ](rust-2024/standard-library.md) + - [Changes to the prelude](rust-2024/prelude.md) + - [Add `IntoIterator` for `Box<[T]>`](rust-2024/intoiterator-box-slice.md) + - [Newly unsafe functions](rust-2024/newly-unsafe-functions.md) + - [Cargo](rust-2024/cargo.md) + - [Cargo: Rust-version aware resolver](rust-2024/cargo-resolver.md) + - [Cargo: Table and key name consistency](rust-2024/cargo-table-key-names.md) + - [Cargo: Reject unused inherited default-features](rust-2024/cargo-inherited-default-features.md) + - [Rustdoc](rust-2024/rustdoc.md) + - [Rustdoc combined tests](rust-2024/rustdoc-doctests.md) + - [Rustdoc nested `include!` change](rust-2024/rustdoc-nested-includes.md) + - [Rustfmt](rust-2024/rustfmt.md) + - [Rustfmt: Style edition](rust-2024/rustfmt-style-edition.md) + - [Rustfmt: Formatting fixes](rust-2024/rustfmt-formatting-fixes.md) + - [Rustfmt: Combine all delimited exprs as last argument](rust-2024/rustfmt-overflow-delimited-expr.md) + - [Rustfmt: Raw identifier sorting](rust-2024/rustfmt-raw-identifier-sorting.md) + - [Rustfmt: Version sorting](rust-2024/rustfmt-version-sorting.md) diff --git a/src/rust-2021/c-string-literals.md b/src/rust-2021/c-string-literals.md new file mode 100644 index 0000000..643d098 --- /dev/null +++ b/src/rust-2021/c-string-literals.md @@ -0,0 +1,74 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# C-string literals + +## Summary + +- Literals of the form `c"foo"` or `cr"foo"` represent a string of type [`&core::ffi::CStr`][CStr]. + +[CStr]: ../../core/ffi/struct.CStr.html + +## Details + +Starting with Rust 1.77, C-strings can be written using C-string literal syntax with the `c` or `cr` prefix. + +Previously, it was challenging to properly produce a valid string literal that could interoperate with C APIs which terminate with a NUL byte. +The [`cstr`] crate was a popular solution, but that required compiling a proc-macro which was quite expensive. +Now, C-strings can be written directly using literal syntax notation, which will generate a value of type [`&core::ffi::CStr`][CStr] which is automatically terminated with a NUL byte. + +```rust,edition2021 +# use core::ffi::CStr; + +assert_eq!(c"hello", CStr::from_bytes_with_nul(b"hello\0").unwrap()); +assert_eq!( + c"byte escapes \xff work", + CStr::from_bytes_with_nul(b"byte escapes \xff work\0").unwrap() +); +assert_eq!( + c"unicode escapes \u{00E6} work", + CStr::from_bytes_with_nul(b"unicode escapes \xc3\xa6 work\0").unwrap() +); +assert_eq!( + c"unicode characters αβγ encoded as UTF-8", + CStr::from_bytes_with_nul( + b"unicode characters \xce\xb1\xce\xb2\xce\xb3 encoded as UTF-8\0" + ) + .unwrap() +); +assert_eq!( + c"strings can continue \ + on multiple lines", + CStr::from_bytes_with_nul(b"strings can continue on multiple lines\0").unwrap() +); +``` + +C-strings do not allow interior NUL bytes (such as with a `\0` escape). + +Similar to regular strings, C-strings also support "raw" syntax with the `cr` prefix. +These raw C-strings do not process backslash escapes which can make it easier to write strings that contain backslashes. +Double-quotes can be included by surrounding the quotes with the `#` character. +Multiple `#` characters can be used to avoid ambiguity with internal `"#` sequences. + +```rust,edition2021 +assert_eq!(cr"foo", c"foo"); +// Number signs can be used to embed interior double quotes. +assert_eq!(cr#""foo""#, c"\"foo\""); +// This requires two #. +assert_eq!(cr##""foo"#"##, c"\"foo\"#"); +// Escapes are not processed. +assert_eq!(cr"C:\foo", c"C:\\foo"); +``` + +See [The Reference] for more details. + +[`cstr`]: https://crates.io/crates/cstr +[The Reference]: ../../reference/tokens.html#c-string-and-raw-c-string-literals + +## Migration + +Migration is only necessary for macros which may have been assuming a sequence of tokens that looks similar to `c"…"` or `cr"…"`, which previous to the 2021 edition would tokenize as two separate tokens, but in 2021 appears as a single token. + +As part of the [syntax reservation] for the 2021 edition, any macro input which may run into this issue should issue a warning from the `rust_2021_prefixes_incompatible_syntax` migration lint. +See that chapter for more detail. + +[syntax reservation]: reserved-syntax.md diff --git a/src/rust-2021/raw-lifetimes.md b/src/rust-2021/raw-lifetimes.md new file mode 100644 index 0000000..dff755d --- /dev/null +++ b/src/rust-2021/raw-lifetimes.md @@ -0,0 +1,49 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Raw lifetimes + +## Summary + +- `'r#ident_or_keyword` is now allowed as a lifetime, which allows using keywords such as `'r#fn`. + +## Details + +Raw lifetimes are introduced in the 2021 edition to support the ability to migrate to newer editions that introduce new keywords. This is analogous to [raw identifiers] which provide the same functionality for identifiers. For example, the 2024 edition introduced the `gen` keyword. Since lifetimes cannot be keywords, this would cause code that use a lifetime `'gen` to fail to compile. Raw lifetimes allow the migration lint to modify those lifetimes to `'r#gen` which do allow keywords. + +In editions prior to 2021, raw lifetimes are parsed as separate tokens. For example `'r#foo` is parsed as three tokens: `'r`, `#`, and `foo`. + +[raw identifiers]: ../../reference/identifiers.html#raw-identifiers + +## Migration + +As a part of the 2021 edition a migration lint, [`rust_2021_prefixes_incompatible_syntax`], has been added in order to aid in automatic migration of Rust 2018 codebases to Rust 2021. + +In order to migrate your code to be Rust 2021 Edition compatible, run: + +```sh +cargo fix --edition +``` + +Should you want or need to manually migrate your code, migration is fairly straight-forward. + +Let's say you have a macro that is defined like so: + +```rust +macro_rules! my_macro { + ($a:tt $b:tt $c:tt) => {}; +} +``` + +In Rust 2015 and 2018 it's legal for this macro to be called like so with no space between the tokens: + +```rust,ignore +my_macro!('r#foo); +``` + +In the 2021 edition, this is now parsed as a single token. In order to call this macro, you must add a space before the identifier like so: + +```rust,ignore +my_macro!('r# foo); +``` + +[`rust_2021_prefixes_incompatible_syntax`]: ../../rustc/lints/listing/allowed-by-default.html#rust-2021-prefixes-incompatible-syntax diff --git a/src/rust-2024/cargo-inherited-default-features.md b/src/rust-2024/cargo-inherited-default-features.md new file mode 100644 index 0000000..c6e036c --- /dev/null +++ b/src/rust-2024/cargo-inherited-default-features.md @@ -0,0 +1,52 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Cargo: Reject unused inherited default-features + +## Summary + +- `default-features = false` is no longer allowed in an inherited workspace dependency if the workspace dependency specifies `default-features = true` (or does not specify `default-features`). + +## Details + +[Workspace inheritance] allows you to specify dependencies in one place (the workspace), and then to refer to those workspace dependencies from within a package. +There was an inadvertent interaction with how `default-features` is specified that is no longer allowed in the 2024 Edition. + +Unless the workspace specifies `default-features = false`, it is no longer allowed to specify `default-features = false` in an inherited package dependency. +For example, with a workspace that specifies: + +```toml +[workspace.dependencies] +regex = "1.10.4" +``` + +The following is now an error: + +```toml +[package] +name = "foo" +version = "1.0.0" +edition = "2024" + +[dependencies] +regex = { workspace = true, default-features = false } # ERROR +``` + +The reason for this change is to avoid confusion when specifying `default-features = false` when the default feature is already enabled, since it has no effect. + +If you want the flexibility of deciding whether or not a dependency enables the default-features of a dependency, be sure to set `default-features = false` in the workspace definition. +Just beware that if you build multiple workspace members at the same time, the features will be unified so that if one member sets `default-features = true` (which is the default if not explicitly set), the default-features will be enabled for all members using that dependency. + +## Migration + +When using `cargo fix --edition`, Cargo will automatically update your `Cargo.toml` file to remove `default-features = false` in this situation. + +If you would prefer to update your `Cargo.toml` manually, check for any warnings when running a build and remove the corresponding entries. +Previous editions should display something like: + +```text +warning: /home/project/Cargo.toml: `default-features` is ignored for regex, +since `default-features` was not specified for `workspace.dependencies.regex`, +this could become a hard error in the future +``` + +[workspace inheritance]: ../../cargo/reference/specifying-dependencies.html#inheriting-a-dependency-from-a-workspace diff --git a/src/rust-2024/cargo-resolver.md b/src/rust-2024/cargo-resolver.md new file mode 100644 index 0000000..e9a22ba --- /dev/null +++ b/src/rust-2024/cargo-resolver.md @@ -0,0 +1,38 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Cargo: Rust-version aware resolver + +## Summary + +- `edition = "2024"` implies `resolver = "3"` in `Cargo.toml` which enables a Rust-version aware dependency resolver. + +## Details + +Since Rust 1.84.0, Cargo has opt-in support for compatibility with +[`package.rust-version`] to be considered when selecting dependency versions +by setting [`resolver.incompatible-rust-version = "fallback"`] in `.cargo/config.toml`. + +Starting in Rust 2024, this will be the default. +That is, writing `edition = "2024"` in `Cargo.toml` will imply `resolver = "3"` +which will imply [`resolver.incompatible-rust-version = "fallback"`]. + +The resolver is a global setting for a [workspace], and the setting is ignored in dependencies. +The setting is only honored for the top-level package of the workspace. +If you are using a [virtual workspace], you will still need to explicitly set the [`resolver` field] +in the `[workspace]` definition if you want to opt-in to the new resolver. + +For more details on how Rust-version aware dependency resolution works, see [the Cargo book](../../cargo/reference/resolver.html#rust-version). + +[`package.rust-version`]: ../../cargo/reference/rust-version.html +[`resolver.incompatible-rust-version = "fallback"`]: ../../cargo/reference/config.html#resolverincompatible-rust-versions +[workspace]: ../../cargo/reference/workspaces.html +[virtual workspace]: ../../cargo/reference/workspaces.html#virtual-workspace +[`resolver` field]: ../../cargo/reference/resolver.html#resolver-versions + +## Migration + +There are no automated migration tools for updating for the new resolver. + +We recommend projects +[verify against the latest dependencies in CI](../../cargo/guide/continuous-integration.html#verifying-latest-dependencies) +to catch bugs in dependencies as soon as possible. diff --git a/src/rust-2024/cargo-table-key-names.md b/src/rust-2024/cargo-table-key-names.md new file mode 100644 index 0000000..cd8833f --- /dev/null +++ b/src/rust-2024/cargo-table-key-names.md @@ -0,0 +1,43 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Cargo: Table and key name consistency + +## Summary + +- Several table and key names in `Cargo.toml` have been removed where there were previously two ways to specify the same thing. + - Removed `[project]`; use `[package]` instead. + - Removed `default_features`; use `default-features` instead. + - Removed `crate_type`; use `crate-type` instead. + - Removed `proc_macro`; use `proc-macro` instead. + - Removed `dev_dependencies`; use `dev-dependencies` instead. + - Removed `build_dependencies`; use `build-dependencies` instead. + +## Details + +Several table and keys names are no longer allowed in the 2024 Edition. +There were two ways to specify these tables or keys, and this helps ensure there is only one way to specify them. + +Some were due to a change in decisions over time, and some were inadvertent implementation artifacts. +In order to avoid confusion, and to enforce a single style for specifying these tables and keys, only one variant is now allowed. + +For example: + +```toml +[dev_dependencies] +rand = { version = "0.8.5", default_features = false } +``` + +Should be changed to: + +```toml +[dev-dependencies] +rand = { version = "0.8.5", default-features = false } +``` + +Notice that the underscores were changed to dashes for `dev_dependencies` and `default_features`. + +## Migration + +When using `cargo fix --edition`, Cargo will automatically update your `Cargo.toml` file to use the preferred table and key names. + +If you would prefer to update your `Cargo.toml` manually, be sure to go through the list above and make sure only the new forms are used. diff --git a/src/rust-2024/cargo.md b/src/rust-2024/cargo.md new file mode 100644 index 0000000..b78b685 --- /dev/null +++ b/src/rust-2024/cargo.md @@ -0,0 +1,7 @@ +# Cargo + + + +以降の節では、2024 エディションでの Cargo へのアップデートについて詳説します。 diff --git a/src/rust-2024/gen-keyword.md b/src/rust-2024/gen-keyword.md new file mode 100644 index 0000000..9656632 --- /dev/null +++ b/src/rust-2024/gen-keyword.md @@ -0,0 +1,59 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# `gen` keyword + +## Summary + +- `gen` is a [reserved keyword]. + +[reserved keyword]: ../../reference/keywords.html#reserved-keywords + +## Details + +The `gen` keyword has been reserved as part of [RFC #3513] to introduce "gen blocks" in a future release of Rust. `gen` blocks will provide a way to make it easier to write certain kinds of iterators. Reserving the keyword now will make it easier to stabilize `gen` blocks before the next edition. + +[RFC #3513]: https://rust-lang.github.io/rfcs/3513-gen-blocks.html + +## Migration + +Introducing the `gen` keyword can cause a problem for any identifiers that are already called `gen`. For example, any variable or function name called `gen` would clash with the new keyword. To overcome this, Rust supports the `r#` prefix for a [raw identifier], which allows identifiers to overlap with keywords. + +The [`keyword_idents_2024`] lint will automatically modify any identifier named `gen` to be `r#gen` so that code continues to work on both editions. This lint is part of the `rust-2024-compatibility` lint group, which will automatically be applied when running `cargo fix --edition`. To migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +For example, this will change: + +```rust +fn gen() { + println!("generating!"); +} + +fn main() { + gen(); +} +``` + +to be: + +```rust +fn r#gen() { + println!("generating!"); +} + +fn main() { + r#gen(); +} +``` + +Alternatively, you can manually enable the lint to find places where `gen` identifiers need to be modified to `r#gen`: + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(keyword_idents_2024)] +``` + +[raw identifier]: ../../reference/identifiers.html#raw-identifiers +[`keyword_idents_2024`]: ../../rustc/lints/listing/allowed-by-default.html#keyword-idents-2024 diff --git a/src/rust-2024/index.md b/src/rust-2024/index.md new file mode 100644 index 0000000..b198c10 --- /dev/null +++ b/src/rust-2024/index.md @@ -0,0 +1,13 @@ +# Rust 2024 + + + +| 情報 | | +| --- | --- | +| RFC | [#3501](https://rust-lang.github.io/rfcs/3501-edition-2024.html) | +| リリースバージョン | 1.85.0 | diff --git a/src/rust-2024/intoiterator-box-slice.md b/src/rust-2024/intoiterator-box-slice.md new file mode 100644 index 0000000..8bef0bc --- /dev/null +++ b/src/rust-2024/intoiterator-box-slice.md @@ -0,0 +1,82 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Add `IntoIterator` for `Box<[T]>` + +## Summary + +- Boxed slices implement [`IntoIterator`] in *all* editions. +- Calls to [`IntoIterator::into_iter`] are *hidden* in editions prior to 2024 when using method call syntax (i.e., `boxed_slice.into_iter()`). So, `boxed_slice.into_iter()` still resolves to `(&(*boxed_slice)).into_iter()` as it has before. +- `boxed_slice.into_iter()` changes meaning to call [`IntoIterator::into_iter`] in Rust 2024. + +[`IntoIterator`]: ../../std/iter/trait.IntoIterator.html +[`IntoIterator::into_iter`]: ../../std/iter/trait.IntoIterator.html#tymethod.into_iter + +## Details + +Until Rust 1.80, `IntoIterator` was not implemented for boxed slices. In prior versions, if you called `.into_iter()` on a boxed slice, the method call would automatically dereference from `Box<[T]>` to `&[T]`, and return an iterator that yielded references of `&T`. For example, the following worked in prior versions: + +```rust +// Example of behavior in previous editions. +let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice(); +// Note: .into_iter() was required in versions older than 1.80 +for x in my_boxed_slice.into_iter() { + // x is of type &u32 in editions prior to 2024 +} +``` + +In Rust 1.80, implementations of `IntoIterator` were added for boxed slices. This allows iterating over elements of the slice by-value instead of by-reference: + +```rust +// NEW as of 1.80, all editions +let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice(); +for x in my_boxed_slice { // notice no need for calling .into_iter() + // x is of type u32 +} +``` + +This example is allowed on all editions because previously this was an error since `for` loops do not automatically dereference like the `.into_iter()` method call does. + +However, this would normally be a breaking change because existing code that manually called `.into_iter()` on a boxed slice would change from having an iterator over references to an iterator over values. To resolve this problem, method calls of `.into_iter()` on boxed slices have edition-dependent behavior. In editions before 2024, it continues to return an iterator over references, and starting in Edition 2024 it returns an iterator over values. + +```rust,edition2024 +// Example of changed behavior in Edition 2024 +let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice(); +// Example of old code that still manually calls .into_iter() +for x in my_boxed_slice.into_iter() { + // x is now type u32 in Edition 2024 +} +``` + +## Migration + +The [`boxed_slice_into_iter`] lint will automatically modify any calls to `.into_iter()` on boxed slices to call `.iter()` instead to retain the old behavior of yielding references. This lint is part of the `rust-2024-compatibility` lint group, which will automatically be applied when running `cargo fix --edition`. To migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +For example, this will change: + +```rust +fn main() { + let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice(); + for x in my_boxed_slice.into_iter() { + // x is of type &u32 + } +} +``` + +to be: + +```rust +fn main() { + let my_boxed_slice: Box<[u32]> = vec![1, 2, 3].into_boxed_slice(); + for x in my_boxed_slice.iter() { + // x is of type &u32 + } +} +``` + +The [`boxed_slice_into_iter`] lint is defaulted to warn on all editions, so unless you have manually silenced the lint, you should already see it before you migrate. + +[`boxed_slice_into_iter`]: ../../rustc/lints/listing/warn-by-default.html#boxed-slice-into-iter diff --git a/src/rust-2024/language.md b/src/rust-2024/language.md new file mode 100644 index 0000000..4e24a21 --- /dev/null +++ b/src/rust-2024/language.md @@ -0,0 +1,11 @@ + + +# 言語 + + + +以降の節では、2024 エディションでの言語へのアップデートについて詳説します。 diff --git a/src/rust-2024/macro-fragment-specifiers.md b/src/rust-2024/macro-fragment-specifiers.md new file mode 100644 index 0000000..eff84f5 --- /dev/null +++ b/src/rust-2024/macro-fragment-specifiers.md @@ -0,0 +1,53 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Macro Fragment Specifiers + +## Summary + +- The `expr` [fragment specifier] now also supports `const` and `_` expressions. +- The `expr_2021` fragment specifier has been added for backwards compatibility. + +[fragment specifier]: ../../reference/macros-by-example.html#metavariables + +## Details + +As new syntax is added to Rust, existing `macro_rules` fragment specifiers are sometimes not allowed to match on the new syntax in order to retain backwards compatibility. Supporting the new syntax in the old fragment specifiers is sometimes deferred until the next edition, which provides an opportunity to update them. + +Indeed this happened with [`const` expressions] added in 1.79 and [`_` expressions] added in 1.59. In the 2021 Edition and earlier, the `expr` fragment specifier does *not* match those expressions. This is because you may have a scenario like: + +```rust,edition2021 +macro_rules! example { + ($e:expr) => { println!("first rule"); }; + (const $e:expr) => { println!("second rule"); }; +} + +fn main() { + example!(const { 1 + 1 }); +} +``` + +Here, in the 2021 Edition, the macro will match the *second* rule. If earlier editions had changed `expr` to match the newly introduced `const` expressions, then it would match the *first* rule, which would be a breaking change. + +In the 2024 Edition, `expr` specifiers now also match `const` and `_` expressions. To support the old behavior, the `expr_2021` fragment specifier has been added which does *not* match the new expressions. + +[`const` expressions]: ../../reference/expressions/block-expr.html#const-blocks +[`_` expressions]: ../../reference/expressions/underscore-expr.html + +## Migration + +The [`edition_2024_expr_fragment_specifier`] lint will change all uses of the `expr` specifier to `expr_2021` to ensure that the behavior of existing macros does not change. The lint is part of the `rust-2024-compatibility` lint group which is included in the automatic edition migration. In order to migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +In *most* cases, you will likely want to keep the `expr` specifier instead, in order to support the new expressions. You will need to review your macro to determine if there are other rules that would otherwise match with `const` or `_` and determine if there is a conflict. If you want the new behavior, just revert any changes made by the lint. + +Alternatively, you can manually enable the lint to find macros where you may need to update the `expr` specifier. + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(edition_2024_expr_fragment_specifier)] +``` + +[`edition_2024_expr_fragment_specifier`]: ../../rustc/lints/listing/allowed-by-default.html#edition-2024-expr-fragment-specifier diff --git a/src/rust-2024/match-ergonomics.md b/src/rust-2024/match-ergonomics.md new file mode 100644 index 0000000..9e203f8 --- /dev/null +++ b/src/rust-2024/match-ergonomics.md @@ -0,0 +1,137 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Match ergonomics reservations + +## Summary + +- Writing `mut`, `ref`, or `ref mut` on a binding is only allowed within a pattern when the pattern leading up to that binding is fully explicit (i.e. when it does not use match ergonomics). + - Put differently, when the default binding mode is not `move`, writing `mut`, `ref`, or `ref mut` on a binding is an error. +- Reference patterns (`&` or `&mut`) are only allowed within the fully-explicit prefix of a pattern. + - Put differently, reference patterns can only match against references in the scrutinee when the default binding mode is `move`. + +## Details + +### Background + +Within `match`, `let`, and other constructs, we match a *pattern* against a *scrutinee*. E.g.: + +```rust +let &[&mut [ref x]] = &[&mut [()]]; // x: &() +// ~~~~~~~~~~~~~~~ ~~~~~~~~~~~~ +// Pattern Scrutinee +``` + +Such a pattern is called fully explicit because it does not elide (i.e. "skip" or "pass") any references within the scrutinee. By contrast, this otherwise-equivalent pattern is not fully explicit: + +```rust +let [[x]] = &[&mut [()]]; // x: &() +``` + +Patterns such as this are said to be using match ergonomics, originally introduced in [RFC 2005][]. + +Under match ergonomics, as we incrementally match a pattern against a scrutinee, we keep track of the default binding mode. This mode can be one of `move`, `ref mut`, or `ref`, and it starts as `move`. When we reach a binding, unless an explicit binding mode is provided, the default binding mode is used to decide the binding's type. + +For example, here we provide an explicit binding mode, causing `x` to be bound by reference: + +```rust +let ref x = (); // &() +``` + +By contrast: + +```rust +let [x] = &[()]; // &() +``` + +Here, in the pattern, we pass the outer shared reference in the scrutinee. This causes the default binding mode to switch from `move` to `ref`. Since there is no explicit binding mode specified, the `ref` binding mode is used when binding `x`. + +[RFC 2005]: https://github.com/rust-lang/rfcs/pull/2005 + +### `mut` restriction + +In Rust 2021 and earlier editions, we allow this oddity: + +```rust,edition2021 +let [x, mut y] = &[(), ()]; // x: &(), mut y: () +``` + +Here, because we pass the shared reference in the pattern, the default binding mode switches to `ref`. But then, in these editions, writing `mut` on the binding resets the default binding mode to `move`. + +This can be surprising as it's not intuitive that mutability should affect the type. + +To leave space to fix this, in Rust 2024 it's an error to write `mut` on a binding when the default binding mode is not `move`. That is, `mut` can only be written on a binding when the pattern (leading up to that binding) is fully explicit. + +In Rust 2024, we can write the above example as: + +```rust +let &[ref x, mut y] = &[(), ()]; // x: &(), mut y: () +``` + +### `ref` / `ref mut` restriction + +In Rust 2021 and earlier editions, we allow: + +```rust,edition2021 +let [ref x] = &[()]; // x: &() +``` + +Here, the `ref` explicit binding mode is redundant, as by passing the shared reference (i.e. not mentioning it in the pattern), the binding mode switches to `ref`. + +To leave space for other language possibilities, we are disallowing explicit binding modes where they are redundant in Rust 2024. We can rewrite the above example as simply: + +```rust +let [x] = &[()]; // x: &() +``` + +### Reference patterns restriction + +In Rust 2021 and earlier editions, we allow this oddity: + +```rust,edition2021 +let [&x, y] = &[&(), &()]; // x: (), y: &&() +``` + +Here, the `&` in the pattern both matches against the reference on `&()` and resets the default binding mode to `move`. This can be surprising because the single `&` in the pattern causes a larger than expected change in the type by removing both layers of references. + +To leave space to fix this, in Rust 2024 it's an error to write `&` or `&mut` in the pattern when the default binding mode is not `move`. That is, `&` or `&mut` can only be written when the pattern (leading up to that point) is fully explicit. + +In Rust 2024, we can write the above example as: + +```rust +let &[&x, ref y] = &[&(), &()]; +``` + +## Migration + +The [`rust_2024_incompatible_pat`][] lint flags patterns that are not allowed in Rust 2024. This lint is part of the `rust-2024-compatibility` lint group which is automatically applied when running `cargo fix --edition`. This lint will automatically convert affected patterns to fully explicit patterns that work correctly in Rust 2024 and in all prior editions. + +To migrate your code to be compatible with Rust 2024, run: + +```sh +cargo fix --edition +``` + +For example, this will convert this... + +```rust,edition2021 +let [x, mut y] = &[(), ()]; +let [ref x] = &[()]; +let [&x, y] = &[&(), &()]; +``` + +...into this: + +```rust +let &[ref x, mut y] = &[(), ()]; +let &[ref x] = &[()]; +let &[&x, ref y] = &[&(), &()]; +``` + +Alternatively, you can manually enable the lint to find patterns that will need to be migrated: + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(rust_2024_incompatible_pat)] +``` + +[`rust_2024_incompatible_pat`]: ../../rustc/lints/listing/allowed-by-default.html#rust-2024-incompatible-pat diff --git a/src/rust-2024/missing-macro-fragment-specifiers.md b/src/rust-2024/missing-macro-fragment-specifiers.md new file mode 100644 index 0000000..1bf989c --- /dev/null +++ b/src/rust-2024/missing-macro-fragment-specifiers.md @@ -0,0 +1,38 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Missing macro fragment specifiers + +## Summary + +- The [`missing_fragment_specifier`] lint is now a hard error. + +[`missing_fragment_specifier`]: ../../rustc/lints/listing/deny-by-default.html#missing-fragment-specifier + +## Details + +The [`missing_fragment_specifier`] lint detects a situation when an **unused** pattern in a `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not followed by a fragment specifier (e.g. `:expr`). This is now a hard error in the 2024 Edition. + +```rust,compile_fail +macro_rules! foo { + () => {}; + ($name) => { }; // ERROR: missing fragment specifier +} + +fn main() { + foo!(); +} +``` + +Calling the macro with arguments that would match a rule with a missing specifier (e.g., `foo!($name)`) is a hard error in all editions. However, simply defining a macro with missing fragment specifiers is not, though we did add a lint in Rust 1.17. + +We'd like to make this a hard error in all editions, but there would be too much breakage right now. So we're starting by making this a hard error in Rust 2024.[^future-incompat] + +[^future-incompat]: The lint is marked as a "future-incompatible" warning to indicate that it may become a hard error in all editions in a future release. See [#40107] for more information. + +[#40107]: https://github.com/rust-lang/rust/issues/40107 + +## Migration + +To migrate your code to the 2024 Edition, remove the unused matcher rule from the macro. The [`missing_fragment_specifier`] lint is on by default in all editions, and should alert you to macros with this issue. + +There is no automatic migration for this change. We expect that this style of macro is extremely rare. The lint has been a future-incompatibility lint since Rust 1.17, a deny-by-default lint since Rust 1.20, and since Rust 1.82, it has warned about dependencies that are using this pattern. diff --git a/src/rust-2024/never-type-fallback.md b/src/rust-2024/never-type-fallback.md new file mode 100644 index 0000000..8b8e8f3 --- /dev/null +++ b/src/rust-2024/never-type-fallback.md @@ -0,0 +1,158 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Never type fallback change + +## Summary + +- Never type (`!`) to any type ("never-to-any") coercions fall back to never type (`!`) rather than to unit type (`()`). +- The [`never_type_fallback_flowing_into_unsafe`] lint is now `deny` by default. + +[`never_type_fallback_flowing_into_unsafe`]: ../../rustc/lints/listing/warn-by-default.html#never-type-fallback-flowing-into-unsafe + +## Details + +When the compiler sees a value of type `!` (never) in a [coercion site][], it implicitly inserts a coercion to allow the type checker to infer any type: + +```rust,should_panic +# #![feature(never_type)] +// This: +let x: u8 = panic!(); + +// ...is (essentially) turned by the compiler into: +let x: u8 = absurd(panic!()); + +// ...where `absurd` is the following function +// (it's sound because `!` always marks unreachable code): +fn absurd(x: !) -> T { x } +``` + +This can lead to compilation errors if the type cannot be inferred: + +```rust,compile_fail,E0282 +# #![feature(never_type)] +# fn absurd(x: !) -> T { x } +// This: +{ panic!() }; + +// ...gets turned into this: +{ absurd(panic!()) }; //~ ERROR can't infer the type of `absurd` +``` + +To prevent such errors, the compiler remembers where it inserted `absurd` calls, and if it can't infer the type, it uses the fallback type instead: + +```rust,should_panic +# #![feature(never_type)] +# fn absurd(x: !) -> T { x } +type Fallback = /* An arbitrarily selected type! */ !; +{ absurd::(panic!()) } +``` + +This is what is known as "never type fallback". + +Historically, the fallback type has been `()` (unit). This caused `!` to spontaneously coerce to `()` even when the compiler would not infer `()` without the fallback. That was confusing and has prevented the stabilization of the `!` type. + +In the 2024 edition, the fallback type is now `!`. (We plan to make this change across all editions at a later date.) This makes things work more intuitively. Now when you pass `!` and there is no reason to coerce it to something else, it is kept as `!`. + +In some cases your code might depend on the fallback type being `()`, so this can cause compilation errors or changes in behavior. + +[coercion site]: ../../reference/type-coercions.html#coercion-sites + +### `never_type_fallback_flowing_into_unsafe` + +The default level of the [`never_type_fallback_flowing_into_unsafe`] lint has been raised from `warn` to `deny` in the 2024 Edition. This lint helps detect a particular interaction with the fallback to `!` and `unsafe` code which may lead to undefined behavior. See the link for a complete description. + +## Migration + +There is no automatic fix, but there is automatic detection of code that will be broken by the edition change. While still on a previous edition you will see warnings if your code will be broken. + +The fix is to specify the type explicitly so that the fallback type is not used. Unfortunately, it might not be trivial to see which type needs to be specified. + +One of the most common patterns broken by this change is using `f()?;` where `f` is generic over the `Ok`-part of the return type: + +```rust +# #![allow(dependency_on_unit_never_type_fallback)] +# fn outer(x: T) -> Result { +fn f() -> Result { + Ok(T::default()) +} + +f()?; +# Ok(x) +# } +``` + +You might think that, in this example, type `T` can't be inferred. However, due to the current desugaring of the `?` operator, it was inferred as `()`, and it will now be inferred as `!`. + +To fix the issue you need to specify the `T` type explicitly: + +```rust,edition2024 +# #![deny(dependency_on_unit_never_type_fallback)] +# fn outer(x: T) -> Result { +# fn f() -> Result { +# Ok(T::default()) +# } +f::<()>()?; +// ...or: +() = f()?; +# Ok(x) +# } +``` + +Another relatively common case is panicking in a closure: + +```rust,should_panic +# #![allow(dependency_on_unit_never_type_fallback)] +trait Unit {} +impl Unit for () {} + +fn run(f: impl FnOnce() -> R) { + f(); +} + +run(|| panic!()); +``` + +Previously `!` from the `panic!` coerced to `()` which implements `Unit`. However now the `!` is kept as `!` so this code fails because `!` doesn't implement `Unit`. To fix this you can specify the return type of the closure: + +```rust,edition2024,should_panic +# #![deny(dependency_on_unit_never_type_fallback)] +# trait Unit {} +# impl Unit for () {} +# +# fn run(f: impl FnOnce() -> R) { +# f(); +# } +run(|| -> () { panic!() }); +``` + +A similar case to that of `f()?` can be seen when using a `!`-typed expression in one branch and a function with an unconstrained return type in the other: + +```rust +# #![allow(dependency_on_unit_never_type_fallback)] +if true { + Default::default() +} else { + return +}; +``` + +Previously `()` was inferred as the return type of `Default::default()` because `!` from `return` was spuriously coerced to `()`. Now, `!` will be inferred instead causing this code to not compile because `!` does not implement `Default`. + +Again, this can be fixed by specifying the type explicitly: + +```rust,edition2024 +# #![deny(dependency_on_unit_never_type_fallback)] +() = if true { + Default::default() +} else { + return +}; + +// ...or: + +if true { + <() as Default>::default() +} else { + return +}; +``` diff --git a/src/rust-2024/newly-unsafe-functions.md b/src/rust-2024/newly-unsafe-functions.md new file mode 100644 index 0000000..b49ed46 --- /dev/null +++ b/src/rust-2024/newly-unsafe-functions.md @@ -0,0 +1,78 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Unsafe functions + +## Summary + +- The following functions are now marked [`unsafe`]: + - [`std::env::set_var`] + - [`std::env::remove_var`] + - [`std::os::unix::process::CommandExt::before_exec`] + +[`unsafe`]: ../../reference/unsafe-keyword.html#unsafe-functions-unsafe-fn +[`std::env::set_var`]: ../../std/env/fn.set_var.html +[`std::env::remove_var`]: ../../std/env/fn.remove_var.html +[`std::os::unix::process::CommandExt::before_exec`]: ../../std/os/unix/process/trait.CommandExt.html#method.before_exec + +## Details + +Over time it has become evident that certain functions in the standard library should have been marked as `unsafe`. However, adding `unsafe` to a function can be a breaking change since it requires existing code to be placed in an `unsafe` block. To avoid the breaking change, these functions are marked as `unsafe` starting in the 2024 Edition, while not requiring `unsafe` in previous editions. + +### `std::env::{set_var, remove_var}` + +It can be unsound to call [`std::env::set_var`] or [`std::env::remove_var`] in a multi-threaded program due to safety limitations of the way the process environment is handled on some platforms. The standard library originally defined these as safe functions, but it was later determined that was not correct. + +It is important to ensure that these functions are not called when any other thread might be running. See the [Safety] section of the function documentation for more details. + +[Safety]: ../../std/env/fn.set_var.html#safety + +### `std::os::unix::process::CommandExt::before_exec` + +The [`std::os::unix::process::CommandExt::before_exec`] function is a unix-specific function which provides a way to run a closure before calling `exec`. This function was deprecated in the 1.37 release, and replaced with [`pre_exec`] which does the same thing, but is marked as `unsafe`. + +Even though `before_exec` is deprecated, it is now correctly marked as `unsafe` starting in the 2024 Edition. This should help ensure that any legacy code which has not already migrated to `pre_exec` to require an `unsafe` block. + +There are very strict safety requirements for the `before_exec` closure to satisfy. See the [Safety section][pre-exec-safety] for more details. + +[`pre_exec`]: ../../std/os/unix/process/trait.CommandExt.html#tymethod.pre_exec +[pre-exec-safety]: ../../std/os/unix/process/trait.CommandExt.html#notes-and-safety + +## Migration + +To make your code compile in both the 2021 and 2024 editions, you will need to make sure that these functions are called only from within `unsafe` blocks. + +**⚠ Caution**: It is important that you manually inspect the calls to these functions and possibly rewrite your code to satisfy the preconditions of those functions. In particular, `set_var` and `remove_var` should not be called if there might be multiple threads running. You may need to elect to use a different mechanism other than environment variables to manage your use case. + +The [`deprecated_safe_2024`] lint will automatically modify any use of these functions to be wrapped in an `unsafe` block so that it can compile on both editions. This lint is part of the `rust-2024-compatibility` lint group, which will automatically be applied when running `cargo fix --edition`. To migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +For example, this will change: + +```rust +fn main() { + std::env::set_var("FOO", "123"); +} +``` + +to be: + +```rust +fn main() { + // TODO: Audit that the environment access only happens in single-threaded code. + unsafe { std::env::set_var("FOO", "123") }; +} +``` + +Just beware that this automatic migration will not be able to verify that these functions are being used correctly. It is still your responsibility to manually review their usage. + +Alternatively, you can manually enable the lint to find places these functions are called: + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(deprecated_safe_2024)] +``` + +[`deprecated_safe_2024`]: ../../rustc/lints/listing/allowed-by-default.html#deprecated-safe-2024 diff --git a/src/rust-2024/prelude.md b/src/rust-2024/prelude.md new file mode 100644 index 0000000..46f7816 --- /dev/null +++ b/src/rust-2024/prelude.md @@ -0,0 +1,106 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Changes to the prelude + +## Summary + +- The [`Future`] and [`IntoFuture`] traits are now part of the prelude. +- This might make calls to trait methods ambiguous which could make some code fail to compile. +- `RustcEncodable` and `RustcDecodable` have been removed from the prelude. + +[`Future`]: ../../std/future/trait.Future.html +[`IntoFuture`]: ../../std/future/trait.IntoFuture.html + +## Details + +The [prelude of the standard library](../../std/prelude/index.html) is the module containing everything that is automatically imported in every module. +It contains commonly used items such as `Option`, `Vec`, `drop`, and `Clone`. + +The Rust compiler prioritizes any manually imported items over those from the prelude, +to make sure additions to the prelude will not break any existing code. +For example, if you have a crate or module called `example` containing a `pub struct Option;`, +then `use example::*;` will make `Option` unambiguously refer to the one from `example`; +not the one from the standard library. + +However, adding a _trait_ to the prelude can break existing code in a subtle way. +For example, a call to `x.poll()` which comes from a `MyPoller` trait might fail to compile if `std`'s `Future` is also imported, because the call to `poll` is now ambiguous and could come from either trait. + +As a solution, Rust 2024 will use a new prelude. +It's identical to the current one, except for the following changes: + +- Added: + - [`std::future::Future`][`Future`] + - [`std::future::IntoFuture`][`IntoFuture`] +- Removed: + - `RustcEncodable` + - `RustcDecodable` + +### `RustcEncodable` and `RustcDecodable` removal + +`RustcEncodable` and `RustcDecodable` are two undocumented derive macros that have been removed from the prelude. +These were deprecated before Rust 1.0, but remained within the standard library prelude. +The 2024 Edition has removed these from the prelude since they are not expected to be used. + +If in the unlikely case there is a project still using these, it is recommended to switch to a serialization library, such as those found on [crates.io]. + +[crates.io]: https://crates.io/categories/encoding + +## Migration + +### Conflicting trait methods + +When two traits that are in scope have the same method name, it is ambiguous which trait method should be used. For example: + +```rust,edition2021 +trait MyPoller { + // This name is the same as the `poll` method on the `Future` trait from `std`. + fn poll(&self) { + println!("polling"); + } +} + +impl MyPoller for T {} + +fn main() { + // Pin<&mut async {}> implements both `std::future::Future` and `MyPoller`. + // If both traits are in scope (as would be the case in Rust 2024), + // then it becomes ambiguous which `poll` method to call + core::pin::pin!(async {}).poll(); +} +``` + +We can fix this so that it works on all editions by using fully qualified syntax: + +```rust,ignore +fn main() { + // Now it is clear which trait method we're referring to + <_ as MyPoller>::poll(&core::pin::pin!(async {})); +} +``` + +The [`rust_2024_prelude_collisions`] lint will automatically modify any ambiguous method calls to use fully qualified syntax. This lint is part of the `rust-2024-compatibility` lint group, which will automatically be applied when running `cargo fix --edition`. To migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +Alternatively, you can manually enable the lint to find places where these qualifications need to be added: + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(rust_2024_prelude_collisions)] +``` + +[`rust_2024_prelude_collisions`]: ../../rustc/lints/listing/allowed-by-default.html#rust-2024-prelude-collisions + +### `RustcEncodable` and `RustcDecodable` + +It is strongly recommended that you migrate to a different serialization library if you are still using these. +However, these derive macros are still available in the standard library, they are just required to be imported from the older prelude now: + +```rust,edition2021 +#[allow(soft_unstable)] +use core::prelude::v1::{RustcDecodable, RustcEncodable}; +``` + +There is no automatic migration for this change; you will need to make the update manually. diff --git a/src/rust-2024/reserved-syntax.md b/src/rust-2024/reserved-syntax.md new file mode 100644 index 0000000..2193cbf --- /dev/null +++ b/src/rust-2024/reserved-syntax.md @@ -0,0 +1,65 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Reserved syntax + +## Summary + +- Unprefixed guarded strings of the form `#"foo"#` are reserved for future use. +- Two or more `#` characters are reserved for future use. + +## Details + +[RFC 3593] reserved syntax in the 2024 Edition for guarded string literals that do not have a prefix to make room for possible future language changes. The 2021 Edition [reserved syntax][2021] for guarded strings with a prefix, such as `ident##"foo"##`. The 2024 Edition extends that to also reserve strings without the `ident` prefix. + +There are two reserved syntaxes: + +- One or more `#` characters immediately followed by a [string literal]. +- Two or more `#` characters in a row (not separated by whitespace). + +This reservation is done across an edition boundary because of interactions with tokenization and macros. For example, consider this macro: + +```rust +macro_rules! demo { + ( $a:tt ) => { println!("one token") }; + ( $a:tt $b:tt $c:tt ) => { println!("three tokens") }; +} + +demo!("foo"); +demo!(r#"foo"#); +demo!(#"foo"#); +demo!(###) +``` + +Prior to the 2024 Edition, this produces: + +```text +one token +one token +three tokens +three tokens +``` + +Starting in the 2024 Edition, the `#"foo"#` line and the `###` line now generates a compile error because those forms are now reserved. + +[2021]: ../rust-2021/reserved-syntax.md +[string literal]: ../../reference/tokens.html#string-literals +[RFC 3593]: https://rust-lang.github.io/rfcs/3593-unprefixed-guarded-strings.html + +## Migration + +The [`rust_2024_guarded_string_incompatible_syntax`] lint will identify any tokens that match the reserved syntax, and will suggest a modification to insert spaces where necessary to ensure the tokens continue to be parsed separately. + +The lint is part of the `rust-2024-compatibility` lint group which is included in the automatic edition migration. In order to migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +Alternatively, you can manually enable the lint to find macro calls where you may need to update the tokens: + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(rust_2024_guarded_string_incompatible_syntax)] +``` + +[`rust_2024_guarded_string_incompatible_syntax`]: ../../rustc/lints/listing/allowed-by-default.html#rust-2024-guarded-string-incompatible-syntax diff --git a/src/rust-2024/rpit-lifetime-capture.md b/src/rust-2024/rpit-lifetime-capture.md new file mode 100644 index 0000000..f101e10 --- /dev/null +++ b/src/rust-2024/rpit-lifetime-capture.md @@ -0,0 +1,298 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# RPIT lifetime capture rules + +This chapter describes changes related to the **Lifetime Capture Rules 2024** introduced in [RFC 3498], including how to use opaque type *precise capturing* (introduced in [RFC 3617]) to migrate your code. + +[RFC 3498]: https://github.com/rust-lang/rfcs/pull/3498 +[RFC 3617]: https://github.com/rust-lang/rfcs/pull/3617 + +## Summary + +- In Rust 2024, *all* in-scope generic parameters, including lifetime parameters, are implicitly captured when the `use<..>` bound is not present. +- Uses of the `Captures` trick (`Captures<..>` bounds) and of the outlives trick (e.g. `'_` bounds) can be replaced by `use<..>` bounds (in all editions) or removed entirely (in Rust 2024). + +## Details + +### Capturing + +*Capturing* a generic parameter in an RPIT (return-position impl Trait) opaque type allows for that parameter to be used in the corresponding hidden type. In Rust 1.82, we added `use<..>` bounds that allow specifying explicitly which generic parameters to capture. Those will be helpful for migrating your code to Rust 2024, and will be helpful in this chapter for explaining how the edition-specific implicit capturing rules work. These `use<..>` bounds look like this: + +```rust +# #![feature(precise_capturing)] +fn capture<'a, T>(x: &'a (), y: T) -> impl Sized + use<'a, T> { + // ~~~~~~~~~~~~~~~~~~~~~~~ + // This is the RPIT opaque type. + // + // It captures `'a` and `T`. + (x, y) + //~~~~~~ + // The hidden type is: `(&'a (), T)`. + // + // This type can use `'a` and `T` because they were captured. +} +``` + +The generic parameters that are captured affect how the opaque type can be used. E.g., this is an error because the lifetime is captured despite the fact that the hidden type does not use the lifetime: + +```rust,compile_fail +# #![feature(precise_capturing)] +fn capture<'a>(_: &'a ()) -> impl Sized + use<'a> {} + +fn test<'a>(x: &'a ()) -> impl Sized + 'static { + capture(x) + //~^ ERROR lifetime may not live long enough +} +``` + +Conversely, this is OK: + +```rust +# #![feature(precise_capturing)] +fn capture<'a>(_: &'a ()) -> impl Sized + use<> {} + +fn test<'a>(x: &'a ()) -> impl Sized + 'static { + capture(x) //~ OK +} +``` + +### Edition-specific rules when no `use<..>` bound is present + +If the `use<..>` bound is not present, then the compiler uses edition-specific rules to decide which in-scope generic parameters to capture implicitly. + +In all editions, all in-scope type and const generic parameters are captured implicitly when the `use<..>` bound is not present. E.g.: + +```rust +# #![feature(precise_capturing)] +fn f_implicit() -> impl Sized {} +// ~~~~~~~~~~ +// No `use<..>` bound is present here. +// +// In all editions, the above is equivalent to: +fn f_explicit() -> impl Sized + use {} +``` + +In Rust 2021 and earlier editions, when the `use<..>` bound is not present, generic lifetime parameters are only captured when they appear syntactically within a bound in RPIT opaque types in the signature of bare functions and associated functions and methods within inherent impls. However, starting in Rust 2024, these in-scope generic lifetime parameters are unconditionally captured. E.g.: + +```rust +# #![feature(precise_capturing)] +fn f_implicit(_: &()) -> impl Sized {} +// In Rust 2021 and earlier, the above is equivalent to: +fn f_2021(_: &()) -> impl Sized + use<> {} +// In Rust 2024 and later, it's equivalent to: +fn f_2024(_: &()) -> impl Sized + use<'_> {} +``` + +This makes the behavior consistent with RPIT opaque types in the signature of associated functions and methods within trait impls, uses of RPIT within trait definitions (RPITIT), and opaque `Future` types created by `async fn`, all of which implicitly capture all in-scope generic lifetime parameters in all editions when the `use<..>` bound is not present. + +### Outer generic parameters + +Generic parameters from an outer impl are considered to be in scope when deciding what is implicitly captured. E.g.: + +```rust +# #![feature(precise_capturing)] +struct S((T, [(); C])); +impl S { +// ~~~~~~~~~~~~~~~~~ +// These generic parameters are in scope. + fn f_implicit() -> impl Sized {} + // ~ ~~~~~~~~~~ + // ^ This generic is in scope too. + // ^ + // | + // No `use<..>` bound is present here. + // + // In all editions, it's equivalent to: + fn f_explicit() -> impl Sized + use {} +} +``` + +### Lifetimes from higher-ranked binders + +Similarly, generic lifetime parameters introduced into scope by a higher-ranked `for<..>` binder are considered to be in scope. E.g.: + +```rust +# #![feature(precise_capturing)] +trait Tr<'a> { type Ty; } +impl Tr<'_> for () { type Ty = (); } + +fn f_implicit() -> impl for<'a> Tr<'a, Ty = impl Copy> {} +// In Rust 2021 and earlier, the above is equivalent to: +fn f_2021() -> impl for<'a> Tr<'a, Ty = impl Copy + use<>> {} +// In Rust 2024 and later, it's equivalent to: +//fn f_2024() -> impl for<'a> Tr<'a, Ty = impl Copy + use<'a>> {} +// ~~~~~~~~~~~~~~~~~~~~ +// However, note that the capturing of higher-ranked lifetimes in +// nested opaque types is not yet supported. +``` + +### Argument position impl Trait (APIT) + +Anonymous (i.e. unnamed) generic parameters created by the use of APIT (argument position impl Trait) are considered to be in scope. E.g.: + +```rust +# #![feature(precise_capturing)] +fn f_implicit(_: impl Sized) -> impl Sized {} +// ~~~~~~~~~~ +// This is called APIT. +// +// The above is *roughly* equivalent to: +fn f_explicit<_0: Sized>(_: _0) -> impl Sized + use<_0> {} +``` + +Note that the former is not *exactly* equivalent to the latter because, by naming the generic parameter, turbofish syntax can now be used to provide an argument for it. There is no way to explicitly include an anonymous generic parameter in a `use<..>` bound other than by converting it to a named generic parameter. + +## Migration + +### Migrating while avoiding overcapturing + +The `impl_trait_overcaptures` lint flags RPIT opaque types that will capture additional lifetimes in Rust 2024. This lint is part of the `rust-2024-compatibility` lint group which is automatically applied when running `cargo fix --edition`. In most cases, the lint can automatically insert `use<..>` bounds where needed such that no additional lifetimes are captured in Rust 2024. + +To migrate your code to be compatible with Rust 2024, run: + +```sh +cargo fix --edition +``` + +For example, this will change: + +```rust +fn f<'a>(x: &'a ()) -> impl Sized { *x } +``` + +...into: + +```rust +# #![feature(precise_capturing)] +fn f<'a>(x: &'a ()) -> impl Sized + use<> { *x } +``` + +Without this `use<>` bound, in Rust 2024, the opaque type would capture the `'a` lifetime parameter. By adding this bound, the migration lint preserves the existing semantics. + +### Migrating cases involving APIT + +In some cases, the lint cannot make the change automatically because a generic parameter needs to be given a name so that it can appear within a `use<..>` bound. In these cases, the lint will alert you that a change may need to be made manually. E.g., given: + +```rust,edition2021 +fn f<'a>(x: &'a (), y: impl Sized) -> impl Sized { (*x, y) } +// ^^ ~~~~~~~~~~ +// This is a use of APIT. +// +//~^ WARN `impl Sized` will capture more lifetimes than possibly intended in edition 2024 +//~| NOTE specifically, this lifetime is in scope but not mentioned in the type's bounds +# +# fn test<'a>(x: &'a (), y: ()) -> impl Sized + 'static { +# f(x, y) +# } +``` + +The code cannot be converted automatically because of the use of APIT and the fact that the generic type parameter must be named in the `use<..>` bound. To convert this code to Rust 2024 without capturing the lifetime, you must name that type parameter. E.g.: + +```rust +# #![feature(precise_capturing)] +# #![deny(impl_trait_overcaptures)] +fn f<'a, T: Sized>(x: &'a (), y: T) -> impl Sized + use { (*x, y) } +// ~~~~~~~~ +// The type parameter has been named here. +# +# fn test<'a>(x: &'a (), y: ()) -> impl Sized + use<> { +# f(x, y) +# } +``` + +Note that this changes the API of the function slightly as a type argument can now be explicitly provided for this parameter using turbofish syntax. If this is undesired, you might consider instead whether you can simply continue to omit the `use<..>` bound and allow the lifetime to be captured. This might be particularly desirable if you might in the future want to use that lifetime in the hidden type and would like to save space for that. + +### Migrating away from the `Captures` trick + +Prior to the introduction of precise capturing `use<..>` bounds in Rust 1.82, correctly capturing a lifetime in an RPIT opaque type often required using the `Captures` trick. E.g.: + +```rust +#[doc(hidden)] +pub trait Captures {} +impl Captures for U {} + +fn f<'a, T>(x: &'a (), y: T) -> impl Sized + Captures<(&'a (), T)> { +// ~~~~~~~~~~~~~~~~~~~~~ +// This is called the `Captures` trick. + (x, y) +} +# +# fn test<'t, 'x>(t: &'t (), x: &'x ()) { +# f(t, x); +# } +``` + +With the `use<..>` bound syntax, the `Captures` trick is no longer needed and can be replaced with the following in all editions: + +```rust +# #![feature(precise_capturing)] +fn f<'a, T>(x: &'a (), y: T) -> impl Sized + use<'a, T> { + (x, y) +} +# +# fn test<'t, 'x>(t: &'t (), x: &'x ()) { +# f(t, x); +# } +``` + +In Rust 2024, the `use<..>` bound can often be omitted entirely, and the above can be written simply as: + +```rust,edition2024 +# #![feature(lifetime_capture_rules_2024)] +fn f<'a, T>(x: &'a (), y: T) -> impl Sized { + (x, y) +} +# +# fn test<'t, 'x>(t: &'t (), x: &'x ()) { +# f(t, x); +# } +``` + +There is no automatic migration for this, and the `Captures` trick still works in Rust 2024, but you might want to consider migrating code manually away from using this old trick. + +### Migrating away from the outlives trick + +Prior to the introduction of precise capturing `use<..>` bounds in Rust 1.82, it was common to use the "outlives trick" when a lifetime needed to be used in the hidden type of some opaque. E.g.: + +```rust +fn f<'a, T: 'a>(x: &'a (), y: T) -> impl Sized + 'a { + // ~~~~ ~~~~ + // ^ This is the outlives trick. + // | + // This bound is needed only for the trick. + (x, y) +// ~~~~~~ +// The hidden type is `(&'a (), T)`. +} +``` + +This trick was less baroque than the `Captures` trick, but also less correct. As we can see in the example above, even though any lifetime components within `T` are independent from the lifetime `'a`, we're required to add a `T: 'a` bound in order to make the trick work. This created undue and surprising restrictions on callers. + +Using precise capturing, you can write the above instead, in all editions, as: + +```rust +# #![feature(precise_capturing)] +fn f(x: &(), y: T) -> impl Sized + use<'_, T> { + (x, y) +} +# +# fn test<'t, 'x>(t: &'t (), x: &'x ()) { +# f(t, x); +# } +``` + +In Rust 2024, the `use<..>` bound can often be omitted entirely, and the above can be written simply as: + +```rust,edition2024 +# #![feature(precise_capturing)] +# #![feature(lifetime_capture_rules_2024)] +fn f(x: &(), y: T) -> impl Sized { + (x, y) +} +# +# fn test<'t, 'x>(t: &'t (), x: &'x ()) { +# f(t, x); +# } +``` + +There is no automatic migration for this, and the outlives trick still works in Rust 2024, but you might want to consider migrating code manually away from using this old trick. diff --git a/src/rust-2024/rustdoc-doctests.md b/src/rust-2024/rustdoc-doctests.md new file mode 100644 index 0000000..4c6a47f --- /dev/null +++ b/src/rust-2024/rustdoc-doctests.md @@ -0,0 +1,82 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Rustdoc combined tests + +## Summary + +- [Doctests] are now combined into a single binary which should result in a significant performance improvement. + +## Details + +Prior the the 2024 Edition, rustdoc's "test" mode would compile each code block in your documentation as a separate executable. Although this was relatively simple to implement, it resulted in a significant performance burden when there were a large number of documentation tests. Starting with the 2024 Edition, rustdoc will attempt to combine documentation tests into a single binary, significantly reducing the overhead for compiling doctests. + +```rust +/// Adds two numbers +/// +/// ``` +/// assert_eq!(add(1, 1), 2); +/// ``` +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +/// Subtracts two numbers +/// +/// ``` +/// assert_eq!(subtract(2, 1), 1); +/// ``` +pub fn subtract(left: u64, right: u64) -> u64 { + left - right +} +``` + +In this example, the two doctests will now be compiled into a single executable. Rustdoc will essentially place each example in a separate function within a single binary. The tests still run in independent processes as they did before, so any global state (like global statics) should still continue to work correctly.[^implementation] + +This change is only available in the 2024 Edition to avoid potential incompatibilities with existing doctests which may not work in a combined executable. However, these incompatibilities are expected to be extremely rare. + +[doctests]: ../../rustdoc/write-documentation/documentation-tests.html +[libtest harness]: ../../rustc/tests/index.html + +[^implementation]: For more information on the details of how this work, see ["Doctests - How were they improved?"](https://blog.guillaume-gomez.fr/articles/2024-08-17+Doctests+-+How+were+they+improved%3F). + +### `standalone_crate` tag + +In some situations it is not possible for rustdoc to combine examples into a single executable. Rustdoc will attempt to automatically detect if this is not possible. For example, a test will not be combined with others if it: + +* Uses the [`compile_fail`][tags] tag, which indicates that the example should fail to compile. +* Uses an [`edition`][tags] tag, which indicates the edition of the example.[^edition-tag] +* Uses global attributes, like the [`global_allocator`] attribute, which could potentially interfere with other tests. +* Defines any crate-wide attributes (like `#![feature(...)]`). +* Defines a macro that uses `$crate`, because the `$crate` path will not work correctly. + +However, rustdoc is not able to automatically determine *all* situations where an example cannot be combined with other examples. In these situations, you can add the `standalone_crate` language tag to indicate that the example should be built as a separate executable. For example: + +```rust +//! ``` +//! let location = std::panic::Location::caller(); +//! assert_eq!(location.line(), 5); +//! ``` +``` + +This is sensitive to the code structure of how the example is compiled and won't work with the "combined" approach because the line numbers will shift depending on how the doctests are combined. In these situations, you can add the `standalone_crate` tag to force the example to be built separately just as it was in previous editions. E.g.: + +```rust +//! ```standalone_crate +//! let location = std::panic::Location::caller(); +//! assert_eq!(location.line(), 5); +//! ``` +``` + +[tags]: ../../rustdoc/write-documentation/documentation-tests.html#attributes +[`global_allocator`]: ../../std/alloc/trait.GlobalAlloc.html + +[^edition-tag]: Note that rustdoc will only combine tests if the entire crate is Edition 2024 or greater. Using the `edition2024` tag in older editions will not result in those tests being combined. + +## Migration + +There is no automatic migration to determine which doctests need to be annotated with the `standalone_crate` tag. It's very unlikely that any given doctest will not work correctly when migrated. We suggest that you update your crate to the 2024 Edition and then run your documentation tests and see if any fail. If one does, you will need to analyze whether it can be rewritten to be compatible with the combined approach, or alternatively, add the `standalone_crate` tag to retain the previous behavior. + +Some things to watch out for and avoid are: + +- Checking the values of [`std::panic::Location`](https://doc.rust-lang.org/std/panic/struct.Location.html) or things that make use of `Location`. The location of the code is now different since multiple tests are now located in the same test crate. +- Checking the value of [`std::any::type_name`](https://doc.rust-lang.org/std/any/fn.type_name.html), which now has a different module path. diff --git a/src/rust-2024/rustdoc-nested-includes.md b/src/rust-2024/rustdoc-nested-includes.md new file mode 100644 index 0000000..edcd0f1 --- /dev/null +++ b/src/rust-2024/rustdoc-nested-includes.md @@ -0,0 +1,62 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Rustdoc nested `include!` change + +## Summary + +When a doctest is included with `include_str!`, if that doctest itself also uses `include!`, `include_str!`, or `include_bytes!`, the path is resolved relative to the Markdown file, rather than to the Rust source file. + +## Details + +Prior to the 2024 edition, adding documentation with `#[doc=include_str!("path/file.md")]` didn't carry span information into any doctests in that file. As a result, if the Markdown file was in a different directory than the source, any paths included had to be specified relative to the source file. + +For example, consider a library crate with these files: + +- `Cargo.toml` +- `README.md` +- `src/` + - `lib.rs` +- `examples/` + - `data.bin` + +Let's say that `lib.rs` contains this: + +```rust,ignore +#![doc=include_str!("../README.md")] +``` + +And assume this `README.md` file: + +````markdown +``` +let _ = include_bytes!("../examples/data.bin"); +// ^^^ notice this +``` +```` + +Prior to the 2024 edition, the path in `README.md` needed to be relative to the `lib.rs` file. In 2024 and later, it is now relative to `README.md` itself, so we would update `README.md` to: + +````markdown +``` +let _ = include_bytes!("examples/data.bin"); +``` +```` + +## Migration + +There is no automatic migration to convert the paths in affected doctests. If one of your doctests is affected, you'll see an error like this after migrating to the new edition when building your tests: + +```text +error: couldn't read `../examples/data.bin`: No such file or directory (os error 2) + --> src/../README.md:2:24 + | +2 | let _ = include_bytes!("../examples/data.bin"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `include_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) +help: there is a file with the same name in a different directory + | +2 | let _ = include_bytes!("examples/data.bin"); + | ~~~~~~~~~~~~~~~~~~~ +``` + +To migrate your doctests to Rust 2024, update any affected paths to be relative to the file containing the doctests. diff --git a/src/rust-2024/rustdoc.md b/src/rust-2024/rustdoc.md new file mode 100644 index 0000000..c9a412e --- /dev/null +++ b/src/rust-2024/rustdoc.md @@ -0,0 +1,7 @@ +# Rustdoc + + + +以降の節では、2024 エディションでの Rustdoc へのアップデートについて詳説します。 diff --git a/src/rust-2024/rustfmt-formatting-fixes.md b/src/rust-2024/rustfmt-formatting-fixes.md new file mode 100644 index 0000000..db1dd0c --- /dev/null +++ b/src/rust-2024/rustfmt-formatting-fixes.md @@ -0,0 +1,646 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Rustfmt: Formatting fixes + +## Summary + +- Fixes to various formatting scenarios. + +## Details + +The 2024 style edition introduces several fixes to various formatting scenarios. + +### Don't align unrelated trailing comments after items or at the end of blocks + + + +Previously rustfmt would assume that a comment on a line following an item with a trailing comment should be indented to match the trailing comment. This has been changed so that those comments are not indented. + +**Style edition 2021:** + +```rust,ignore +pub const IFF_MULTICAST: ::c_int = 0x0000000800; // Supports multicast + // Multicast using broadcst. add. + +pub const SQ_CRETAB: u16 = 0x000e; // CREATE TABLE +pub const SQ_DRPTAB: u16 = 0x000f; // DROP TABLE +pub const SQ_CREIDX: u16 = 0x0010; // CREATE INDEX + //const SQ_DRPIDX: u16 = 0x0011; // DROP INDEX + //const SQ_GRANT: u16 = 0x0012; // GRANT + //const SQ_REVOKE: u16 = 0x0013; // REVOKE + +fn foo() { + let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem. + // Id turpis. Nam posuere lectus vitae nibh. Etiam tortor orci, sagittis + // malesuada, rhoncus quis, hendrerit eget, libero. Quisque commodo nulla at + let b = baz(); + + let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] + // TODO(emilio): It may make sense to make this range [.01, 10.0], to align + // with css-fonts-4's range of [1, 1000]. +} +``` + +**Style edition 2024:** + +```rust,ignore +pub const IFF_MULTICAST: ::c_int = 0x0000000800; // Supports multicast +// Multicast using broadcst. add. + +pub const SQ_CRETAB: u16 = 0x000e; // CREATE TABLE +pub const SQ_DRPTAB: u16 = 0x000f; // DROP TABLE +pub const SQ_CREIDX: u16 = 0x0010; // CREATE INDEX +//const SQ_DRPIDX: u16 = 0x0011; // DROP INDEX +//const SQ_GRANT: u16 = 0x0012; // GRANT +//const SQ_REVOKE: u16 = 0x0013; // REVOKE + +fn foo() { + let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem. + // Id turpis. Nam posuere lectus vitae nibh. Etiam tortor orci, sagittis + // malesuada, rhoncus quis, hendrerit eget, libero. Quisque commodo nulla at + let b = baz(); + + let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] + // TODO(emilio): It may make sense to make this range [.01, 10.0], to align + // with css-fonts-4's range of [1, 1000]. +} +``` + +### Don't indent strings in comments + + + +Previously rustfmt would incorrectly attempt to format strings in comments. + +**Original:** + +```rust,ignore +pub fn main() { + /* let s = String::from( + " +hello +world +", + ); */ +} +``` + +**Style edition 2021:** + +```rust,ignore +pub fn main() { + /* let s = String::from( + " + hello + world + ", + ); */ +} +``` + +**Style edition 2024:** + +No change from original. + +### Long strings don't prevent formatting expressions + + + +In some situations, long strings would previously prevent the expression from being formatted. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let value = if x == "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." { 0 } else {10}; + + let x = Testing { + foo: "long_long_long_long_long_long_long_lo_long_long_long_long_long_long__long_long_long_long_long_long_", +bar: "long_long_long_long_long_long_long_long_long_long_lo_long_long_lolong_long_long_lo_long_long_lolong_long_long_lo_long_long_lo", +}; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let value = if x + == "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." + { + 0 + } else { + 10 + }; + + let x = Testing { + foo: "long_long_long_long_long_long_long_lo_long_long_long_long_long_long__long_long_long_long_long_long_", + bar: "long_long_long_long_long_long_long_long_long_long_lo_long_long_lolong_long_long_lo_long_long_lolong_long_long_lo_long_long_lo", + }; +} +``` + +### Fixed indentation of generics in impl blocks + + + +Generics in `impl` items had excessive indentation. + +**Style edition 2021:** + +```rust,ignore +impl< + Target: FromEvent + FromEvent, + A: Widget2, + B: Widget2, + C: for<'a> CtxFamily<'a>, + > Widget2 for WidgetEventLifter +{ + type Ctx = C; + type Event = Vec; +} +``` + +**Style edition 2024:** + +```rust,ignore +impl< + Target: FromEvent + FromEvent, + A: Widget2, + B: Widget2, + C: for<'a> CtxFamily<'a>, +> Widget2 for WidgetEventLifter +{ + type Ctx = C; + type Event = Vec; +} +``` + +### Use correct indentation when formatting a complex `fn` + + + +In some cases, a complex `fn` signature could end up with an unusual indentation that is now fixed. + +**Style edition 2021:** + +```rust,ignore +fn build_sorted_static_get_entry_names( + mut entries: Vec<(u8, &'static str)>, +) -> (impl Fn( + AlphabeticalTraversal, + Box>, +) -> BoxFuture<'static, Result, Status>> + + Send + + Sync + + 'static) { +} +``` + +**Style edition 2024:** + +```rust,ignore +fn build_sorted_static_get_entry_names( + mut entries: Vec<(u8, &'static str)>, +) -> ( + impl Fn( + AlphabeticalTraversal, + Box>, + ) -> BoxFuture<'static, Result, Status>> + + Send + + Sync + + 'static +) { +} +``` + +### Avoid extra space in nested tuple indexing expression + + + +Nested tuple indexing expressions would incorrectly include an extra space. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let _ = ((1,),).0 .0; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let _ = ((1,),).0.0; +} +``` + +### End return/break/continue inside a block in a match with a semicolon + + + +A `return`, `break`, or `continue` inside a block in a match arm was incorrectly missing a semicolon. + +**Style edition 2021:** + +```rust,ignore +fn foo() { + match 0 { + 0 => { + return AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + } + _ => "", + }; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn foo() { + match 0 { + 0 => { + return AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; + } + _ => "", + }; +} +``` + +### Long array and slice patterns are now wrapped + + + +Long array and slice patterns were not getting wrapped properly. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let [aaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, cccccccccccccccccccccccccc, ddddddddddddddddddddddddd] = + panic!(); +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let [ + aaaaaaaaaaaaaaaaaaaaaaaaaa, + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, + cccccccccccccccccccccccccc, + ddddddddddddddddddddddddd, + ] = panic!(); +} +``` + +### Format the last expression-statement as an expression + + + +The last statement in a block which is an expression is now formatted as an expression. + +**Style edition 2021:** + +```rust,ignore +fn main() { + let toto = || { + if true { + 42 + } else { + 24 + } + }; + + { + T + } +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + let toto = || { + if true { 42 } else { 24 } + }; + + { T } +} +``` + +### Same formatting between function and macro calls + + + +Some formatting is now the same in a macro invocation as it is in a function call. + +**Style edition 2021:** + +```rust,ignore +fn main() { + macro_call!(HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some()); + + fn_call( + HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some(), + ); +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + macro_call!( + HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some() + ); + + fn_call( + HAYSTACK + .par_iter() + .find_any(|&&x| x[0] % 1000 == 999) + .is_some(), + ); +} +``` + +### Force block closures for closures with a single loop body + + + +Closures with a single loop are now formatted as a block expression. + +**Style edition 2021:** + +```rust,ignore +fn main() { + thread::spawn(|| loop { + println!("iteration"); + }); +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + thread::spawn(|| { + loop { + println!("iteration"); + } + }); +} +``` + +### Empty lines in where clauses are now removed + + + +Empty lines in a `where` clause are now removed. + +**Style edition 2021:** + +```rust,ignore +fn foo(_: T) +where + T: std::fmt::Debug, + + T: std::fmt::Display, +{ +} +``` + +**Style edition 2024:** + +```rust,ignore +fn foo(_: T) +where + T: std::fmt::Debug, + T: std::fmt::Display, +{ +} +``` + +### Fixed formatting of a let-else statement with an attribute + + + +If a let-else statement had an attribute, then it would cause the `else` clause to incorrectly wrap the `else` part separately. + +**Style edition 2021:** + +```rust,ignore +fn main() { + #[cfg(target_os = "linux")] + let x = 42 + else { + todo!() + }; + + // This is the same without an attribute. + let x = 42 else { todo!() }; +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + #[cfg(target_os = "linux")] + let x = 42 else { todo!() }; + + // This is the same without an attribute. + let x = 42 else { todo!() }; +} +``` + +### Off-by-one error for wrapping enum variant doc comments + + + +When using the `wrap_comments` feature, the comments were being wrapped at a column width off-by-one. + +**Original:** + +```rust,ignore +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} +``` + +**Style edition 2021:** + +```rust,ignore +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines + /// still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} +``` + +**Style edition 2024:** + +```rust,ignore +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} +``` + +### Off-by-one error for `format_macro_matchers` + + + +When using the `format_macro_matchers` feature, the matcher was being wrapped at a column width off-by-one. + +**Style edition 2021:** + +```rust,ignore +macro_rules! test { + ($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{ + return; + }}; +} +``` + +**Style edition 2024:** + +```rust,ignore +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + return; + }}; +} +``` + +### Fixed failure with `=>` in comment after match `=>` + + + +In certain circumstances if a comment contained a `=>` after the `=>` in a match expression, this would cause a failure to format correctly. + +**Style edition 2021:** + +```rust,ignore +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} +``` + +**Style edition 2024:** + +```rust,ignore +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} +``` + +### Multiple inner attributes in a match expression indented incorrectly + + + +Multiple inner attributes in a match expression were being indented incorrectly. + +**Style edition 2021:** + +```rust,ignore +pub fn main() { + match a { + #![attr1] + #![attr2] + _ => None, + } +} +``` + +**Style edition 2024:** + +```rust,ignore +pub fn main() { + match a { + #![attr1] + #![attr2] + _ => None, + } +} +``` + +## Migration + +The change can be applied automatically by running `cargo fmt` or `rustfmt` with the 2024 Edition. See the [Style edition] chapter for more information on migrating and how style editions work. + +[Style edition]: rustfmt-style-edition.md diff --git a/src/rust-2024/rustfmt-overflow-delimited-expr.md b/src/rust-2024/rustfmt-overflow-delimited-expr.md new file mode 100644 index 0000000..2625636 --- /dev/null +++ b/src/rust-2024/rustfmt-overflow-delimited-expr.md @@ -0,0 +1,92 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Rustfmt: Combine all delimited exprs as last argument + +## Summary + +* Some expressions with multi-line final arguments will now format as a single line, with the final expression overflowing. + +## Details + +When structs, slices, arrays, and block/array-like macros are used as the last argument in an expression list, they are now allowed to overflow (like blocks/closures) instead of being indented on a new line. + +```rust,ignore +// Edition 2021 + +fn example() { + foo(ctx, |param| { + action(); + foo(param) + }); + + foo( + ctx, + Bar { + x: value, + y: value2, + }, + ); + + foo( + ctx, + &[ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ], + ); + + foo( + ctx, + vec![ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ], + ); +} +``` + +This now formats as the following in the 2024 style edition: + +```rust,ignore +// Edition 2024 + +fn example() { + foo(ctx, |param| { + action(); + foo(param) + }); + + foo(ctx, Bar { + x: value, + y: value2, + }); + + foo(ctx, &[ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ]); + + foo(ctx, vec![ + MAROON_TOMATOES, + PURPLE_POTATOES, + ORGANE_ORANGES, + GREEN_PEARS, + RED_APPLES, + ]); +} +``` + +## Migration + +The change can be applied automatically by running `cargo fmt` or `rustfmt` with the 2024 Edition. See the [Style edition] chapter for more information on migrating and how style editions work. + +[Style edition]: rustfmt-style-edition.md diff --git a/src/rust-2024/rustfmt-raw-identifier-sorting.md b/src/rust-2024/rustfmt-raw-identifier-sorting.md new file mode 100644 index 0000000..195fbc8 --- /dev/null +++ b/src/rust-2024/rustfmt-raw-identifier-sorting.md @@ -0,0 +1,38 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Rustfmt: Raw identifier sorting + +## Summary + +`rustfmt` now properly sorts [raw identifiers]. + +[raw identifiers]: ../../reference/identifiers.html#raw-identifiers + +## Details + +The [Rust Style Guide] includes [rules for sorting][sorting] that `rustfmt` applies in various contexts, such as on imports. + +Prior to the 2024 Edition, when sorting rustfmt would use the leading `r#` token instead of the ident which led to unwanted results. For example: + +```rust,ignore +use websocket::client::ClientBuilder; +use websocket::r#async::futures::Stream; +use websocket::result::WebSocketError; +``` + +In the 2024 Edition, `rustfmt` now produces: + +```rust,ignore +use websocket::r#async::futures::Stream; +use websocket::client::ClientBuilder; +use websocket::result::WebSocketError; +``` + +[Rust Style Guide]: ../../style-guide/index.html +[sorting]: ../../style-guide/index.html#sorting + +## Migration + +The change can be applied automatically by running `cargo fmt` or `rustfmt` with the 2024 Edition. See the [Style edition] chapter for more information on migrating and how style editions work. + +[Style edition]: rustfmt-style-edition.md diff --git a/src/rust-2024/rustfmt-style-edition.md b/src/rust-2024/rustfmt-style-edition.md new file mode 100644 index 0000000..3d4ed41 --- /dev/null +++ b/src/rust-2024/rustfmt-style-edition.md @@ -0,0 +1,86 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Rustfmt: Style edition + +## Summary + +User can now control which style edition to use with `rustfmt`. + +## Details + +The default formatting produced by Rustfmt is governed +by the rules in the [Rust Style Guide]. + +Additionally, Rustfmt has a formatting stability guarantee that aims +to avoid causing noisy formatting churn for users when updating a +Rust toolchain. This stability guarantee essentially means that a newer +version of Rustfmt cannot modify the _successfully formatted_ output +that was produced by a previous version of Rustfmt. + +The combination of those two constraints had historically locked both +the Style Guide and the default formatting behavior in Rustfmt. This +impasse caused various challenges, such as preventing the ability to +iterate on style improvements, and requiring Rustfmt to maintain legacy +formatting quirks that were obviated long ago (e.g. nested tuple access). + +[RFC 3338] resolved this impasse by establishing a mechanism for the +Rust Style Guide to be aligned to Rust's Edition model wherein the +Style Guide could evolve across Editions, and `rustfmt` would allow users +to specify their desired Edition of the Style Guide, referred to as the Style Edition. + +In the 2024 Edition, `rustfmt` now supports the ability for users to control +the Style Edition used for formatting. The 2024 Edition of the Style Guide also +includes enhancements to the Style Guide which are detailed elsewhere in this Edition Guide. + +By default `rustfmt` will use the same Style Edition as the standard Rust Edition +used for parsing, but the Style Edition can also be overridden and configured separately. + +There are multiple ways to run `rustfmt` with the 2024 Style Edition: + +With a `Cargo.toml` file that has `edition` set to `2024`, run: + +```sh +cargo fmt +``` + +Or run `rustfmt` directly with `2024` for the edition to use the 2024 edition +for both parsing and the 2024 edition of the Style Guide: + +```sh +rustfmt lib.rs --edition 2024 +``` + +The style edition can also be set in a `rustfmt.toml` configuration file: +```toml +style_edition = "2024" +``` + +Which is then used when running `rustfmt` directly: +```sh +rustfmt lib.rs +``` + +Alternatively, the style edition can be specified directly from `rustfmt` options: + +```sh +rustfmt lib.rs --style-edition 2024 +``` + +[Rust Style Guide]: ../../style-guide/index.html +[RFC 3338]: https://rust-lang.github.io/rfcs/3338-style-evolution.html + +## Migration + +Running `cargo fmt` or `rustfmt` with the 2024 edition or style edition will +automatically migrate formatting over to the 2024 style edition formatting. + +Projects who have contributors that may utilize their editor's format-on-save +features are also strongly encouraged to add a `.rustfmt.toml` file to their project +that includes the corresponding `style_edition` utilized within their project, or to +encourage their users to ensure their local editor format-on-save feature is +configured to use that same `style_edition`. + +This is to ensure that the editor format-on-save output is consistent with the +output when `cargo fmt` is manually executed by the developer, or the project's CI +process (many editors will run `rustfmt` directly which by default uses the 2015 +edition, whereas `cargo fmt` uses the edition specified in the `Cargo.toml` file) diff --git a/src/rust-2024/rustfmt-version-sorting.md b/src/rust-2024/rustfmt-version-sorting.md new file mode 100644 index 0000000..c2865c8 --- /dev/null +++ b/src/rust-2024/rustfmt-version-sorting.md @@ -0,0 +1,43 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Rustfmt: Version sorting + +## Summary + +`rustfmt` utilizes a new sorting algorithm. + +## Details + +The [Rust Style Guide] includes [rules for sorting][sorting] that `rustfmt` applies in various contexts, such as on imports. + +Previous versions of the Style Guide and Rustfmt generally used an "ASCIIbetical" based approach. In the 2024 Edition this is changed to use a version-sort like algorithm that compares Unicode characters lexicographically and provides better results in ASCII digit comparisons. + +For example with a given (unsorted) input: + +```rust,ignore +use std::num::{NonZeroU32, NonZeroU16, NonZeroU8, NonZeroU64}; +use std::io::{Write, Read, stdout, self}; +``` + +In the prior Editions, `rustfmt` would have produced: + +```rust,ignore +use std::io::{self, stdout, Read, Write}; +use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8}; +``` + +In the 2024 Edition, `rustfmt` now produces: + +```rust,ignore +use std::io::{self, Read, Write, stdout}; +use std::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64}; +``` + +[Rust Style Guide]: ../../style-guide/index.html +[sorting]: ../../style-guide/index.html#sorting + +## Migration + +The change can be applied automatically by running `cargo fmt` or `rustfmt` with the 2024 Edition. See the [Style edition] chapter for more information on migrating and how style editions work. + +[Style edition]: rustfmt-style-edition.md diff --git a/src/rust-2024/rustfmt.md b/src/rust-2024/rustfmt.md new file mode 100644 index 0000000..668ebf0 --- /dev/null +++ b/src/rust-2024/rustfmt.md @@ -0,0 +1,7 @@ +# Rustfmt + + + +以降の節では、2024 エディションでの Rustfmt へのアップデートについて詳説します。 diff --git a/src/rust-2024/standard-library.md b/src/rust-2024/standard-library.md new file mode 100644 index 0000000..9c6f9b3 --- /dev/null +++ b/src/rust-2024/standard-library.md @@ -0,0 +1,11 @@ + + +# 標準ライブラリ + + + +以降の節では、2024 エディションでの標準ライブラリへのアップデートについて詳説します。 diff --git a/src/rust-2024/static-mut-references.md b/src/rust-2024/static-mut-references.md new file mode 100644 index 0000000..18e9487 --- /dev/null +++ b/src/rust-2024/static-mut-references.md @@ -0,0 +1,357 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Disallow references to static mut + +## Summary + +- The [`static_mut_refs`] lint level is now `deny` by default. + This checks for taking a shared or mutable reference to a `static mut`. + +[`static_mut_refs`]: ../../rustc/lints/listing/warn-by-default.html#static-mut-refs + +## Details + +The [`static_mut_refs`] lint detects taking a reference to a [`static mut`]. In the 2024 Edition, this lint is now `deny` by default to emphasize that you should avoid making these references. + + +```rust +static mut X: i32 = 23; +static mut Y: i32 = 24; + +unsafe { + let y = &X; // ERROR: shared reference to mutable static + let ref x = X; // ERROR: shared reference to mutable static + let (x, y) = (&X, &Y); // ERROR: shared reference to mutable static +} +``` + +Merely taking such a reference in violation of Rust's mutability XOR aliasing requirement has always been *instantaneous* [undefined behavior], **even if the reference is never read from or written to**. Furthermore, upholding mutability XOR aliasing for a `static mut` requires *reasoning about your code globally*, which can be particularly difficult in the face of reentrancy and/or multithreading. + +Note that there are some cases where implicit references are automatically created without a visible `&` operator. For example, these situations will also trigger the lint: + + +```rust +static mut NUMS: &[u8; 3] = &[0, 1, 2]; + +unsafe { + println!("{NUMS:?}"); // ERROR: shared reference to mutable static + let n = NUMS.len(); // ERROR: shared reference to mutable static +} +``` + +## Alternatives + +Wherever possible, it is **strongly recommended** to use instead an *immutable* `static` of a type that provides *interior mutability* behind some *locally-reasoned abstraction* (which greatly reduces the complexity of ensuring that Rust's mutability XOR aliasing requirement is upheld). + +In situations where no locally-reasoned abstraction is possible and you are therefore compelled still to reason globally about accesses to your `static` variable, you must now use raw pointers such as can be obtained via the [`&raw const` or `&raw mut` operators][raw]. By first obtaining a raw pointer rather than directly taking a reference, (the safety requirements of) accesses through that pointer will be more familiar to `unsafe` developers and can be deferred until/limited to smaller regions of code. + +[Undefined Behavior]: ../../reference/behavior-considered-undefined.html +[`static mut`]: ../../reference/items/static-items.html#mutable-statics +[`addr_of_mut!`]: https://docs.rust-lang.org/core/ptr/macro.addr_of_mut.html +[raw]: ../../reference/expressions/operator-expr.html#raw-borrow-operators + +Note that the following examples are just illustrations and are not intended as full-fledged implementations. Do not copy these as-is. There are details for your specific situation that may require alterations to fit your needs. These are intended to help you see different ways to approach your problem. + +It is recommended to read the documentation for the specific types in the standard library, the reference on [undefined behavior], the [Rustonomicon], and if you are having questions to reach out on one of the Rust forums such as the [Users Forum]. + +[undefined behavior]: ../../reference/behavior-considered-undefined.html +[Rustonomicon]: ../../nomicon/index.html +[Users Forum]: https://users.rust-lang.org/ + +### Don't use globals + +This is probably something you already know, but if possible it is best to avoid mutable global state. Of course this can be a little more awkward or difficult at times, particularly if you need to pass a mutable reference around between many functions. + +### Atomics + +The [atomic types][atomics] provide integers, pointers, and booleans that can be used in a `static` (without `mut`). + +```rust,edition2024 +# use std::sync::atomic::Ordering; +# use std::sync::atomic::AtomicU64; + +// Chnage from this: +// static mut COUNTER: u64 = 0; +// to this: +static COUNTER: AtomicU64 = AtomicU64::new(0); + +fn main() { + // Be sure to analyze your use case to determine the correct Ordering to use. + COUNTER.fetch_add(1, Ordering::Relaxed); +} +``` + +[atomics]: ../../std/sync/atomic/index.html + +### Mutex or RwLock + +When your type is more complex than an atomic, consider using a [`Mutex`] or [`RwLock`] to ensure proper access to the global value. + +```rust,edition2024 +# use std::sync::Mutex; +# use std::collections::VecDeque; + +// Change from this: +// static mut QUEUE: VecDeque = VecDeque::new(); +// to this: +static QUEUE: Mutex> = Mutex::new(VecDeque::new()); + +fn main() { + QUEUE.lock().unwrap().push_back(String::from("abc")); + let first = QUEUE.lock().unwrap().pop_front(); +} +``` + +[`Mutex`]: ../../std/sync/struct.Mutex.html +[`RwLock`]: ../../std/sync/struct.RwLock.html + +### OnceLock or LazyLock + +If you are using a `static mut` because you need to do some one-time initialization that can't be `const`, you can instead reach for [`OnceLock`] or [`LazyLock`] instead. + +```rust,edition2024 +# use std::sync::LazyLock; +# +# struct GlobalState; +# +# impl GlobalState { +# fn new() -> GlobalState { +# GlobalState +# } +# fn example(&self) {} +# } + +// Instead of some temporary or uninitialized type like: +// static mut STATE: Option = None; +// use this instead: +static STATE: LazyLock = LazyLock::new(|| { + GlobalState::new() +}); + +fn main() { + STATE.example(); +} +``` + +[`OnceLock`] is similar to [`LazyLock`], but can be used if you need to pass information into the constructor, which can work well with single initialization points (like `main`), or if the inputs are available wherever you access the global. + +```rust,edition2024 +# use std::sync::OnceLock; +# +# struct GlobalState; +# +# impl GlobalState { +# fn new(verbose: bool) -> GlobalState { +# GlobalState +# } +# fn example(&self) {} +# } +# +# struct Args { +# verbose: bool +# } +# fn parse_arguments() -> Args { +# Args { verbose: true } +# } + +static STATE: OnceLock = OnceLock::new(); + +fn main() { + let args = parse_arguments(); + let state = GlobalState::new(args.verbose); + let _ = STATE.set(state); + // ... + STATE.get().unwrap().example(); +} +``` + +[`OnceLock`]: ../../std/sync/struct.OnceLock.html +[`LazyLock`]: ../../std/sync/struct.LazyLock.html + +### `no_std` one-time initialization + +This example is similar to [`OnceLock`] in that it provides one-time initialization of a global, but it does not require `std` which is useful in a `no_std` context. Assuming your target supports atomics, then you can use an atomic to check for the initialization of the global. The pattern might look something like this: + +```rust,edition2024 +# use core::sync::atomic::AtomicUsize; +# use core::sync::atomic::Ordering; +# +# struct Args { +# verbose: bool, +# } +# fn parse_arguments() -> Args { +# Args { verbose: true } +# } +# +# struct GlobalState { +# verbose: bool, +# } +# +# impl GlobalState { +# const fn default() -> GlobalState { +# GlobalState { verbose: false } +# } +# fn new(verbose: bool) -> GlobalState { +# GlobalState { verbose } +# } +# fn example(&self) {} +# } + +const UNINITIALIZED: usize = 0; +const INITIALIZING: usize = 1; +const INITIALIZED: usize = 2; + +static STATE_INITIALIZED: AtomicUsize = AtomicUsize::new(UNINITIALIZED); +static mut STATE: GlobalState = GlobalState::default(); + +fn set_global_state(state: GlobalState) { + if STATE_INITIALIZED + .compare_exchange( + UNINITIALIZED, + INITIALIZING, + Ordering::SeqCst, + Ordering::SeqCst, + ) + .is_ok() + { + // SAFETY: The reads and writes to STATE are guarded with the INITIALIZED guard. + unsafe { + STATE = state; + } + STATE_INITIALIZED.store(INITIALIZED, Ordering::SeqCst); + } else { + panic!("already initialized, or concurrent initialization"); + } +} + +fn get_state() -> &'static GlobalState { + if STATE_INITIALIZED.load(Ordering::Acquire) != INITIALIZED { + panic!("not initialized"); + } else { + // SAFETY: Mutable access is not possible after state has been initialized. + unsafe { &*&raw const STATE } + } +} + +fn main() { + let args = parse_arguments(); + let state = GlobalState::new(args.verbose); + set_global_state(state); + // ... + let state = get_state(); + state.example(); +} +``` + +This example assumes you can put some default value in the static before it is initialized (the const `default` constructor in this example). If that is not possible, consider using either [`MaybeUninit`], or dynamic trait dispatch (with a dummy type that implements a trait), or some other approach to have a default placeholder. + +There are community-provided crates that can provide similar one-time initialization, such as the [`static-cell`] crate (which supports targets that do not have atomics by using [`portable-atomic`]). + +[`MaybeUninit`]: ../../core/mem/union.MaybeUninit.html +[`static-cell`]: https://crates.io/crates/static_cell +[`portable-atomic`]: https://crates.io/crates/portable-atomic + +### Raw pointers + +In some cases you can continue to use `static mut`, but avoid creating references. For example, if you just need to pass [raw pointers] into a C library, don't create an intermediate reference. Instead you can use [raw borrow operators], like in the following example: + +```rust,edition2024,no_run +# #[repr(C)] +# struct GlobalState { +# value: i32 +# } +# +# impl GlobalState { +# const fn new() -> GlobalState { +# GlobalState { value: 0 } +# } +# } + +static mut STATE: GlobalState = GlobalState::new(); + +unsafe extern "C" { + fn example_ffi(state: *mut GlobalState); +} + +fn main() { + unsafe { + // Change from this: + // example_ffi(&mut STATE as *mut GlobalState); + // to this: + example_ffi(&raw mut STATE); + } +} +``` + +Just beware that you still need to uphold the aliasing constraints around mutable pointers. This may require some internal or external synchronization or proofs about how it is used across threads, interrupt handlers, and reentrancy. + +[raw borrow operators]: ../../reference/expressions/operator-expr.html#raw-borrow-operators +[raw pointers]: ../../reference/types/pointer.html#raw-pointers-const-and-mut + +### `UnsafeCell` with `Sync` + +[`UnsafeCell`] does not impl `Sync`, so it cannot be used in a `static`. You can create your own wrapper around [`UnsafeCell`] to add a `Sync` impl so that it can be used in a `static` to implement interior mutability. This approach can be useful if you have external locks or other guarantees that uphold the safety invariants required for mutable pointers. + +Note that this is largely the same as the [raw pointers](#raw-pointers) example. The wrapper helps to emphasize how you are using the type, and focus on which safety requirements you should be careful of. But otherwise they are roughly the same. + +```rust,edition2024 +# use std::cell::UnsafeCell; +# +# fn with_interrupts_disabled(f: T) { +# // A real example would disable interrupts. +# f(); +# } +# +# #[repr(C)] +# struct GlobalState { +# value: i32, +# } +# +# impl GlobalState { +# const fn new() -> GlobalState { +# GlobalState { value: 0 } +# } +# } + +#[repr(transparent)] +pub struct SyncUnsafeCell(UnsafeCell); + +unsafe impl Sync for SyncUnsafeCell {} + +static STATE: SyncUnsafeCell = SyncUnsafeCell(UnsafeCell::new(GlobalState::new())); + +fn set_value(value: i32) { + with_interrupts_disabled(|| { + let state = STATE.0.get(); + unsafe { + // SAFETY: This value is only ever read in our interrupt handler, + // and interrupts are disabled, and we only use this in one thread. + (*state).value = value; + } + }); +} +``` + +The standard library has a nightly-only (unstable) variant of [`UnsafeCell`] called [`SyncUnsafeCell`]. This example above shows a very simplified version of the standard library type, but would be used roughly the same way. It can provide even better isolation, so do check out its implementation for more details. + +This example includes a fictional `with_interrupts_disabled` function which is the type of thing you might see in an embedded environment. For example, the [`critical-section`] crate provides a similar kind of functionality that could be used for an embedded environment. + +[`critical-section`]: https://crates.io/crates/critical-section +[`UnsafeCell`]: ../../std/cell/struct.UnsafeCell.html +[`SyncUnsafeCell`]: ../../std/cell/struct.SyncUnsafeCell.html + +### Safe references + +In some cases it may be safe to create a reference of a `static mut`. The whole point of the [`static_mut_refs`] lint is that this is very hard to do correctly! However, that's not to say it is *impossible*. If you have a situation where you can guarantee that the aliasing requirements are upheld, such as guaranteeing the static is narrowly scoped (only used in a small module or function), has some internal or external synchronization, accounts for interrupt handlers and reentrancy, panic safety, drop handlers, etc., then taking a reference may be fine. + +There are two approaches you can take for this. You can either allow the [`static_mut_refs`] lint (preferably as narrowly as you can), or convert raw pointers to a reference, as with `&mut *&raw mut MY_STATIC`. + + + +#### Short-lived references + +If you must create a reference to a `static mut`, then it is recommended to minimize the scope of how long that reference exists. Avoid squirreling the reference away somewhere, or keeping it alive through a large section of code. Keeping it short-lived helps with auditing, and verifying that exclusive access is maintained for the duration. Using pointers should be your default unit, and only convert the pointer to a reference on demand when absolutely required. + +## Migration + +There is no automatic migration to fix these references to `static mut`. To avoid undefined behavior you must rewrite your code to use a different approach as recommended in the [Alternatives](#alternatives) section. diff --git a/src/rust-2024/temporary-if-let-scope.md b/src/rust-2024/temporary-if-let-scope.md new file mode 100644 index 0000000..2b40bbb --- /dev/null +++ b/src/rust-2024/temporary-if-let-scope.md @@ -0,0 +1,104 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# `if let` temporary scope + +## Summary + +- In an `if let $pat = $expr { .. } else { .. }` expression, the temporary values generated from evaluating `$expr` will be dropped before the program enters the `else` branch instead of after. + +## Details + +The 2024 Edition changes the drop scope of [temporary values] in the scrutinee[^scrutinee] of an `if let` expression. This is intended to help reduce the potentially unexpected behavior involved with the temporary living for too long. + +Before 2024, the temporaries could be extended beyond the `if let` expression itself. For example: + +```rust,edition2021 +// Before 2024 +# use std::sync::RwLock; + +fn f(value: &RwLock>) { + if let Some(x) = *value.read().unwrap() { + println!("value is {x}"); + } else { + let mut v = value.write().unwrap(); + if v.is_none() { + *v = Some(true); + } + } + // <--- Read lock is dropped here in 2021 +} +``` + +In this example, the temporary read lock generated by the call to `value.read()` will not be dropped until after the `if let` expression (that is, after the `else` block). In the case where the `else` block is executed, this causes a deadlock when it attempts to acquire a write lock. + +The 2024 Edition shortens the lifetime of the temporaries to the point where the then-block is completely evaluated or the program control enters the `else` block. + +```rust,edition2024 +// Starting with 2024 +# use std::sync::RwLock; + +fn f(value: &RwLock>) { + if let Some(x) = *value.read().unwrap() { + println!("value is {x}"); + } + // <--- Read lock is dropped here in 2024 + else { + let mut s = value.write().unwrap(); + if s.is_none() { + *s = Some(true); + } + } +} +``` + +See the [temporary scope rules] for more information about how temporary scopes are extended. See the [tail expression temporary scope] chapter for a similar change made to tail expressions. + +[^scrutinee]: The [scrutinee] is the expression being matched on in the `if let` expression. + +[scrutinee]: ../../reference/glossary.html#scrutinee +[temporary values]: ../../reference/expressions.html#temporaries +[temporary scope rules]: ../../reference/destructors.html#temporary-scopes +[tail expression temporary scope]: temporary-tail-expr-scope.md + +## Migration + +It is always safe to rewrite `if let` with a `match`. The temporaries of the `match` scrutinee are extended past the end of the `match` expression (typically to the end of the statement), which is the same as the 2021 behavior of `if let`. + +The [`if_let_rescope`] lint suggests a fix when a lifetime issue arises due to this change or the lint detects that a temporary value with a custom, non-trivial `Drop` destructor is generated from the scrutinee of the `if let`. For instance, the earlier example may be rewritten into the following when the suggestion from `cargo fix` is accepted: + +```rust +# use std::sync::RwLock; +fn f(value: &RwLock>) { + match *value.read().unwrap() { + Some(x) => { + println!("value is {x}"); + } + _ => { + let mut s = value.write().unwrap(); + if s.is_none() { + *s = Some(true); + } + } + } + // <--- Read lock is dropped here in both 2021 and 2024 +} +``` + +In this particular example, that's probably not what you want due to the aforementioned deadlock! However, some scenarios may be assuming that the temporaries are held past the `else` clause, in which case you may want to retain the old behavior. + +The [`if_let_rescope`] lint is part of the `rust-2024-compatibility` lint group which is included in the automatic edition migration. In order to migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +After the migration, it is recommended that you review all of the changes of `if let` to `match` and decide what is the behavior that you need with respect to when temporaries are dropped. If you determine that the change is unnecessary, then you can revert the change back to `if let`. + +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(if_let_rescope)] +``` + +[`if_let_rescope`]: ../../rustc/lints/listing/allowed-by-default.html#if-let-rescope 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..bf11e9a --- /dev/null +++ b/src/rust-2024/temporary-tail-expr-scope.md @@ -0,0 +1,103 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Tail expression temporary scope + +## Summary + +- 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. + +[function]: ../../reference/items/functions.html +[block]: ../../reference/expressions/block-expr.html + +## Details + +The 2024 Edition changes the drop order of [temporary values] in tail expressions. It often comes as a surprise that, before the 2024 Edition, temporary values in tail expressions can live longer than the block itself, and are dropped later than the local variable bindings, as in the following example: + +[temporary values]: ../../reference/expressions.html#temporaries + +```rust,edition2021,compile_fail,E0597 +// Before 2024 +# use std::cell::RefCell; +fn f() -> usize { + let c = RefCell::new(".."); + c.borrow().len() // error[E0597]: `c` does not live long enough +} +``` + +This yields the following error with the 2021 Edition: + +```text +error[E0597]: `c` does not live long enough + --> src/lib.rs:4:5 + | +3 | let c = RefCell::new(".."); + | - binding `c` declared here +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 + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `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 + | +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`. +``` + +In 2021 the local variable `c` is dropped before the temporary created by `c.borrow()`. The 2024 Edition changes this so that the temporary value `c.borrow()` is dropped first, followed by dropping the local variable `c`, allowing the code to compile as expected. + +### Temporary scope may be narrowed + +When a temporary is created in order to evaluate an expression, the temporary is dropped based on the [temporary scope rules]. Those rules define how long the temporary will be kept alive. Before 2024, temporaries from tail expressions of a block would be extended outside of the block to the next temporary scope boundary. In many cases this would be the end of a statement or function body. In 2024, the temporaries of the tail expression may now be dropped immediately at the end of the block (before any local variables in the block). + +This narrowing of the temporary scope may cause programs to fail to compile in 2024. For example: + +```rust,edition2024,E0716,compile_fail +// This example works in 2021, but fails to compile in 2024. +fn main() { + let x = { &String::from("1234") }.len(); +} +``` + +In this example, in 2021, the temporary `String` is extended outside of the block, past the call to `len()`, and is dropped at the end of the statement. In 2024, it is dropped immediately at the end of the block, causing a compile error about the temporary being dropped while borrowed. + +The solution for these kinds of situations is to lift the block expression out to a local variable so that the temporary lives long enough: + +```rust,edition2024 +fn main() { + let s = { &String::from("1234") }; + let x = s.len(); +} +``` + +This particular example takes advantage of [temporary lifetime extension]. Temporary lifetime extension is a set of specific rules which allow temporaries to live longer than they normally would. Because the `String` temporary is behind a reference, the `String` temporary is extended long enough for the next statement to call `len()` on it. + +See the [`if let` temporary scope] chapter for a similar change made to temporary scopes of `if let` expressions. + +[`if let` temporary scope]: temporary-if-let-scope.md +[temporary scope rules]: ../../reference/destructors.html#temporary-scopes +[temporary lifetime extension]: ../../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 diff --git a/src/rust-2024/unsafe-attributes.md b/src/rust-2024/unsafe-attributes.md new file mode 100644 index 0000000..16edf5a --- /dev/null +++ b/src/rust-2024/unsafe-attributes.md @@ -0,0 +1,77 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Unsafe attributes + +## Summary + +- The following attributes must now be marked as `unsafe`: + - [`export_name`] + - [`link_section`] + - [`no_mangle`] + +[`export_name`]: ../../reference/abi.html#the-export_name-attribute +[`link_section`]: ../../reference/abi.html#the-link_section-attribute +[`no_mangle`]: ../../reference/abi.html#the-no_mangle-attribute + +## Details + +Rust 1.82 added the ability in all editions to mark certain attributes as `unsafe` to indicate that they have soundness requirements that must be upheld.[^RFC3325] The syntax for an unsafe attribute looks like this: + +```rust +// SAFETY: there is no other global function of this name +#[unsafe(no_mangle)] +pub fn example() {} +``` + +Marking the attribute with `unsafe` highlights that there are safety requirements that must be upheld that the compiler cannot verify on its own. + +Starting with the 2024 Edition, it is now required to mark these attributes as `unsafe`. The following section describes the safety requirements for these attributes. + +[^RFC3325]: See [RFC 3325](https://rust-lang.github.io/rfcs/3325-unsafe-attributes.html) for the original proposal. + +### Safety requirements + +The [`no_mangle`], [`export_name`], and [`link_section`] attributes influence the symbol names and linking behavior of items. Care must be taken to ensure that these attributes are used correctly. + +Because the set of symbols across all linked libraries is a global namespace, there can be issues if there is a symbol name collision between libraries. Typically this isn't an issue for normally defined functions because [symbol mangling] helps ensure that the symbol name is unique. However, attributes like `export_name` can upset that assumption of uniqueness. + +For example, in previous editions the following crashes on most Unix-like platforms despite containing only safe code: + +```rust,no_run,edition2021 +fn main() { + println!("Hello, world!"); +} + +#[export_name = "malloc"] +fn foo() -> usize { 1 } +``` + +In the 2024 Edition, it is now required to mark these attributes as unsafe to emphasize that it is required to ensure that the symbol is defined correctly: + +```rust,edition2024 +// SAFETY: There should only be a single definition of the loop symbol. +#[unsafe(export_name="loop")] +fn arduino_loop() { + // ... +} +``` + +[symbol mangling]: ../../rustc/symbol-mangling/index.html +[`unsafe_attr_outside_unsafe`]: ../../rustc/lints/listing/allowed-by-default.html#unsafe-attr-outside-unsafe + +## Migration + +The [`unsafe_attr_outside_unsafe`] lint can update these attributes to use the `unsafe(...)` format. The lint is part of the `rust-2024-compatibility` lint group which is included in the automatic edition migration. In order to migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +Just beware that this automatic migration will not be able to verify that these attributes are being used correctly. It is still your responsibility to manually review their usage. + +Alternatively, you can manually enable the lint to find places where these attributes need to be updated. + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(unsafe_attr_outside_unsafe)] +``` diff --git a/src/rust-2024/unsafe-extern.md b/src/rust-2024/unsafe-extern.md new file mode 100644 index 0000000..7affe13 --- /dev/null +++ b/src/rust-2024/unsafe-extern.md @@ -0,0 +1,56 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# Unsafe `extern` blocks + +## Summary + +- [`extern` blocks] must now be marked with the `unsafe` keyword. + +[`extern` blocks]: ../../reference/items/external-blocks.html + +## Details + +Rust 1.82 added the ability in all editions to mark [`extern` blocks] with the `unsafe` keyword.[^RFC3484] Adding the `unsafe` keyword helps to emphasize that it is the responsibility of the author of the `extern` block to ensure that the signatures are correct. If the signatures are not correct, then it may result in undefined behavior. + +The syntax for an unsafe `extern` block looks like this: + +```rust +unsafe extern "C" { + // sqrt (from libm) may be called with any `f64` + pub safe fn sqrt(x: f64) -> f64; + + // strlen (from libc) requires a valid pointer, + // so we mark it as being an unsafe fn + pub unsafe fn strlen(p: *const std::ffi::c_char) -> usize; + + // this function doesn't say safe or unsafe, so it defaults to unsafe + pub fn free(p: *mut core::ffi::c_void); + + pub safe static IMPORTANT_BYTES: [u8; 256]; +} +``` + +In addition to being able to mark an `extern` block as `unsafe`, you can also specify if individual items in the `extern` block are `safe` or `unsafe`. Items marked as `safe` can be used without an `unsafe` block. + +Starting with the 2024 Edition, it is now required to include the `unsafe` keyword on an `extern` block. This is intended to make it very clear that there are safety requirements that must be upheld by the extern definitions. + +[^RFC3484]: See [RFC 3484](https://github.com/rust-lang/rfcs/blob/master/text/3484-unsafe-extern-blocks.md) for the original proposal. + +## Migration + +The [`missing_unsafe_on_extern`] lint can update `extern` blocks to add the `unsafe` keyword. The lint is part of the `rust-2024-compatibility` lint group which is included in the automatic edition migration. In order to migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +Just beware that this automatic migration will not be able to verify that the signatures in the `extern` block are correct. It is still your responsibility to manually review their definition. + +Alternatively, you can manually enable the lint to find places where there are `unsafe` blocks that need to be updated. + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(missing_unsafe_on_extern)] +``` + +[`missing_unsafe_on_extern`]: ../../rustc/lints/listing/allowed-by-default.html#missing-unsafe-on-extern diff --git a/src/rust-2024/unsafe-op-in-unsafe-fn.md b/src/rust-2024/unsafe-op-in-unsafe-fn.md new file mode 100644 index 0000000..0a7844f --- /dev/null +++ b/src/rust-2024/unsafe-op-in-unsafe-fn.md @@ -0,0 +1,58 @@ +> **Rust Edition Guide は現在 Rust 2024 のアップデート作業に向けて翻訳作業中です。本ページは英語版をコピーしていますが、一部のリンクが動作しないなどの問題が発生する場合があります。問題が発生した場合は、[原文(英語版)](https://doc.rust-lang.org/nightly/edition-guide/introduction.html)をご参照ください。** + +# unsafe_op_in_unsafe_fn warning + +## Summary + +- The [`unsafe_op_in_unsafe_fn`] lint now warns by default. + This warning detects calls to unsafe operations in unsafe functions without an explicit unsafe block. + +[`unsafe_op_in_unsafe_fn`]: ../../rustc/lints/listing/allowed-by-default.html#unsafe-op-in-unsafe-fn + +## Details + +The [`unsafe_op_in_unsafe_fn`] lint will fire if there are [unsafe operations] in an unsafe function without an explicit [`unsafe {}` block][unsafe-block]. + +```rust +# #![warn(unsafe_op_in_unsafe_fn)] +unsafe fn get_unchecked(x: &[T], i: usize) -> &T { + x.get_unchecked(i) // WARNING: requires unsafe block +} +``` + +The solution is to wrap any unsafe operations in an `unsafe` block: + +```rust +# #![deny(unsafe_op_in_unsafe_fn)] +unsafe fn get_unchecked(x: &[T], i: usize) -> &T { + unsafe { x.get_unchecked(i) } +} +``` + +This change is intended to help protect against accidental use of unsafe operations in an unsafe function. +The `unsafe` function keyword was performing two roles. +One was to declare that *calling* the function requires unsafe, and that the caller is responsible to uphold additional safety requirements. +The other role was to allow the use of unsafe operations inside of the function. +This second role was determined to be too risky without explicit `unsafe` blocks. + +More information and motivation may be found in [RFC #2585]. + +[unsafe operations]: ../../reference/unsafety.html +[unsafe-block]: ../../reference/expressions/block-expr.html#unsafe-blocks +[RFC #2585]: https://rust-lang.github.io/rfcs/2585-unsafe-block-in-unsafe-fn.html + +## Migration + +The [`unsafe_op_in_unsafe_fn`] lint is part of the `rust-2024-compatibility` lint group. +In order to migrate your code to be Rust 2024 Edition compatible, run: + +```sh +cargo fix --edition +``` + +Alternatively, you can manually enable the lint to find places where unsafe blocks need to be added, or switch it to `allow` to silence the lint completely. + +```rust +// Add this to the root of your crate to do a manual migration. +#![warn(unsafe_op_in_unsafe_fn)] +```