Series: The Rust Annals

Vol. I Issue 42 nlopes.dev

Announcing Rust 1.41.0

The release combines a substantial trait-coherence relaxation with important Cargo, FFI, and standard-library changes.

Rust 1.41.0 relaxes the orphan rule to permit useful trait implementations involving a local type, makes cargo install update outdated packages, introduces a less conflict-prone format for new Cargo.lock files, and guarantees a carefully constrained ABI correspondence between Box<T> and C pointers. It also expands the standard library, starts landing MIR optimizations intended to improve compile time, and marks the last release at the current support level for 32-bit Apple targets.

Local trait parameters permit more foreign-type implementations

Rust’s orphan rule prevents ecosystem breakage when a dependency adds a trait implementation: an implementation is allowed only when either the trait or the implemented type is local to the current crate. Before Rust 1.41.0, its treatment of generics was unnecessarily strict and could make composition cumbersome or impossible even with workarounds such as the newtype pattern.

For example, Rust 1.40.0 rejected this conversion from a crate’s local BetterVec<T> to the standard library’s foreign Vec<T> because both From and Vec were foreign:

impl<T> From<BetterVec<T>> for Vec<T> {
    // ...
}

It is an instance of the following pattern:

impl<T> ForeignTrait<LocalType> for ForeignType<T> {
    // ...
}

Rust 1.41.0 permits the implementation because the foreign trait is parameterized by a local type. The precise generic coherence rules remain more involved; the stabilization report and RFC provide the details.

Cargo updates installed packages and reduces lockfile conflicts

Starting with Rust 1.41.0, cargo install updates an existing installation when a newer release of that crate is available. Previously, the only option was --force, which reinstalls the binary crate even when it is already up to date.

Cargo also introduces a new Cargo.lock format designed to avoid unnecessary merge conflicts when dependencies change on separate branches. Cargo uses the lockfile to record dependency versions and checksums for consistent builds. The new format applies to newly created lockfiles; existing lockfiles continue using the previous format. The design choices are described in the implementing pull request.

Box gains a constrained C-pointer ABI guarantee

For T: Sized, Rust 1.41.0 declares Box<T> representation- and ABI-compatible with C’s T*. An extern "C" Rust function called from C can therefore use Box<T> where its corresponding C declaration uses T*. For example:

// C header

// Returns ownership to the caller.
struct Foo* foo_new(void);

// Takes ownership from the caller; no-op when invoked with NULL.
void foo_delete(struct Foo*);
#[repr(C)]
pub struct Foo;

#[no_mangle]
pub extern "C" fn foo_new() -> Box<Foo> {
    Box::new(Foo)
}

// The possibility of NULL is represented with the `Option<_>`.
#[no_mangle]
pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}

The guarantee does not remove Box’s validity requirements: a Box<T> must remain non-null, aligned, and ready for deallocation by the global allocator. It is therefore best to use only boxes originating from the global allocator. The Box<T> documentation gives further details.

Standard-library additions shorten result handling and expose pointer counts

The standard library stabilizes or adds the following capabilities:

Compiler optimization work begins as 32-bit Apple support approaches demotion

Rust 1.41.0 started landing MIR optimizations that should improve compile time; the associated Inside Rust post describes that work.

This is also the last release with the current level of compiler support for 32-bit Apple targets, including i686-apple-darwin. Starting with Rust 1.42.0, those targets will be demoted to the lowest support tier. The project’s 32-bit Apple target announcement provides more information.

Reproduced from the Rust blog under its publication licence. Typeset in Literata.