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_prefix and str::trim_suffix (also on slices and Path::trim_prefix): like strip_prefix, but returning the original value instead of None when the prefix is absent.
  • Box::map, Rc::map and Arc::map.
  • Vec::from_fn, bool::toggle and Box::take.
  • core::mem::DropGuard for 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 install uses the crate’s lockfile by default; --locked is 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-wasip3 is promoted to Tier 2.
  • -Cprofile-sample-use is stable, for sample-based profile-guided optimization.
  • The standard library now uses Unicode 18.0.0.
  • box patterns are no longer syntactically allowed.
  • Closures capture variables used in if let more precisely, which may cause new borrow errors in some code.

Upgrade checklist

  1. rustup update stable, then cargo build and cargo test on your workspace.
  2. Fix any new inference errors involving ! or Box with explicit types.
  3. Replace Infallible with ! where it reads better (they are now the same type, so this is optional).
  4. Add [lints.cargo] unused_dependencies = "warn" and clean up.
  5. Consider a dependency cooldown for production services.
  6. 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.