Stable Release in branch 1.98
1.98.0
Released 20 Aug 2026
(3 days ago)
SoftwareRust
Version1.98
Initial release1.98.0
20 Aug 2026
(3 days ago)
Latest release1.98.0
20 Aug 2026
(3 days ago)
Support statusSupported
Release noteshttps://github.com/rust-lang/rust/releases/tag/1.98.0
Source codehttps://github.com/rust-lang/rust/tree/1.98.0
Downloadhttps://github.com/rust-lang/rust/releases/tag/1.98.0
Rust 1.98 ReleasesView full list

What Is New in Rust 1.98

CategoryHighlights
New Features
  • Lifetimes on &mut references can now shorten during unsize-coercion, even in invariant position (for example coercing Cell<&'long mut i32> to Cell<&'short mut dyn Send>)
  • New deny-by-default lint invalid_runtime_symbol_definitions and warn-by-default lint suspicious_runtime_symbol_definitions targeting core runtime symbols like memcmp, memset, and strlen
  • New warn-by-default lint c_void_returns that flags core::ffi::c_void used as a return type
  • powerpc64-unknown-linux-gnuelfv2 and aarch64-unknown-linux-pauthtest added as Tier 3 targets
  • thumbv7a-none-eabi, thumbv7a-none-eabihf, thumbv7r-none-eabi, thumbv7r-none-eabihf, and thumbv8r-none-eabihf promoted to Tier 2
  • New stable APIs including str::substr_range, [T]::subslice_range, core::fmt::NumBuffer, algebraic float methods, and UTF-16 endian-aware String constructors
Improvements
  • Location<'_> lifetime in PanicHookInfo and PanicInfo changed to 'static
  • The derive macro is now explicitly documented as available at {core,std}::derive
  • LoongArch CRC intrinsics stabilized
Bug Fixes
  • transmute() now correctly checks that types have equal size when certain repr attributes are involved
  • Closed a gap in structural equality checks for constant patterns that disagreed with a manual PartialEq implementation alongside a derived one
Breaking Changes
  • ambiguous_glob_imports is now a hard error in more cases, and import ambiguity errors trigger more broadly
  • repr(transparent) is stricter about which fields count as having a "trivial" layout; repr(C) types, types with private fields, and #[non_exhaustive] types no longer qualify
  • The derived Ord implementation now uses a fast path built from derive(PartialOrd), which can surface bugs in crates whose PartialOrd and Ord impls were previously inconsistent
  • Where-bounds written as Type = Type or Type == Type are no longer syntactically accepted
  • On Emscripten, the WASM exception handling ABI is now used unconditionally; the -Zemscripten-wasm-eh=false flag has been removed
  • On Solaris, File::lock now returns "unsupported" instead of using an implementation with incorrect semantics
  • Fully elided lifetime bounds on trait object types may resolve differently, or be rejected, in narrow edge cases

What language changes are new in Rust 1.98?

The headline language change in Rust 1.98 lets the compiler shorten the lifetime of a &mut reference during unsize-coercion, even when that reference sits in an invariant position. In practice, this closes a gap that previously only applied to &mut -> & and & -> & coercions.

Concretely, you can now write code that coerces Cell<&'long mut i32> into Cell<&'short mut dyn Send> without extra lifetime gymnastics. This matters if you build generic wrapper types around mutable references and have hit borrow-checker friction when trying to erase a concrete type into a trait object while shortening its lifetime.

fn shorten<'long: 'short, 'short>(cell: &Cell<&'long mut i32>) -> &Cell<&'short mut dyn Send> {
    cell
}

Watch out for the accompanying compatibility note: fully elided lifetime bounds on trait object types may now resolve differently, or even get rejected, in very specific niche scenarios. Most codebases will not notice this, but it is worth a quick look if you rely heavily on elided lifetimes with trait objects.

Which new lints should Rust 1.98 users watch for?

Rust 1.98 introduces two lints aimed at catching mismatched or unsafe redefinitions of core runtime symbols. The deny-by-default invalid_runtime_symbol_definitions lint and the warn-by-default suspicious_runtime_symbol_definitions lint currently target symbols such as memcmp, memset, and strlen, with more symbols planned for future releases.

This matters if you write no_std or embedded code that provides custom implementations of these C runtime functions. Most teams working in application-level Rust will never trigger these lints, but low-level crates that shadow libc symbols should compile with the new toolchain early to catch any deny-level failures before they hit CI.

