The Rust team is happy to announce a new version of Rust, 1.41.0. Rust is a programming language that is empowering everyone to build reliable and efficient software.
If you have a previous version of Rust installed via rustup, getting Rust 1.41.0 is as easy as:
$ rustup update stable
If you don't have it already, you can get rustup
from the
appropriate page on our website, and check out the detailed release notes for
1.41.0 on GitHub.
What's in 1.41.0 stable
The highlights of Rust 1.41.0 include relaxed restrictions for trait
implementations, improvements to cargo install
, a more git
-friendly
Cargo.lock
, and new FFI-related guarantees for Box<T>
. See the detailed
release notes to learn about other changes not covered by this post.
Relaxed restrictions when implementing traits
To prevent breakages in the ecosystem when a dependency adds a new trait
impl
, Rust enforces the orphan rule. The gist of it is that
a trait impl
is only allowed if either the trait or the type being
implemented is local to (defined in) the current crate as opposed to a
foreign crate. What this means exactly is complicated, however,
when generics are involved.
Before Rust 1.41.0, the orphan rule was unnecessarily strict, getting in the
way of composition. As an example, suppose your crate defines the
BetterVec<T>
struct, and you want a way to convert your struct to the
standard library's Vec<T>
. The code you would write is:
impl<T> From<BetterVec<T>> for Vec<T> {
// ...
}
...which is an instance of the pattern:
impl<T> ForeignTrait<LocalType> for ForeignType<T> {
// ...
}
In Rust 1.40.0 this impl
was forbidden by the orphan rule, as both From
and
Vec
are defined in the standard library, which is foreign to the current
crate. There were ways to work around the limitation, such as the newtype
pattern, but they were often cumbersome or even impossible in
some cases.
While it's still true that both From
and Vec
were foreign, the trait (in
this case From
) was parameterized by a local type. Therefore, Rust 1.41.0
allows this impl
.
For more details, read the the stabilization report and the RFC proposing the change.
cargo install
updates packages when outdated
With cargo install
, you can install binary crates in your system. The command
is often used by the community to install popular CLI tools written in Rust.
Starting from Rust 1.41.0, cargo install
will also update existing
installations of the crate if a new release came out since you installed it.
Before this release the only option was to pass the --force
flag, which
reinstalls the binary crate even if it's up to date.
Cargo.lock
format
Less conflict-prone To ensure consistent builds, Cargo uses a file named Cargo.lock
, containing
dependency versions and checksums. Unfortunately, the way the data was arranged
in it caused unnecessary merge conflicts when changing dependencies in separate
branches.
Rust 1.41.0 introduces a new format for the file, explicitly designed to avoid those conflicts. This new format will be used for all new lockfiles, while existing lockfiles will still rely on the previous format. You can learn about the choices leading to the new format in the PR adding it.
Box<T>
in FFI
More guarantees when using Starting with Rust 1.41.0, we have declared that a Box<T>
, where T: Sized
is now ABI compatible with the C language's pointer (T*
) types. So if you
have an extern "C"
Rust function, called from C, your Rust function can now
use Box<T>
, for some specific T
, while using T*
in C for the
corresponding function. As an example, on the C side you may have:
// 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*);
...while on the Rust side, you would have:
#[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>>) {}
Note however that while Box<T>
and T*
have the same representation and ABI,
a Box<T>
must still be non-null, aligned, and ready for deallocation by the
global allocator. To ensure this, it is best to only use Box
es originating
from the global allocator.
Important: At least at present, you should avoid using Box<T>
types for
functions that are defined in C but invoked from Rust. In those cases, you
should directly mirror the C types as closely as possible. Using types like
Box<T>
where the C definition is just using T*
can lead to undefined
behavior.
To read more, consult the documentation for Box<T>
.
Library changes
In Rust 1.41.0, we've made the following additions to the standard library:
-
The
Result::map_or
andResult::map_or_else
methods were stabilized.Similar to
Option::map_or
andOption::map_or_else
, these methods are shorthands for the.map(|val| process(val)).unwrap_or(default)
pattern. -
NonZero*
numerics now implementFrom<NonZero*>
if it's a smaller integer width. For example,NonZeroU16
now implementsFrom<NonZeroU8>
. -
The
weak_count
andstrong_count
methods onWeak
pointers were stabilized.std::rc::Weak::weak_count
std::rc::Weak::strong_count
std::sync::Weak::weak_count
std::sync::Weak::strong_count
These methods return the number of weak (
rc::Weak<T>
andsync::Weak<T>
) or strong (Rc<T>
andArc<T>
) pointers to the allocation respectively.
Reducing support for 32-bit Apple targets soon
Rust 1.41.0 is the last release with the current level of compiler support for
32-bit Apple targets, including the i686-apple-darwin
target. Starting from
Rust 1.42.0, these targets will be demoted to the lowest support tier.
You can learn more about this change in this blog post.
Other changes
There are other changes in the Rust 1.41.0 release: check out what changed in Rust, Cargo, and Clippy. We also have started landing MIR optimizations, which should improve compile time: you can learn more about them in the "Inside Rust" blog post.
Contributors to 1.41.0
Many people came together to create Rust 1.41.0. We couldn't have done it without all of you. Thanks!