Announcing Rust 1.96
Source: Hacker News
Rust 1.96.0 Release
The Rust team is happy to announce a new version of Rust, 1.96.0. Rust is a programming language empowering everyone to build reliable and efficient software.
Installation
If you already have a previous version of Rust installed via rustup, upgrade to 1.96.0 with:
rustup update stable
If you don’t have rustup yet, you can get it here. For a full list of changes, see the detailed release notes for 1.96.0.
To help test future releases, consider switching to the beta or nightly channels:
rustup default beta # use the beta channel
rustup default nightly # use the nightly channel
Please report any bugs you encounter!
What’s New in 1.96.0 (stable)
New Range* Types
Many users expect Range and related core::ops types to be Copy, but they implement Iterator directly, and implementing both Iterator and Copy on the same type is a foot‑gun (see the Clippy lint).
RFC 3550 introduced replacement range types that implement IntoIterator instead of Iterator, allowing them to be Copy. The standard‑library portion of that RFC is now stable, adding:
core::range::Rangecore::range::RangeFromcore::range::RangeInclusive- Associated iterators
A future Rust version will also add core::range::RangeFull and core::range::RangeTo (re‑exports from core::ops) and move the current ranges to core::range::legacy::*. The 0..1 syntax still produces the legacy types for now, but will be updated to the new core::range types in a later edition.
Example
use core::range::Range;
#[derive(Clone, Copy)]
pub struct Span(Range);
impl Span {
pub fn of(self, s: &str) -> &str {
&s[self.0]
}
}
RangeInclusive now makes its fields public, unlike the legacy version which kept the exhausted‑iterator state hidden. When a concrete type is needed, prefer the new ranges—they will eventually become the default.
Tip: Library authors should consider using
impl RangeBoundsin public APIs; it accepts both legacy and new range types.
Assert‑Matching Macros
Two new macros, assert_matches! and debug_assert_matches!, check that a value matches a given pattern and panic with a Debug representation of the value if it does not. They are equivalent to assert!(matches!(..)) and debug_assert!(matches!(..)), but the printed value makes diagnosing failures easier.
These macros are not in the standard prelude (to avoid colliding with third‑party crates of the same name). Import them manually:
use core::assert_matches;
/// [Random Number](https://xkcd.com/221/)
fn get_random_number() -> u32 {
// chosen by a fair dice roll.
// guaranteed to be random.
4
}
fn main() {
assert_matches!(get_random_number(), 1..=6);
}
Changes to WebAssembly Targets
WebAssembly targets no longer pass --allow-undefined to the linker. Consequently, undefined symbols now cause a linker error instead of being silently turned into imports from the "env" module. This catches bugs earlier and prevents accidental symbol‑naming issues.
If you need the old behaviour, re‑enable it with:
RUSTFLAGS="-Clink-arg=--allow-undefined"
or by editing the source and using #[link(wasm_import_module = "env")] on the block defining the symbol.
The change was previously announced and takes effect in Rust 1.96.
Stabilized APIs
assert_matches!debug_assert_matches!From for AssertUnwindSafeFrom for LazyCellFrom for LazyLockcore::range::RangeToInclusivecore::range::RangeToInclusiveItercore::range::RangeFromcore::range::RangeFromItercore::range::Rangecore::range::RangeIter
Security Advisories
Rust 1.96 contains fixes for two vulnerabilities affecting users of third‑party registries.
- CVE‑2026‑5223 – a medium‑severity issue related to extraction of crate tarballs.
(Details of the second advisory were truncated in the source material.)
Security
- CVE‑2026‑5221 – A low‑severity issue related to handling of symlinks.
- CVE‑2026‑5222 – A low‑severity vulnerability concerning authentication with normalized URLs.
Note: Users of crates.io are not affected by either vulnerability.
Other changes
Check out everything that changed in:
Contributors to 1.96.0
Many people came together to create Rust 1.96.0. We couldn’t have done it without all of you.
Thanks!