Rust 1.100.0 shipped on 12 November 2026, and it is a landmark release: the never type ! is finally stable after years behind a feature gate, custom allocators are stable, and Cargo gains its own lint system and dependency cooldowns. This guide explains each change with small examples, plus the compatibility notes to check before you bump your toolchain.
Upgrade
rustup update stable
rustc --version # rustc 1.100.0 ...
All details below come from the official 1.100.0 release notes.
1. The never type is stable
You have used ! for years as the return type of functions that never return, like panic! or an infinite server loop. What was unstable was using ! as an ordinary type everywhere else: in generics, in Result, in trait impls. That is now allowed on stable.
Errors that cannot happen
The classic use is a Result whose error case is impossible. Before, you used std::convert::Infallible. In 1.100, Infallible is now a type alias to !, so the two are the same type:
use std::str::FromStr;
struct Name(String);
impl FromStr for Name {
type Err = !; // parsing a Name can never fail
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Name(s.trim().to_string()))
}
}
fn main() {
// The error case is uninhabited, so this pattern is irrefutable.
let Ok(name) = " Ferris ".parse::<Name>();
println!("{}", name.0);
}
Because no value of type ! can exist, the compiler knows the Err arm is impossible, and let Ok(name) = ... needs no else.
Generic code over “never fails”
trait Job {
type Error;
fn run(&self) -> Result<u32, Self::Error>;
}
struct Constant;
impl Job for Constant {
type Error = !;
fn run(&self) -> Result<u32, !> {
Ok(42)
}
}
The standard library also adds impl AsRef for ! and impl AsMut for ! in this release.
The fallback change to watch
The compatibility notes say the never type fallback changed to ! on all editions. In rare code where the compiler had to infer the type of a diverging expression (often with panic!, return or unimplemented!() inside generic calls), inference previously fell back to (). It now falls back to !. Most code is unaffected, but if a crate suddenly fails to compile with a trait-bound error mentioning !, add an explicit type annotation where the compiler was guessing.
2. Custom allocators are stable
The std::alloc::Allocator trait and allocator-aware constructors are now stable, including Box::new_in, Vec::new_in and Vec::with_capacity_in, with Global and System implementing Allocator. This lets you choose where an individual collection’s memory comes from, without changing the global allocator:
use std::alloc::System;
fn main() {
// This Vec uses the system allocator explicitly.
let mut v: Vec<u32, System> = Vec::with_capacity_in(16, System);
v.extend([1, 2, 3]);
let b = Box::new_in(99_u64, System);
println!("{v:?} {b}");
}
The real payoff is arena and bump allocators in performance-sensitive code (parsers, game frames, request-scoped memory), which crates can now offer on stable Rust. A compatibility note warns that some Box impls were generalised to arbitrary allocators, which can cause new type inference errors in rare cases.
3. Handy new standard library APIs
A selection of newly stabilized APIs:
str::trim_prefixandstr::trim_suffix(also on slices andPath::trim_prefix): likestrip_prefix, but returning the original value instead ofNonewhen the prefix is absent.Box::map,Rc::mapandArc::map.Vec::from_fn,bool::toggleandBox::take.core::mem::DropGuardfor running cleanup code when a guard goes out of scope.impl Default for std::sync::Once.
fn main() {
let url = "https://example.com";
let host = url.trim_prefix("https://");
let same = "example.com".trim_prefix("https://");
assert_eq!(host, "example.com");
assert_eq!(same, "example.com"); // unchanged, no Option to unwrap
}
4. Cargo lints: unused dependencies
Cargo now has its own linting system. Some Cargo warnings are now lints you control in a [lints.cargo] table, including a new built-in cargo::unused_dependencies check:
# Cargo.toml
[lints.cargo]
unused_dependencies = "warn"
This replaces the need for a separate tool just to find dependencies you no longer use, which helps build times and supply-chain hygiene.
5. Dependency cooldowns
Cargo now supports a minimum publish age (RFC 3923), also called dependency cooldowns. When configured, the resolver ignores versions published more recently than the cutoff, unless they are already in Cargo.lock. The idea is simple: most malicious package releases are caught within days, so not adopting brand-new versions immediately removes a big class of supply-chain attacks. See the Cargo configuration docs linked from the release notes for the exact setting name and format.
6. Other Cargo changes
cargo installuses the crate’s lockfile by default;--lockedis now a no-op. Installs become more reproducible.- New build directory layout for intermediate artifacts. If your tooling reads files inside
target/directly, switch to Cargo’s JSON messages; the layout is not a stable interface.
7. Platform and compiler notes
wasm32-wasip3is promoted to Tier 2.-Cprofile-sample-useis stable, for sample-based profile-guided optimization.- The standard library now uses Unicode 18.0.0.
boxpatterns are no longer syntactically allowed.- Closures capture variables used in
if letmore precisely, which may cause new borrow errors in some code.
Upgrade checklist
rustup update stable, thencargo buildandcargo teston your workspace.- Fix any new inference errors involving
!orBoxwith explicit types. - Replace
Infalliblewith!where it reads better (they are now the same type, so this is optional). - Add
[lints.cargo] unused_dependencies = "warn"and clean up. - Consider a dependency cooldown for production services.
- Update tools that read
target/paths directly.
Takeaway
Rust 1.100 finishes two long-running language projects, the never type and the allocator API, and gives Cargo better hygiene tools with unused-dependency lints and cooldowns. For most projects the upgrade is painless; spend five minutes on the compatibility notes, then start using ! for impossible errors and trim_prefix for cleaner string handling.
