The Rust team is happy to announce a new version of Rust, 1.40.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.40.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.40.0 on GitHub.
What's in 1.40.0 stable
The highlights of Rust 1.40.0 include #[non_exhaustive]
and improvements to macros!()
and #[attribute]
s. Finally, borrow-check migration warnings have become hard errors in Rust 2015. See the detailed release notes for additional information.
#[non_exhaustive]
structs, enums, and variants
Suppose you're a library author of a crate alpha
, that has a pub struct Foo
. You would like to make alpha::Foo
's fields pub
as well, but you're not sure whether you might be adding more fields to Foo
in future releases. So now you have a dilemma: either you make the fields private, with the drawbacks that follow, or you risk users depending on the exact fields, breaking their code when you add a new one. Rust 1.40.0 introduces a way to break the logjam: #[non_exhaustive]
.
The attribute #[non_exhaustive]
, when attached to a struct
or the variant of an enum
, will prevent code outside of the crate defining it from constructing said struct
or variant. To avoid future breakage, other crates are also prevented from exhaustively matching on the fields. The following example illustrates errors in beta
which depends on alpha
:
// alpha/lib.rs:
#[non_exhaustive]
struct Foo {
pub a: bool,
}
enum Bar {
#[non_exhaustive]
Variant { b: u8 }
}
fn make_foo() -> Foo { ... }
fn make_bar() -> Bar { ... }
// beta/lib.rs:
let x = Foo { a: true }; //~ ERROR
let Foo { a } = make_foo(); //~ ERROR
// `beta` will still compile when more fields are added.
let Foo { a, .. } = make_foo(); //~ OK
let x = Bar::Variant { b: 42 }; //~ ERROR
let Bar::Variant { b } = make_bar(); //~ ERROR
let Bar::Variant { b, .. } = make_bar(); //~ OK
// -- `beta` will still compile...
What happens behind the scenes is that the visibility of the constructors for a #[non_exhaustive]
struct
or enum
variant is lowered to pub(crate)
, preventing access outside the crate defining it.
A perhaps more important aspect of #[non_exhaustive]
is that it can also be attached to enum
s themselves. An example, taken from the standard library, is Ordering
:
#[non_exhaustive]
pub enum Ordering { Relaxed, Release, Acquire, AcqRel, SeqCst }
The purpose of #[non_exhaustive]
in this context is to ensure that more variants can be added over time. This is achieved by preventing other crates from exhaustively pattern match
-ing on Ordering
. That is, the compiler would reject:
match ordering {
// This is an error, since if a new variant is added,
// this would suddenly break on an upgrade of the compiler.
Relaxed | Release | Acquire | AcqRel | SeqCst => {
/* logic */
}
}
Instead, other crates need to account for the possibility of more variants by adding a wildcard arm using e.g. _
:
match ordering {
Relaxed | Release | Acquire | AcqRel | SeqCst => { /* ... */ }
// OK; if more variants are added, nothing will break.
_ => { /* logic */ }
}
For more details on the #[non_exhaustive]
attribute, see the stabilization report.
Macro and attribute improvements
In 1.40.0, we have introduced several improvements to macros and attributes, including:
-
Calling procedural macros
mac!()
in type contexts.For example, you may write
type Foo = expand_to_type!(bar);
whereexpand_to_type
would be a procedural macro. -
Macros in
extern { ... }
blocks.This includes
bang!()
macros, for example:macro_rules! make_item { ($name:ident) => { fn $name(); } } extern { make_item!(alpha); make_item!(beta); }
Procedural macro attributes on items in
extern { ... }
blocks are now also supported:extern "C" { // Let's assume that this expands to `fn foo();`. #[my_identity_macro] fn foo(); }
-
Generating
macro_rules!
items in procedural macros.Function-like (
mac!()
) and attribute (#[mac]
) macros can both now generatemacro_rules!
items. For details on hygiene, please refer to the attached stabilization report. -
The
$m:meta
matcher supports arbitrary token-stream values.That is, the following is now valid:
macro_rules! accept_meta { ($m:meta) => {} } accept_meta!( my::path ); accept_meta!( my::path = "lit" ); accept_meta!( my::path ( a b c ) ); accept_meta!( my::path [ a b c ] ); accept_meta!( my::path { a b c } );
Borrow check migration warnings are hard errors in Rust 2015
In the 1.35.0 release, we announced that NLL had come to Rust 2015 after first being released for the 2018 edition in Rust 1.31.
As we noted back then, the old borrow checker had some bugs which would allow memory unsafety, and the NLL borrow checker fixed them. As these fixes break some stable code, we decided to gradually phase in the errors, by checking if the old borrow checker would accept the program and the NLL checker would reject it. In those cases, the errors would be downgraded to warnings.
The previous release, Rust 1.39.0, changes these warnings into errors for code using the 2018 edition. Rust 1.40.0 applies the same change for users of the 2015 edition, closing those soundness holes for good. This also allows us to clean up the old code from the compiler.
If your build breaks due to this change, or you want to learn more, check out Niko Matsakis's blog post.
const fn
s in the standard library
More With Rust 1.40.0, the following function became const fn
:
Additions to the standard library
In Rust 1.40.0 the following functions and macros were stabilized:
-
A macro, which is a shorter, more memorable, and convenient version of
unimplemented!()
. -
Creates a
Vec<T>
by repeating a slicen
times. -
This function
take
s the value out of a mutable reference and replaces it with the type's default. This is similar toOption::take
andCell::take
and provides a convenient short-hand formem::replace(&mut dst, Default::default())
. -
BTreeMap::get_key_value
andHashMap::get_key_value
Returns the key-value pair corresponding to the supplied key.
-
Option::as_deref
,Option::as_deref_mut
These work similarly to
Option::as_ref
andOption::as_mut
but also useDeref
andDerefMut
respectively, so thatopt_box.as_deref()
andopt_box.as_deref_mut()
, whereopt_box: Option<Box<T>>
, produce anOption<&T>
andOption<&mut T>
respectively. -
This function flattens an
Option<Option<T>>
toOption<T>
producingSome(x)
forSome(Some(x))
andNone
otherwise. The function is similar toIterator::flatten
. -
Returns the socket address of the remote peer this socket was connected to.
-
{f32,f64}::to_be_bytes
,{f32,f64}::to_le_bytes
,{f32,f64}::to_ne_bytes
,{f32,f64}::from_be_bytes
,{f32,f64}::from_le_bytes
, and{f32,f64}::from_ne_bytes
Return the memory representation of the floating point number as a byte array in big-endian (network), little-endian, and native-endian byte order.
Other changes
There are other changes in the Rust 1.40.0 release: check out what changed in Rust, Cargo, and Clippy.
Please also see the compatibility notes to check if you're affected by those changes.
Contributors to 1.40.0
Many people came together to create Rust 1.40.0. We couldn't have done it without all of you. Thanks!