Skip to content

Commit 51ae1e9

Browse files
authored
Merge pull request #1604 from Mark-Simulacrum/1.87.0
1.87.0 announcement
2 parents 1437021 + 2736a6a commit 51ae1e9

File tree

2 files changed

+265
-0
lines changed

2 files changed

+265
-0
lines changed

content/Rust-1.87.0/index.md

+265
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
+++
2+
path = "2025/05/15/Rust-1.87.0"
3+
title = "Announcing Rust 1.87.0 and ten years of Rust!"
4+
authors = ["The Rust Release Team"]
5+
aliases = [
6+
"2025/05/15/Rust-1.87.0.html",
7+
"releases/1.87.0",
8+
]
9+
10+
[extra]
11+
release = true
12+
+++
13+
14+
Live from the [10 Years of Rust celebration](https://2025.rustweek.org/celebration/) in Utrecht, Netherlands,
15+
the Rust team is happy to announce a new version of Rust, 1.87.0!
16+
17+
![picture of Rustaceans at the release party](party.jpg)
18+
19+
Today's release day happens to fall exactly on the 10 year anniversary of
20+
[Rust 1.0](https://blog.rust-lang.org/2015/05/15/Rust-1.0/)!
21+
22+
Thank you to the myriad contributors who have worked on Rust, past and present.
23+
Here's to many more decades of Rust! 🎉
24+
25+
---
26+
27+
As usual, the new version includes all the changes that have been part of the beta version in the
28+
past six weeks, following the consistent regular release cycle that we have followed since Rust 1.0.
29+
30+
If you have a previous version of Rust installed via `rustup`, you can get 1.87.0 with:
31+
32+
```
33+
$ rustup update stable
34+
```
35+
36+
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.87.0](https://doc.rust-lang.org/stable/releases.html#version-1870-2025-04-03).
37+
38+
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!
39+
40+
## What's in 1.87.0 stable
41+
42+
### Anonymous pipes
43+
44+
1.87 adds access to anonymous pipes to the standard library. This includes
45+
integration with `std::process::Command`'s input/output methods. For example,
46+
joining the stdout and stderr streams into one is now relatively
47+
straightforward, as shown below, while it used to require either extra threads
48+
or platform-specific functions.
49+
50+
```rust
51+
use std::process::Command;
52+
use std::io::Read;
53+
54+
let (mut recv, send) = std::io::pipe()?;
55+
56+
let mut command = Command::new("path/to/bin")
57+
// Both stdout and stderr will write to the same pipe, combining the two.
58+
.stdout(send.try_clone()?)
59+
.stderr(send)
60+
.spawn()?;
61+
62+
let mut output = Vec::new();
63+
recv.read_to_end(&mut output)?;
64+
65+
// It's important that we read from the pipe before the process exits, to avoid
66+
// filling the OS buffers if the program emits too much output.
67+
assert!(command.wait()?.success());
68+
```
69+
70+
### Safe architecture intrinsics
71+
72+
Most `std::arch` intrinsics that are unsafe only due to requiring target
73+
features to be enabled are now callable in safe code that has those features
74+
enabled. For example, the following toy program which implements summing an array using
75+
manual intrinsics can now use safe code for the core loop.
76+
77+
```rust
78+
#![forbid(unsafe_op_in_unsafe_fn)]
79+
80+
use std::arch::x86_64::*;
81+
82+
fn sum(slice: &[u32]) -> u32 {
83+
#[cfg(target_arch = "x86_64")]
84+
{
85+
if is_x86_feature_detected!("avx2") {
86+
// SAFETY: We have detected the feature is enabled at runtime,
87+
// so it's safe to call this function.
88+
return unsafe { sum_avx2(slice) };
89+
}
90+
}
91+
92+
slice.iter().sum()
93+
}
94+
95+
#[target_feature(enable = "avx2")]
96+
#[cfg(target_arch = "x86_64")]
97+
fn sum_avx2(slice: &[u32]) -> u32 {
98+
// SAFETY: __m256i and u32 have the same validity.
99+
let (prefix, middle, tail) = unsafe { slice.align_to::<__m256i>() };
100+
101+
let mut sum = prefix.iter().sum::<u32>();
102+
sum += tail.iter().sum::<u32>();
103+
104+
// Core loop is now fully safe code in 1.87, because the intrinsics require
105+
// matching target features (avx2) to the function definition.
106+
let mut base = _mm256_setzero_si256();
107+
for e in middle.iter() {
108+
base = _mm256_add_epi32(base, *e);
109+
}
110+
111+
// SAFETY: __m256i and u32 have the same validity.
112+
let base: [u32; 8] = unsafe { std::mem::transmute(base) };
113+
sum += base.iter().sum::<u32>();
114+
115+
sum
116+
}
117+
```
118+
119+
### `asm!` jumps to Rust code
120+
121+
Inline assembly (`asm!`) can now jump to labeled blocks within Rust code. This
122+
enables more flexible low-level programming, such as implementing optimized
123+
control flow in OS kernels or interacting with hardware more efficiently.
124+
125+
- The `asm!` macro now supports a label operand, which acts as a jump target.
126+
- The label must be a block expression with a return type of `()` or `!`.
127+
- The block executes when jumped to, and execution continues after the `asm!` block.
128+
- Using output and label operands in the same `asm!` invocation remains [unstable](https://github.com/rust-lang/rust/issues/119364).
129+
130+
```rust
131+
unsafe {
132+
asm!(
133+
"jmp {}",
134+
label {
135+
println!("Jumped from asm!");
136+
}
137+
);
138+
}
139+
```
140+
141+
For more details, please consult the [reference](https://doc.rust-lang.org/nightly/reference/inline-assembly.html#r-asm.operand-type.supported-operands.label).
142+
143+
### Precise capturing (`+ use<...>`) in `impl Trait` in trait definitions
144+
145+
This release stabilizes specifying the specific captured generic types and
146+
lifetimes in trait definitions using `impl Trait` return types. This allows
147+
using this feature in trait definitions, expanding on the stabilization for
148+
non-trait functions in
149+
[1.82](https://blog.rust-lang.org/2024/10/17/Rust-1.82.0/#precise-capturing-use-syntax).
150+
151+
Some example desugarings:
152+
153+
```rust
154+
trait Foo {
155+
fn method<'a>(&'a self) -> impl Sized;
156+
157+
// ... desugars to something like:
158+
type Implicit1<'a>: Sized;
159+
fn method_desugared<'a>(&'a self) -> Self::Implicit1<'a>;
160+
161+
// ... whereas with precise capturing ...
162+
fn precise<'a>(&'a self) -> impl Sized + use<Self>;
163+
164+
// ... desugars to something like:
165+
type Implicit2: Sized;
166+
fn precise_desugared<'a>(&'a self) -> Self::Implicit2;
167+
}
168+
```
169+
170+
### Stabilized APIs
171+
172+
173+
- [`Vec::extract_if`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.extract_if)
174+
- [`vec::ExtractIf`](https://doc.rust-lang.org/stable/std/vec/struct.ExtractIf.html)
175+
- [`LinkedList::extract_if`](https://doc.rust-lang.org/stable/std/collections/struct.LinkedList.html#method.extract_if)
176+
- [`linked_list::ExtractIf`](https://doc.rust-lang.org/stable/std/collections/linked_list/struct.ExtractIf.html)
177+
- [`<[T]>::split_off`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off)
178+
- [`<[T]>::split_off_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_mut)
179+
- [`<[T]>::split_off_first`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_first)
180+
- [`<[T]>::split_off_first_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_first_mut)
181+
- [`<[T]>::split_off_last`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_last)
182+
- [`<[T]>::split_off_last_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_off_last_mut)
183+
- [`String::extend_from_within`](https://doc.rust-lang.org/stable/alloc/string/struct.String.html#method.extend_from_within)
184+
- [`os_str::Display`](https://doc.rust-lang.org/stable/std/ffi/os_str/struct.Display.html)
185+
- [`OsString::display`](https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.display)
186+
- [`OsStr::display`](https://doc.rust-lang.org/stable/std/ffi/struct.OsStr.html#method.display)
187+
- [`io::pipe`](https://doc.rust-lang.org/stable/std/io/fn.pipe.html)
188+
- [`io::PipeReader`](https://doc.rust-lang.org/stable/std/io/struct.PipeReader.html)
189+
- [`io::PipeWriter`](https://doc.rust-lang.org/stable/std/io/struct.PipeWriter.html)
190+
- [`impl From<PipeReader> for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeReader%3E-for-OwnedHandle)
191+
- [`impl From<PipeWriter> for OwnedHandle`](https://doc.rust-lang.org/stable/std/os/windows/io/struct.OwnedHandle.html#impl-From%3CPipeWriter%3E-for-OwnedHandle)
192+
- [`impl From<PipeReader> for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html)
193+
- [`impl From<PipeWriter> for Stdio`](https://doc.rust-lang.org/stable/std/process/struct.Stdio.html#impl-From%3CPipeWriter%3E-for-Stdio)
194+
- [`impl From<PipeReader> for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeReader%3E-for-OwnedFd)
195+
- [`impl From<PipeWriter> for OwnedFd`](https://doc.rust-lang.org/stable/std/os/fd/struct.OwnedFd.html#impl-From%3CPipeWriter%3E-for-OwnedFd)
196+
- [`Box<MaybeUninit<T>>::write`](https://doc.rust-lang.org/stable/std/boxed/struct.Box.html#method.write)
197+
- [`impl TryFrom<Vec<u8>> for String`](https://doc.rust-lang.org/stable/std/string/struct.String.html#impl-TryFrom%3CVec%3Cu8%3E%3E-for-String)
198+
- [`<*const T>::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from_unsigned)
199+
- [`<*const T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.byte_offset_from_unsigned)
200+
- [`<*mut T>::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from_unsigned-1)
201+
- [`<*mut T>::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.byte_offset_from_unsigned-1)
202+
- [`NonNull::offset_from_unsigned`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.offset_from_unsigned)
203+
- [`NonNull::byte_offset_from_unsigned`](https://doc.rust-lang.org/stable/std/ptr/struct.NonNull.html#method.byte_offset_from_unsigned)
204+
- [`<uN>::cast_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.cast_signed)
205+
- [`NonZero::<uN>::cast_signed`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_signed-5).
206+
- [`<iN>::cast_unsigned`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.cast_unsigned).
207+
- [`NonZero::<iN>::cast_unsigned`](https://doc.rust-lang.org/stable/std/num/struct.NonZero.html#method.cast_unsigned-5).
208+
- [`<uN>::is_multiple_of`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.is_multiple_of)
209+
- [`<uN>::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shl)
210+
- [`<uN>::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unbounded_shr)
211+
- [`<iN>::unbounded_shl`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shl)
212+
- [`<iN>::unbounded_shr`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unbounded_shr)
213+
- [`<iN>::midpoint`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.midpoint)
214+
- [`<str>::from_utf8`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8)
215+
- [`<str>::from_utf8_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_mut)
216+
- [`<str>::from_utf8_unchecked`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked)
217+
- [`<str>::from_utf8_unchecked_mut`](https://doc.rust-lang.org/stable/std/primitive.str.html#method.from_utf8_unchecked_mut)
218+
219+
These previously stable APIs are now stable in const contexts:
220+
221+
- [`core::str::from_utf8_mut`](https://doc.rust-lang.org/stable/std/str/fn.from_utf8_mut.html)
222+
- [`<[T]>::copy_from_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.copy_from_slice)
223+
- [`SocketAddr::set_ip`](https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html#method.set_ip)
224+
- [`SocketAddr::set_port`](https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html#method.set_port),
225+
- [`SocketAddrV4::set_ip`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV4.html#method.set_ip)
226+
- [`SocketAddrV4::set_port`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV4.html#method.set_port),
227+
- [`SocketAddrV6::set_ip`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_ip)
228+
- [`SocketAddrV6::set_port`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_port)
229+
- [`SocketAddrV6::set_flowinfo`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_flowinfo)
230+
- [`SocketAddrV6::set_scope_id`](https://doc.rust-lang.org/stable/std/net/struct.SocketAddrV6.html#method.set_scope_id)
231+
- [`char::is_digit`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_digit)
232+
- [`char::is_whitespace`](https://doc.rust-lang.org/stable/std/primitive.char.html#method.is_whitespace)
233+
- [`<[[T; N]]>::as_flattened`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_flattened)
234+
- [`<[[T; N]]>::as_flattened_mut`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_flattened_mut)
235+
- [`String::into_bytes`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.into_bytes)
236+
- [`String::as_str`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_str)
237+
- [`String::capacity`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.capacity)
238+
- [`String::as_bytes`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_bytes)
239+
- [`String::len`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.len)
240+
- [`String::is_empty`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.is_empty)
241+
- [`String::as_mut_str`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_mut_str)
242+
- [`String::as_mut_vec`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.as_mut_vec)
243+
- [`Vec::as_ptr`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_ptr)
244+
- [`Vec::as_slice`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_slice)
245+
- [`Vec::capacity`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.capacity)
246+
- [`Vec::len`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.len)
247+
- [`Vec::is_empty`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.is_empty)
248+
- [`Vec::as_mut_slice`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_mut_slice)
249+
- [`Vec::as_mut_ptr`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.as_mut_ptr)
250+
251+
### `i586-pc-windows-msvc` target removal
252+
253+
The Tier 2 target `i586-pc-windows-msvc` has been removed. `i586-pc-windows-msvc`'s difference to the much more popular Tier 1 target `i686-pc-windows-msvc` is that `i586-pc-windows-msvc` does not require SSE2 instruction support. But Windows 10, the minimum required OS version of all `windows` targets (except the `win7` targets), requires SSE2 instructions itself.
254+
255+
All users currently targeting `i586-pc-windows-msvc` should migrate to `i686-pc-windows-msvc`.
256+
257+
You can check the [Major Change Proposal](https://github.com/rust-lang/compiler-team/issues/840) for more information.
258+
259+
### Other changes
260+
261+
Check out everything that changed in [Rust](https://github.com/rust-lang/rust/releases/tag/1.87.0), [Cargo](https://doc.rust-lang.org/nightly/cargo/CHANGELOG.html#cargo-187-2025-05-15), and [Clippy](https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-187).
262+
263+
## Contributors to 1.87.0
264+
265+
Many people came together to create Rust 1.87.0. We couldn't have done it without all of you. [Thanks!](https://thanks.rust-lang.org/rust/1.87.0/)

content/Rust-1.87.0/party.jpg

249 KB
Loading

0 commit comments

Comments
 (0)