|
| 1 | ++++ |
| 2 | +path = "2025/08/07/Rust-1.89.0" |
| 3 | +title = "Announcing Rust 1.89.0" |
| 4 | +authors = ["The Rust Release Team"] |
| 5 | +aliases = ["releases/1.89.0"] |
| 6 | + |
| 7 | +[extra] |
| 8 | +release = true |
| 9 | ++++ |
| 10 | + |
| 11 | +The Rust team is happy to announce a new version of Rust, 1.89.0. Rust is a programming language empowering everyone to build reliable and efficient software. |
| 12 | + |
| 13 | +If you have a previous version of Rust installed via `rustup`, you can get 1.89.0 with: |
| 14 | + |
| 15 | +```console |
| 16 | +$ rustup update stable |
| 17 | +``` |
| 18 | + |
| 19 | +If you don't have it already, you can [get `rustup`](https://www.rust-lang.org/install.html) from the appropriate page on our website, and check out the [detailed release notes for 1.89.0](https://doc.rust-lang.org/stable/releases.html#version-1890-2025-08-07). |
| 20 | + |
| 21 | +If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (`rustup default beta`) or the nightly channel (`rustup default nightly`). Please [report](https://github.com/rust-lang/rust/issues/new/choose) any bugs you might come across! |
| 22 | + |
| 23 | +## What's in 1.89.0 stable |
| 24 | + |
| 25 | +### Explicitly inferred arguments to const generics |
| 26 | + |
| 27 | +Rust now supports `_` as an argument to const generic parameters, inferring the value from surrounding context: |
| 28 | + |
| 29 | +```rust |
| 30 | +pub fn all_false<const LEN: usize>() -> [bool; LEN] { |
| 31 | + [false; _] |
| 32 | +} |
| 33 | +``` |
| 34 | + |
| 35 | +Similar to the rules for when `_` is permitted as a type, `_` is not permitted as an argument to const generics when in a signature: |
| 36 | + |
| 37 | +```rust |
| 38 | +// This is not allowed |
| 39 | +pub const fn all_false<const LEN: usize>() -> [bool; _] { |
| 40 | + [false; LEN] |
| 41 | +} |
| 42 | + |
| 43 | +// Neither is this |
| 44 | +pub const ALL_FALSE: [bool; _] = all_false::<10>(); |
| 45 | +``` |
| 46 | + |
| 47 | +### Mismatched lifetime syntaxes lint |
| 48 | + |
| 49 | +[Lifetime elision][elision] in function signatures is an ergonomic aspect of the Rust language, but it can also be a stumbling point for newcomers and experts alike. This is especially true when lifetimes are inferred in types where it isn't syntactically obvious that a lifetime is even present: |
| 50 | + |
| 51 | +```rust |
| 52 | +// The returned type `std::slice::Iter` has a lifetime, |
| 53 | +// but there's no visual indication of that. |
| 54 | +// |
| 55 | +// Lifetime elision infers the lifetime of the return |
| 56 | +// type to be the same as that of `scores`. |
| 57 | +fn items(scores: &[u8]) -> std::slice::Iter<u8> { |
| 58 | + scores.iter() |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +Code like this will now produce a warning by default: |
| 63 | + |
| 64 | +```text |
| 65 | +warning: hiding a lifetime that's elided elsewhere is confusing |
| 66 | + --> src/lib.rs:1:18 |
| 67 | + | |
| 68 | +1 | fn items(scores: &[u8]) -> std::slice::Iter<u8> { |
| 69 | + | ^^^^^ -------------------- the same lifetime is hidden here |
| 70 | + | | |
| 71 | + | the lifetime is elided here |
| 72 | + | |
| 73 | + = help: the same lifetime is referred to in inconsistent ways, making the signature confusing |
| 74 | + = note: `#[warn(mismatched_lifetime_syntaxes)]` on by default |
| 75 | +help: use `'_` for type paths |
| 76 | + | |
| 77 | +1 | fn items(scores: &[u8]) -> std::slice::Iter<'_, u8> { |
| 78 | + | +++ |
| 79 | +``` |
| 80 | + |
| 81 | +We [first attempted][elided_lifetime_in_path] to improve this situation back in 2018 as part of the [`rust_2018_idioms`][2018-by-default] lint group, but [strong feedback][bevy] about the `elided_lifetimes_in_paths` lint showed that it was too blunt of a hammer as it warns about lifetimes which don't matter to understand the function: |
| 82 | + |
| 83 | +```rust |
| 84 | +use std::fmt; |
| 85 | + |
| 86 | +struct Greeting; |
| 87 | + |
| 88 | +impl fmt::Display for Greeting { |
| 89 | + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 90 | + // -----^^^^^^^^^ expected lifetime parameter |
| 91 | + // Knowing that `Formatter` has a lifetime does not help the programmer |
| 92 | + "howdy".fmt(f) |
| 93 | + } |
| 94 | +} |
| 95 | +``` |
| 96 | + |
| 97 | +We then realized that the confusion we want to eliminate occurs when both |
| 98 | + |
| 99 | +1. lifetime elision inference rules *connect* an input lifetime to an output lifetime |
| 100 | +2. it's not syntactically obvious that a lifetime exists |
| 101 | + |
| 102 | +There are two pieces of Rust syntax that indicate that a lifetime exists: `&` and `'`, with `'` being subdivided into the inferred lifetime `'_` and named lifetimes `'a`. When a type uses a named lifetime, lifetime elision will not infer a lifetime for that type. Using these criteria, we can construct three groups: |
| 103 | + |
| 104 | +| Self-evident it has a lifetime | Allow lifetime elision to infer a lifetime | Examples | |
| 105 | +|--------------------------------|--------------------------------------------|---------------------------------------| |
| 106 | +| No | Yes | `ContainsLifetime` | |
| 107 | +| Yes | Yes | `&T`, `&'_ T`, `ContainsLifetime<'_>` | |
| 108 | +| Yes | No | `&'a T`, `ContainsLifetime<'a>` | |
| 109 | + |
| 110 | +The `mismatched_lifetime_syntaxes` lint checks that the inputs and outputs of a function belong to the same group. For the initial motivating example above, `&[u8]` falls into the second group while `std::slice::Iter<u8>` falls into the first group. We say that the lifetimes in the first group are *hidden*. |
| 111 | + |
| 112 | +Because the input and output lifetimes belong to different groups, the lint will warn about this function, reducing confusion about when a value has a meaningful lifetime that isn't visually obvious. |
| 113 | + |
| 114 | +The `mismatched_lifetime_syntaxes` lint supersedes the `elided_named_lifetimes` lint, which did something similar for named lifetimes specifically. |
| 115 | + |
| 116 | +Future work on the `elided_lifetimes_in_paths` lint intends to split it into more focused sub-lints with an eye to warning about a subset of them eventually. |
| 117 | + |
| 118 | +[elision]: https://doc.rust-lang.org/1.89/book/ch10-03-lifetime-syntax.html#lifetime-elision |
| 119 | +[elided_lifetime_in_path]: https://github.com/rust-lang/rust/pull/46254 |
| 120 | +[2018-by-default]: https://github.com/rust-lang/rust/issues/54910 |
| 121 | +[bevy]: https://github.com/rust-lang/rust/issues/131725 |
| 122 | + |
| 123 | +### More x86 target features |
| 124 | + |
| 125 | +The `target_feature` attribute now supports the `sha512`, `sm3`, `sm4`, `kl` and `widekl` target features on x86. Additionally a number of `avx512` intrinsics and target features are also supported on x86: |
| 126 | + |
| 127 | +```rust |
| 128 | +#[target_feature(enable = "avx512bw")] |
| 129 | +pub fn cool_simd_code(/* .. */) -> /* ... */ { |
| 130 | + /* ... */ |
| 131 | +} |
| 132 | + |
| 133 | +``` |
| 134 | + |
| 135 | +### Cross-compiled doctests |
| 136 | + |
| 137 | +Doctests will now be tested when running `cargo test --doc --target other_target`, this may result in some amount of breakage due to would-be-failing doctests now being tested. |
| 138 | + |
| 139 | +Failing tests can be disabled by annotating the doctest with `ignore-<target>`: |
| 140 | +```rust |
| 141 | +/// ```ignore-x86_64 |
| 142 | +/// panic!("something") |
| 143 | +/// ``` |
| 144 | +pub fn my_function() { } |
| 145 | +``` |
| 146 | + |
| 147 | +### `i128` and `u128` in `extern "C"` functions |
| 148 | + |
| 149 | +`i128` and `u128` no longer trigger the `improper_ctypes_definitions` lint, meaning these types may be used in `extern "C"` functions without warning. This comes with some caveats: |
| 150 | + |
| 151 | +* The Rust types are ABI- and layout-compatible with (unsigned) `__int128` in C when the type is available. |
| 152 | +* On platforms where `__int128` is not available, `i128` and `u128` do not necessarily align with any C type. |
| 153 | +* `i128` is _not_ necessarily compatible with `_BitInt(128)` on any platform, because `_BitInt(128)` and `__int128` may not have the same ABI (as is the case on x86-64). |
| 154 | + |
| 155 | +This is the last bit of follow up to the layout changes from last year: https://blog.rust-lang.org/2024/03/30/i128-layout-update/. |
| 156 | + |
| 157 | +### Demoting `x86_64-apple-darwin` to Tier 2 with host tools |
| 158 | + |
| 159 | +GitHub will soon [discontinue][gha-sunset] providing free macOS x86\_64 runners for public repositories. Apple has also announced their [plans][apple] for discontinuing support for the x86\_86 architecture. |
| 160 | + |
| 161 | +In accordance with these changes, the Rust project is in the [process of demoting the `x86_64-apple-darwin` target][rfc] from Tier 1 to Tier 2 with host tools. This means that the target, including tools like `rustc` and `cargo`, will be guaranteed to build but is not guaranteed to pass our automated test suite. |
| 162 | + |
| 163 | +We expect that the RFC for the demotion to Tier 2 with host tools will be accepted between the releases of Rust 1.89 and 1.90, which means that Rust 1.89 will be the last release of Rust where `x86_64-apple-darwin` is a Tier 1 target. |
| 164 | + |
| 165 | +For users, nothing will change. Builds of both the standard library and the compiler will still be distributed by the Rust Project for use via `rustup` or alternative installation methods. |
| 166 | + |
| 167 | +[apple]: https://en.wikipedia.org/wiki/Mac_transition_to_Apple_silicon#Timeline |
| 168 | +[gha-sunset]: https://github.blog/changelog/2025-07-11-upcoming-changes-to-macos-hosted-runners-macos-latest-migration-and-xcode-support-policy-updates/#macos-13-is-closing-down |
| 169 | +[rfc]: https://github.com/rust-lang/rfcs/pull/3841 |
| 170 | + |
| 171 | +### Standards Compliant C ABI on the `wasm32-unknown-unknown` target |
| 172 | + |
| 173 | +`extern "C"` functions on the `wasm32-unknown-unknown` target now have a standards compliant ABI. See this blog post for more information: https://blog.rust-lang.org/2025/04/04/c-abi-changes-for-wasm32-unknown-unknown. |
| 174 | + |
| 175 | +### Platform Support |
| 176 | + |
| 177 | +- [`x86_64-apple-darwin` is in the process of being demoted to Tier 2 with host tools](https://github.com/rust-lang/rfcs/pull/3841) |
| 178 | +- [Add new Tier-3 targets `loongarch32-unknown-none` and `loongarch32-unknown-none-softfloat`](https://github.com/rust-lang/rust/pull/142053) |
| 179 | + |
| 180 | +Refer to Rust’s [platform support page][platform_support_page] for more information on Rust’s tiered platform support. |
| 181 | + |
| 182 | +### Stabilized APIs |
| 183 | + |
| 184 | +- [`NonZero<char>`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html) |
| 185 | +- Many intrinsics for x86, not enumerated here |
| 186 | + - [AVX512 intrinsics](https://github.com/rust-lang/rust/issues/111137) |
| 187 | + - [`SHA512`, `SM3` and `SM4` intrinsics](https://github.com/rust-lang/rust/issues/126624) |
| 188 | +- [`File::lock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.lock) |
| 189 | +- [`File::lock_shared`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.lock_shared) |
| 190 | +- [`File::try_lock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_lock) |
| 191 | +- [`File::try_lock_shared`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_lock_shared) |
| 192 | +- [`File::unlock`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.unlock) |
| 193 | +- [`NonNull::from_ref`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.from_ref) |
| 194 | +- [`NonNull::from_mut`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.from_mut) |
| 195 | +- [`NonNull::without_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.without_provenance) |
| 196 | +- [`NonNull::with_exposed_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.with_exposed_provenance) |
| 197 | +- [`NonNull::expose_provenance`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.expose_provenance) |
| 198 | +- [`OsString::leak`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.leak) |
| 199 | +- [`PathBuf::leak`](https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.leak) |
| 200 | +- [`Result::flatten`](https://doc.rust-lang.org/stable/std/result/enum.Result.html#method.flatten) |
| 201 | +- [`std::os::linux::net::TcpStreamExt::quickack`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.TcpStreamExt.html#tymethod.quickack) |
| 202 | +- [`std::os::linux::net::TcpStreamExt::set_quickack`](https://doc.rust-lang.org/stable/std/os/linux/net/trait.TcpStreamExt.html#tymethod.set_quickack) |
| 203 | + |
| 204 | +These previously stable APIs are now stable in const contexts: |
| 205 | + |
| 206 | +- [`<[T; N]>::as_mut_slice`](https://doc.rust-lang.org/stable/std/primitive.array.html#method.as_mut_slice) |
| 207 | +- [`<[u8]>::eq_ignore_ascii_case`](https://doc.rust-lang.org/stable/std/primitive.slice.html#impl-%5Bu8%5D/method.eq_ignore_ascii_case) |
| 208 | +- [`str::eq_ignore_ascii_case`](https://doc.rust-lang.org/stable/std/primitive.str.html#impl-str/method.eq_ignore_ascii_case) |
| 209 | + |
| 210 | +### Other changes |
| 211 | + |
| 212 | +Check out everything that changed in [Rust](https://github.com/rust-lang/rust/releases/tag/1.89.0), [Cargo](https://doc.rust-lang.org/nightly/cargo/CHANGELOG.html#cargo-189-2025-08-07), and [Clippy](https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-189). |
| 213 | + |
| 214 | +## Contributors to 1.89.0 |
| 215 | + |
| 216 | +Many people came together to create Rust 1.89.0. We couldn't have done it without all of you. [Thanks!](https://thanks.rust-lang.org/rust/1.89.0/) |
| 217 | + |
| 218 | +[platform_support_page]: https://doc.rust-lang.org/rustc/platform-support.html |
0 commit comments