{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreigveok7d54z4djtzodibakrjyfwzswtlhwx45ppsxqj5p3u7jd4k4",
"uri": "at://did:plc:lujatorbzcq2chhxnvjgc464/app.bsky.feed.post/3mmxgmn67nt62"
},
"path": "/2026/05/28/Rust-1.96.0/",
"publishedAt": "2026-05-28T00:00:00.000Z",
"site": "https://blog.rust-lang.org",
"tags": [
"get rustup",
"detailed release notes for 1.96.0",
"report",
"it is a footgun to implement both Iterator and Copy on the same type",
"RFC3550",
"previously announced",
"assert_matches!",
"debug_assert_matches!",
"From<T> for AssertUnwindSafe<T>",
"From<T> for LazyCell<T, F>",
"From<T> for LazyLock<T, F>",
"core::range::RangeToInclusive",
"core::range::RangeToInclusiveIter",
"core::range::RangeFrom",
"core::range::RangeFromIter",
"core::range::Range",
"core::range::RangeIter",
"CVE-2026-5223",
"CVE-2026-5222",
"Rust",
"Cargo",
"Clippy",
"Thanks!"
],
"textContent": "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.\n\nIf you have a previous version of Rust installed via `rustup`, you can get 1.96.0 with:\n\n\n $ rustup update stable\n\nIf 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.96.0.\n\nIf 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!\n\n## What's in 1.96.0 stable\n\n### New `Range*` types\n\nMany users expect `Range` and related `core::ops` types to be `Copy`, but this is not the case: they implement `Iterator` directly, and it is a footgun to implement both Iterator and Copy on the same type so this has been avoided. RFC3550 proposed a set of replacement range types that implement `IntoIterator` rather than `Iterator`, meaning they can also be `Copy`. The standard library portion of that RFC is now stable, introducing:\n\n * `core::range::Range`\n * `core::range::RangeFrom`\n * `core::range::RangeInclusive`\n * Associated iterators\n\n\n\nA Rust version in the near future will also add `core::range::RangeFull` and `core::range::RangeTo` as re-exports from `core::ops` (these do not implement `Iterator` and already implement `Copy`), and `core::range::legacy::*` as the new home for the current ranges. Range syntax like `0..1` still produces the legacy types for now, but will be updated to `core::range` types in a future edition.\n\nWith these stabilizations, it is now possible to store slice accessors in `Copy` types without splitting `start` and `end`:\n\n\n use core::range::Range; #[derive(Clone, Copy)] pub struct Span(Range<usize>); impl Span { pub fn of(self, s: &str) -> &str { &s[self.0] } }\n\nThe new `RangeInclusive` also makes its fields public, unlike the legacy version which avoided exposing the exhausted iterator state. This isn't a concern with the new type since it must be converted to begin iteration.\n\nLibrary authors should consider making use of `impl RangeBounds` in public API, which accepts both legacy and new range types. If a concrete type is needed, prefer using new ranges as this will eventually become the default.\n\n### Assert matching patterns\n\nThe new macros `assert_matches!` and `debug_assert_matches!` check that a value matches a given pattern, panicking with a `Debug` representation of the value otherwise. These are essentially the same as `assert!(matches!(..))` and `debug_assert!(matches!(..))`, but the printed value improves the possibility of diagnosing the failure.\n\nThese new macros have not been added to the standard prelude, because they would collide with popular third-party crates that provide macros with the same name. Instead, they should be manually imported from `core` or `std` before use.\n\n\n 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); }\n\n### Changes to WebAssembly targets\n\nWebAssembly targets no longer pass `--allow-undefined` to the linker which means that undefined symbols when linking are now a linker error instead of being converted to WebAssembly imports from the `\"env\"` module. This change prevents modules from linking unless all linking-related symbols are defined to catch bugs earlier and prevent accidental issues with symbol naming or similar.\n\nUndefined linking-related symbols are often indicative of build-time related bugs or misconfiguration. If, however, the old behavior is intended then it can be re-enabled with `RUSTFLAGS=-Clink-arg=--allow-undefined` or by editing the source code and using `#[link(wasm_import_module = \"env\")]` on the block defining the symbol.\n\nThis change was previously announced on this blog, and now takes effect in Rust 1.96.\n\n### Stabilized APIs\n\n * assert_matches!\n * debug_assert_matches!\n * From<T> for AssertUnwindSafe<T>\n * From<T> for LazyCell<T, F>\n * From<T> for LazyLock<T, F>\n * core::range::RangeToInclusive\n * core::range::RangeToInclusiveIter\n * core::range::RangeFrom\n * core::range::RangeFromIter\n * core::range::Range\n * core::range::RangeIter\n\n\n\n### Two Cargo advisories\n\nRust 1.96 contains fixes for two vulnerabilities for users of third-party registries.\n\n * CVE-2026-5223 is a **medium** severity vulnerability regarding extraction of crate tarballs with symlinks.\n\n * CVE-2026-5222 is a **low** severity vulnerability regarding authentication with normalized URLs.\n\n\n\n\nUsers of crates.io are **not affected** by either vulnerability.\n\n### Other changes\n\nCheck out everything that changed in Rust, Cargo, and Clippy.\n\n## Contributors to 1.96.0\n\nMany people came together to create Rust 1.96.0. We couldn't have done it without all of you. Thanks!",
"title": "Announcing Rust 1.96.0",
"updatedAt": "2026-05-28T00:00:00.000Z"
}