A third lint, c_void_returns, is now warn-by-default and flags functions that return core::ffi::c_void directly. This usually signals an FFI binding mistake, since c_void is meant to be used behind a pointer, not as a return type on its own.

What platform support changes come with Rust 1.98?

Rust 1.98 expands both the Tier 3 and Tier 2 target lists, with the biggest practical win being for embedded ARM development. thumbv7a-none-eabi, thumbv7a-none-eabihf, thumbv7r-none-eabi, thumbv7r-none-eabihf, and thumbv8r-none-eabihf are all promoted to Tier 2, which means official builds and more reliable CI coverage from the Rust project.

  • powerpc64-unknown-linux-gnuelfv2 added as Tier 3
  • aarch64-unknown-linux-pauthtest added as Tier 3, useful for testing pointer authentication on AArch64
  • The five thumbv7/thumbv8 embedded targets promoted from Tier 3 to Tier 2

In practice, if you ship firmware or RTOS-based projects on Cortex-A or Cortex-R cores, this promotion means you can rely on prebuilt targets from rustup instead of building your own toolchain from source.

What breaking changes affect upgrading to Rust 1.98?

Most Rust 1.98 breaking changes are narrow, but a few are worth testing against before you roll the update out fleet-wide. The most likely one to bite real projects is the fast-path implementation of derived Ord that now builds on derive(PartialOrd).

  • If a type's manual or derived PartialOrd and Ord implementations were already inconsistent, this can surface as different sort or comparison behavior after upgrading
  • repr(transparent) layout checks got stricter: repr(C) types, types with private fields, and #[non_exhaustive] types are no longer treated as having a trivial layout
  • Where-bounds written with = or == between types are now a hard parse error rather than accepted syntax
  • ambiguous_glob_imports now errors in more situations, so wildcard-import-heavy modules are worth a quick recompile check

This matters if you maintain a large crate with legacy glob imports or older derive-based ordering logic. Most teams should run a full test suite against 1.98 in CI before merging the toolchain bump, rather than assuming a patch-level upgrade is safe.

What new stable APIs are available in Rust 1.98?

Rust 1.98 stabilizes a useful batch of string, slice, and numeric APIs that reduce the need for manual index math or third-party crates. str::substr_range and [T]::subslice_range let you recover the byte range of a substring or subslice relative to its parent, which is handy when building diagnostics or parsers.

  • String::from_utf16le, from_utf16le_lossy, from_utf16be, and from_utf16be_lossy for endian-aware UTF-16 decoding without pulling in an external crate
  • {fN}::algebraic_add, algebraic_sub, algebraic_mul, algebraic_div, and algebraic_rem for floating point operations that permit reassociation-friendly optimizations
  • Atomic::from_mut, from_mut_slice, and get_mut_slice for converting between atomic and non-atomic references
  • NonZero<{integer}>::from_str_radix and {integer}::format_into for parsing and formatting without extra allocations

In practice, the UTF-16 constructors and the substring range helpers are the two most likely to replace hand-rolled utility code in existing codebases.

FAQ: Common Questions about Rust 1.98

Does upgrading to Rust 1.98 require changes to existing code?
Most codebases compile unchanged, but projects relying on inconsistent PartialOrd and Ord implementations, older where-bound syntax, or loose repr(transparent) layouts should run their test suite before rolling the upgrade out broadly.

What is the new mut reference coercion rule in Rust 1.98?
Rust 1.98 allows the lifetime of a mut reference to shorten during unsize coercion even in invariant position, for example coercing Cell of a long lived mut i32 reference into Cell of a shorter lived mut dyn Send reference.

Will the new runtime symbol lints break my build?
Only if your crate redefines core runtime symbols like memcmp, memset, or strlen incorrectly, since invalid_runtime_symbol_definitions is deny by default and will fail compilation in that case.

Are any Rust targets promoted in 1.98?
Yes.

Why did my derived Ord behavior change after upgrading?
Rust 1.98 implements a fast path for derive Ord that is built directly from derive PartialOrd, so any type whose manual or derived implementations of the two traits were already inconsistent may now sort or compare differently.

What happened to the emscripten-wasm-eh flag?
It was removed because Rust 1.98 unconditionally uses the WASM exception handling ABI on Emscripten targets instead of JS exceptions.

Releases In Branch 1.98

VersionRelease date
1.98.020 Aug 2026
(3 days ago)