Series: The Rust Annals
Vol. I Issue 89 nlopes.dev
Announcing Rust 1.88.0
Rust 1.88 combines a substantial Rust 2024 control-flow feature with naked functions, explicit boolean configuration, and automatic Cargo cache cleanup.
Rust 1.88 makes conditional control flow more direct with Rust 2024 let chains, gives low-level code full control over a function’s assembly with naked functions, and introduces explicit boolean cfg predicates. Cargo also begins automatically cleaning old cached dependencies, while the standard library gains slice-chunking, collection-filtering, procedural-macro span, and newly const APIs.
Let chains flatten conditional matching in Rust 2024
if and while conditions can now chain let statements with && and intermingle them with boolean expressions. Patterns in the let sub-expressions may be refutable or irrefutable, and their bindings are available to later parts of the chain and to the body. This reduces the nesting previously needed to combine if let or while let with further matches and conditions:
if let Channel::Stable(v) = release_info()
&& let Semver { major, minor, .. } = v
&& major == 1
&& minor == 88
{
println!("`let_chains` was stabilized in this version");
}
Let chains are available only in the Rust 2024 edition because they depend on its if let temporary-scope change for more consistent drop order. Earlier attempts to support every edition encountered difficult edge cases that threatened the implementation’s integrity; crates must upgrade to the 2024 edition to use the feature.
Naked functions give handwritten assembly the entire function body
Rust can now define naked functions without a compiler-generated prologue or epilogue, providing full control over the assembly generated for a particular function and a more ergonomic alternative to defining functions in global_asm!. Such a function uses #[unsafe(naked)], and its body consists of one naked_asm! call:
#[unsafe(naked)]
pub unsafe extern "sysv64" fn wrapping_add(a: u64, b: u64) -> u64 {
// Equivalent to `a.wrapping_add(b)`.
core::arch::naked_asm!(
"lea rax, [rdi + rsi]",
"ret"
);
}
The handwritten assembly defines the entire function body. Unlike a non-naked function, the compiler adds no special handling for arguments or return values. Naked functions are used in low-level settings such as Rust’s compiler-builtins, operating systems, and embedded applications.
Boolean cfg predicates replace implicit empty-list idioms
The cfg predicate language now accepts true and false as configurations that are always enabled or disabled. They work with the cfg and cfg_attr attributes, the built-in cfg! macro, and Cargo [target] tables in both configuration and manifests.
Previously, unconditional configuration could be expressed as cfg(all()) for enabled or cfg(any()) for disabled, but those empty-list meanings were implicit and easy to reverse. cfg(true) and cfg(false) state the intent directly. The design is described in RFC 3695.
Cargo starts reclaiming old cache entries automatically
Cargo now automatically garbage-collects its home-directory cache, whose downloaded dependency files historically accumulated without bound. Files downloaded from the network are removed when they have not been accessed for three months; files obtained from the local system are removed after one month. Automatic collection does not run with --offline or --frozen.
Cargo 1.78 and newer have tracked the access information required for this cleanup. Tracking began before removal was enabled to reduce cache churn for users who still run earlier versions. Anyone who regularly uses both current Cargo and versions older than 1.78, has crates accessed exclusively by those older versions, and does not want those crates downloaded again approximately every three months may wish to set cache.auto-clean-frequency = "never", as described in the Cargo documentation.
The earlier unstable announcement gives more background. Parts of that design remain unstable, including the gc subcommand tracked in cargo#13060.
Library stabilization expands slice, collection, span, pointer, and const operations
The stable library additions include Cell::update; Default implementations for *const T and *mut T; mod ffi::c_str; HashMap::extract_if; HashSet::extract_if; hint::select_unpredictable; proc_macro::Span::line, proc_macro::Span::column, proc_macro::Span::start, proc_macro::Span::end, proc_macro::Span::file, and proc_macro::Span::local_file; plus <[T]>::as_chunks, <[T]>::as_rchunks, <[T]>::as_chunks_unchecked, <[T]>::as_chunks_mut, <[T]>::as_rchunks_mut, and <[T]>::as_chunks_unchecked_mut.
The following previously stable APIs are now stable in const contexts:
NonNull<T>::replace<*mut T>::replacestd::ptr::swap_nonoverlappingCell::replaceCell::getCell::get_mutCell::from_mutCell::as_slice_of_cells
The i686-pc-windows-gnu target has been demoted to Tier 2, as described in an earlier post. There is no immediate effect for users: both compiler and standard-library tools continue to be distributed through rustup. With less testing than at Tier 1, however, the target has a greater chance of accumulating bugs in the future.