The Rust team is happy to announce a new version of Rust, 1.100.0. Rust is a programming language empowering everyone to build reliable and efficient software.
If you have a previous version of Rust installed via rustup, you can get 1.100.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.100.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!
Allocator APIDropGuard APIAfter 10 years and 5 failed stabilization attempts, the never type is finally stable! This also completes the project goal for this work.
The never type, spelled ! in code, is the canonical uninhabited type. It represents the type of diverging computations – computations which never resolve to any value – where any code that follows is unreachable. Expressions that terminate control flow, such as return, break, and std::process::exit, also have the type !.
Since having a value of the never type is impossible, Rust permits a never-to-any coercion, allowing to turn ! into any other type (this is what distinguishes it from any other uninhabited types). This can be used, for example, to not return a value from one of the branches of a match or an if:
fn mrrrow(option: Option<u32>) {
let value = match option {
// `x` has type `u32`
Some(x) => x,
// `return` has type `!`, which is then coerced to `u32`,
// allowing the `match` to pass type checking.
None => return,
};
// ...
}
While the never type could already be used and observed this way, and even named in the return type of functions (-> !), this release allows naming the never type anywhere:
fn infallible_unwrap<T>(res: Result<T, !>) -> T {
// ^^ writing `Result<_, !>` was not allowed before
let Ok(v) = res;
v
}
Additionally this release changes Infallible to be an alias to the never type. That makes all old APIs that used Infallible be compatible with using !. This was the plan ever since the introduction of Infallible and is one of the reasons why the never type stabilization was so hard (waffle gave a talk about some of the troubles of the stabilization).
Unfortunately, to allow changing Infallible, we had to introduce a breaking change. This release changes the "never type fallback" from () to ! in editions before 2024 (i.e. 2015, 2018, and 2021), similarly to what has already been done in edition 2024. This should largely be unnoticeable, but can affect code in some rare cases (for example when ignoring a result of a function returning a generic parameter). Note that this change might also make the compiler detect more code as unreachable.
We tried to minimize the impact of this breaking change as much as possible, by providing future compatibility warnings far in advance and releasing fixes to public crates that have been broken by this. If a dependency is failing due to issues with the never type, consider updating it, as a fix might have already been released for it.
Allocator APIThis release brings about the stabilization of the core parts of allocator_api, enabling library authors to define custom allocators that can be used together with certain standard library types - currently Vec and Box. These are enabled through the newly-stabilized Allocator trait.
This is the foundation of the Allocators 1.0 project goal. A lot remains to be done still, including expanding the API surface usable with custom allocators and stabilizing their use on more collections and pointer types; with the core trait and design out of the way though, expect to see more being stabilized soon!
DropGuard: run a closure on every exit pathThe Drop trait in Rust makes it possible to run code when a variable goes out of scope, regardless of whether we return, ?, or panic. Drop being a part of types means that in Rust you never have to close a socket.
Implementing Drop can however feel a little inconvenient when all you want is to run some code unconditionally when a function exits. This is why we’re introducing core::mem::DropGuard: a new helper type that runs a closure when dropped.
DropGuard takes two arguments: a variable and a closure. It implements Deref and DerefMut so you can keep working with the variable as normal. But when dropped it runs the closure and consumes the variable.
DropGuard also implements a dismiss method which returns the variable from the guard without running the destructor. This makes it possible to quickly implement all-or-nothing transaction-like APIs with a rollback. Here is an example implementing a parser which uses a guard to roll back mutations in case of failure:
use std::mem::DropGuard;
use std::num::ParseIntError;
/// Attempt to parse all `strings` and push them into `nums`.
/// If parsing any of them fails, `nums` remains unchanged.
fn parse_all(nums: &mut Vec<u32>, strings: &[&str]) -> Result<(), ParseIntError> {
let len = nums.len();
let mut nums = DropGuard::new(nums, move |nums| {
nums.truncate(len); // ← 1. Reset the vec on failure
});
for s in strings {
nums.push(s.parse()?); // ← 2. If `?` returns an error, roll back
}
DropGuard::dismiss(nums); // ← 3. Parsing successful, dismiss the guard
Ok(())
}As Rust's unsafe code guidelines are still being decided, it became clear that it would be very useful to decide what exactly it means to create zero-sized types in an unsafe way, and what we should recommend for people to do this.
This question is answered in Rust 1.100 with a single function: std::mem::conjure_zst.
Instead of transmuting (), MaybeUninit::uninit().assume_init(), or various other incantations, this is the dedicated way to create a value of a zero-sized type when you know that doing so is safe to do. If an inhabited type has no size, we know exactly what value it must be: nothing.
Of course, APIs often rely on the inability to construct such types for safety, and that's why this function is unsafe. For example, PyO3's Python<'py> is a zero-sized marker token that represents holding the Python GIL (global interpreter lock). Many of Python's APIs require holding this lock to be safe, but conjuring a token from thin air would allow safe PyO3 calls to violate that precondition.
Building dependencies that are no longer used or are only needed for specific platforms can slow down builds.
Rustc has the unused_crate_dependencies lint for this but it has false positives when used with Cargo because dependencies may be shared between multiple build targets, e.g. dependencies.tracing-subscriber being available for every bin in a package when only some may use it.
Cargo now reports unused dependencies to users, e.g.
warning: unused dependency `tracing-subscriber`
--> Cargo.toml:23:1
|
23 | tracing-subscriber.workspace = true
| ^^^^^^^^^^^^^^^^^^
|
= note: `cargo::unused_dependencies` is set to `warn` by default
help: consider removing the dependency on `tracing-subscriber`
A limitation of this warning is that it will only appear when building every build target that may use an entry in a dependencies table.
For example, running cargo check --bin foo won't show warnings for unused [dependencies] because another bin may be present that uses them.
No warning will be shown for unused dev-dependencies because there isn't a way to ensure every development build target is built.
This warning is being introduced as part of a new linting system for Cargo, controlled by the [lints.cargo] table in Cargo.toml, completing this project goal. See also the other lints that have been introduced.
Cargo builds all libraries and binaries in the build-dir and then uplifts final artifacts to the target-dir. At this time, these share a common parent directory.
Different build configurations, like --features, can lead to different copies of libraries and binaries in the build-dir.
These copies are kept unique by a build-configuration hash but this hash was not always applied due to platform constraints.
This can lead to extra rebuilds, missed rebuilds, confusion over what binaries or libraries are used, and so on.
These problems get exacerbated when sharing a build-dir across git worktrees.
The build-dir now consistently applies the build-configuration hash to all content by organizing the directories around their build step, rather than their file type, and moving the hash from a file's name to the parent directory.
This work began with the build directory layout project goal in 2025, and its stabilization is a milestone toward a new project goal, unblocking future improvements such as cache garbage collection, cross-workspace cache de-duplication, cross-workspace caching, and fine grain locking.
We previously published a call for testing for the changes that are now taking effect. While this is an internal change, this may break build processes and tests that had workarounds for missing or incomplete features. In some cases, the workaround is no longer needed. See cargo#17287 for possible solutions and to add any new use cases.
Malicious versions of packages are often caught within hours or days after being published, by either automated scanners or by the community. Rust 1.100 stabilizes Cargo's min-publish-age aware dependency resolution, which lets you wait for that window before it picks up newly published versions. This practice is also known as dependency cooldowns.
You can opt in via .cargo/config.toml:
[registry]
global-min-publish-age = "3 days"
When selecting versions, Cargo now skips any version published more recently than that, and tells you what it held back:
$ cargo update
Updating crates.io index
Locking 2 packages to highest compatible version as of min-publish-age
Adding cc v1.11.0 (available: v1.18.0, published 3 hours ago)
Adding clap 4.6.7 (available: 4.6.9, published 2 days ago)
When a new version is needed right away, you can override the check for a single update:
$ CARGO_RESOLVER_INCOMPATIBLE_PUBLISH_AGE=allow cargo update clap --precise 4.6.9
Updating crates.io index
Updating clap 4.6.7 -> clap 4.6.9 (published 2 days ago, minimum age 3 days)
The newer version will be recorded in Cargo.lock and kept from then on until a later cargo update re-resolves it.
A few things to keep in mind:
This depends on the registry recording when each version was published.
Versions without a pubtime field in the index are never held back.
cargo install ignores the minimum publish age, for both the installed crate and its dependencies.
Pin a version with cargo install foo@1.2.3 if needed.
Cooldowns reduce the risk from some supply chain attacks but are not a complete defense on their own. Please keep reviewing dependency updates as you otherwise would.
Further work to protect the ecosystem is planned under the crates.io supply chain hardening project goal, including quarantine support and automated detection of suspicious releases.
impl PartialEq<Cow<'_, [U]>> for Vec<T, A>impl PartialEq<Cow<'_, [U]>> for &[T]impl PartialEq<Cow<'_, [U]>> for &mut [T]std::alloc::Allocatorstd::alloc::Globalstd::alloc::Systemimpl Allocator for Globalimpl Allocator for Systemimpl<A: Allocator> Allocator for &Aimpl<T: Allocator, A: Allocator> Allocator for Box<T, A>impl<A: Allocator> Allocator for &mut Aimpl<T: Allocator, A: Allocator> Allocator for Arc<T, A>impl<T: Allocator, A: Allocator> Allocator for Rc<T, A>Box::new_inBox::from_raw_inBox::from_non_null_inBox::into_raw_with_allocatorBox::into_non_null_with_allocatorBox::allocatorVec::new_inVec::with_capacity_inVec::from_raw_parts_inVec::from_parts_inVec::into_raw_parts_with_allocatorVec::into_parts_with_allocatorVec::allocatorChild::main_thread_handleimpl Default for std::sync::Oncebool::toggleBox::takeBox::mapRc::mapArc::mapimpl AsRef<T> for !impl AsMut<T> for !core::mem::DropGuardcore::mem::conjure_zstUnsafeCell::replaceUnsafeCell::as_ref_uncheckedUnsafeCell::as_mut_uncheckedstr::trim_prefixstr::trim_suffix[T]::trim_prefix[T]::trim_suffixPath::trim_prefixVec::from_fnos::windows::process::CommandExt::show_windowCheck out everything that changed in Rust, Cargo, and Clippy.
Many people came together to create Rust 1.100.0. We couldn't have done it without all of you. Thanks!