Live from the 10 Years of Rust celebration in Utrecht, Netherlands, the Rust team is happy to announce a new version of Rust, 1.87.0!

Today's release day happens to fall exactly on the 10 year anniversary of Rust 1.0!
Thank you to the myriad contributors who have worked on Rust, past and present. Here's to many more decades of Rust! 🎉
As usual, the new version includes all the changes that have been part of the beta version in the past six weeks, following the consistent regular release cycle that we have followed since Rust 1.0.
If you have a previous version of Rust installed via rustup, you can get 1.87.0 with:
$ rustup update stable
If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.87.0.
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 any bugs you might come across!
What's in 1.87.0 stable
Anonymous pipes
1.87 adds access to anonymous pipes to the standard library. This includes
integration with std::process::Command's input/output methods. For example,
joining the stdout and stderr streams into one is now relatively
straightforward, as shown below, while it used to require either extra threads
or platform-specific functions.
use Command;
use Read;
let = pipe?;
let mut command = new
// Both stdout and stderr will write to the same pipe, combining the two.
.stdout
.stderr
.spawn?;
let mut output = Vecnew;
recv.read_to_end?;
// It's important that we read from the pipe before the process exits, to avoid
// filling the OS buffers if the program emits too much output.
assert!;
Safe architecture intrinsics
Most std::arch intrinsics that are unsafe only due to requiring target
features to be enabled are now callable in safe code that has those features
enabled. For example, the following toy program which implements summing an array using
manual intrinsics can now use safe code for the core loop.
use *;
asm! jumps to Rust code
Inline assembly (asm!) can now jump to labeled blocks within Rust code. This
enables more flexible low-level programming, such as implementing optimized
control flow in OS kernels or interacting with hardware more efficiently.
- The
asm!macro now supports a label operand, which acts as a jump target. - The label must be a block expression with a return type of
()or!. - The block executes when jumped to, and execution continues after the
asm!block. - Using output and label operands in the same
asm!invocation remains unstable.
unsafe
For more details, please consult the reference.
Precise capturing (+ use<...>) in impl Trait in trait definitions
This release stabilizes specifying the specific captured generic types and
lifetimes in trait definitions using impl Trait return types. This allows
using this feature in trait definitions, expanding on the stabilization for
non-trait functions in
1.82.
Some example desugarings:
Stabilized APIs
Vec::extract_ifvec::ExtractIfLinkedList::extract_iflinked_list::ExtractIf<[T]>::split_off<[T]>::split_off_mut<[T]>::split_off_first<[T]>::split_off_first_mut<[T]>::split_off_last<[T]>::split_off_last_mutString::extend_from_withinos_str::DisplayOsString::displayOsStr::displayio::pipeio::PipeReaderio::PipeWriterimpl From<PipeReader> for OwnedHandleimpl From<PipeWriter> for OwnedHandleimpl From<PipeReader> for Stdioimpl From<PipeWriter> for Stdioimpl From<PipeReader> for OwnedFdimpl From<PipeWriter> for OwnedFdBox<MaybeUninit<T>>::writeimpl TryFrom<Vec<u8>> for String<*const T>::offset_from_unsigned<*const T>::byte_offset_from_unsigned<*mut T>::offset_from_unsigned<*mut T>::byte_offset_from_unsignedNonNull::offset_from_unsignedNonNull::byte_offset_from_unsigned<uN>::cast_signedNonZero::<uN>::cast_signed.<iN>::cast_unsigned.NonZero::<iN>::cast_unsigned.<uN>::is_multiple_of<uN>::unbounded_shl<uN>::unbounded_shr<iN>::unbounded_shl<iN>::unbounded_shr<iN>::midpoint<str>::from_utf8<str>::from_utf8_mut<str>::from_utf8_unchecked<str>::from_utf8_unchecked_mut
These previously stable APIs are now stable in const contexts:
core::str::from_utf8_mut<[T]>::copy_from_sliceSocketAddr::set_ipSocketAddr::set_port,SocketAddrV4::set_ipSocketAddrV4::set_port,SocketAddrV6::set_ipSocketAddrV6::set_portSocketAddrV6::set_flowinfoSocketAddrV6::set_scope_idchar::is_digitchar::is_whitespace<[[T; N]]>::as_flattened<[[T; N]]>::as_flattened_mutString::into_bytesString::as_strString::capacityString::as_bytesString::lenString::is_emptyString::as_mut_strString::as_mut_vecVec::as_ptrVec::as_sliceVec::capacityVec::lenVec::is_emptyVec::as_mut_sliceVec::as_mut_ptr
i586-pc-windows-msvc target removal
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.
All users currently targeting i586-pc-windows-msvc should migrate to i686-pc-windows-msvc.
You can check the Major Change Proposal for more information.
Other changes
Check out everything that changed in Rust, Cargo, and Clippy.
Contributors to 1.87.0
Many people came together to create Rust 1.87.0. We couldn't have done it without all of you. Thanks!