Skip to content

Commit a57df0b

Browse files
authored
Merge pull request #649 from steveklabnik/rust-1.45
Rust 1.45.0 release announcement
2 parents bb31c7f + 916cafa commit a57df0b

File tree

1 file changed

+296
-0
lines changed

1 file changed

+296
-0
lines changed

posts/2020-07-16-Rust-1.45.0.md

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
1+
---
2+
layout: post
3+
title: "Announcing Rust 1.45.0"
4+
author: The Rust Release Team
5+
release: true
6+
---
7+
8+
The Rust team is happy to announce a new version of Rust, 1.45.0. Rust is a
9+
programming language that is empowering everyone to build reliable and
10+
efficient software.
11+
12+
If you have a previous version of Rust installed via rustup, getting Rust
13+
1.45.0 is as easy as:
14+
15+
```console
16+
rustup update stable
17+
```
18+
19+
If you don't have it already, you can [get `rustup`][install] from the
20+
appropriate page on our website, and check out the [detailed release notes for
21+
1.45.0][notes] on GitHub.
22+
23+
[install]: https://www.rust-lang.org/install.html
24+
[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1450-2020-07-16
25+
26+
## What's in 1.45.0 stable
27+
28+
There are two big changes to be aware of in Rust 1.45.0: a fix for some
29+
long-standing unsoundness when casting between integers and floats, and the
30+
stabilization of the final feature needed for one of the more popular web
31+
frameworks to work on stable Rust.
32+
33+
## Fixing unsoundness in casts
34+
35+
[Issue 10184](https://github.com/rust-lang/rust/issues/10184) was originally
36+
opened back in October of 2013, a year and a half before Rust 1.0. As you may
37+
know, `rustc` uses [LLVM](http://llvm.org/) as a compiler backend. When you
38+
write code like this:
39+
40+
```rust
41+
pub fn cast(x: f32) -> u8 {
42+
x as u8
43+
}
44+
```
45+
46+
The Rust compiler in Rust 1.44.0 and before would produce LLVM-IR that looks
47+
like this:
48+
49+
```llvm-ir
50+
define i8 @_ZN10playground4cast17h1bdf307357423fcfE(float %x) unnamed_addr #0 {
51+
start:
52+
%0 = fptoui float %x to i8
53+
ret i8 %0
54+
}
55+
```
56+
57+
That `fptoui` implements the cast, it is short for "floating point to
58+
unsigned integer."
59+
60+
But there's a problem here. From [the
61+
docs](https://llvm.org/docs/LangRef.html#fptoui-to-instruction):
62+
63+
> The ‘fptoui’ instruction converts its floating-point operand into the
64+
> nearest (rounding towards zero) unsigned integer value. If the value cannot
65+
> fit in ty2, the result is a poison value.
66+
67+
Now, unless you happen to dig into the depths of compilers regularly, you may
68+
not understand what that means. It's full of jargon, but there's a simpler
69+
explanation: if you cast a floating point number that's large to an integer
70+
that's small, you get undefined behavior.
71+
72+
That means that this, for example, was not well-defined:
73+
74+
```rust
75+
fn cast(x: f32) -> u8 {
76+
x as u8
77+
}
78+
79+
fn main() {
80+
let f = 300.0;
81+
82+
let x = cast(f);
83+
84+
println!("x: {}", x);
85+
}
86+
```
87+
88+
On Rust 1.44.0, this happens to print "x: 0" on my machine. But it could
89+
print anything, or do anything: this is undefined behavior. But we have
90+
no `unsafe` code here. This is what we call a "soundness" bug, that is,
91+
it is a bug where the compiler does the wrong thing. We tag these bugs
92+
as
93+
[I-unsound](https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3A%22I-unsound+%F0%9F%92%A5%22)
94+
on our issue tracker, and take them very seriously.
95+
96+
This bug took a long time to resolve, though. The reason is that it was very
97+
unclear what the correct path forward was.
98+
99+
In the end, the decision was made to do this:
100+
101+
* `as` would perform a "saturating cast".
102+
* A new `unsafe` cast would be added if you wanted to skip the checks.
103+
104+
This is very similar to array access, for example:
105+
106+
* `array[i]` will check to make sure that `array` has at least `i` elements.
107+
* You can use `unsafe { array.get_unchecked(i) }` to skip the check.
108+
109+
So, what's a saturating cast? Let's look at a slightly modified example:
110+
111+
```rust
112+
fn cast(x: f32) -> u8 {
113+
x as u8
114+
}
115+
116+
fn main() {
117+
let too_big = 300.0;
118+
let too_small = -100.0;
119+
let nan = f32::NAN;
120+
121+
println!("too_big_casted = {}", cast(too_big));
122+
println!("too_small_casted = {}", cast(too_small));
123+
println!("not_a_number_casted = {}", cast(nan));
124+
}
125+
```
126+
127+
This will print:
128+
129+
```text
130+
too_big_casted = 255
131+
too_small_casted = 0
132+
not_a_number_casted = 0
133+
```
134+
135+
That is, numbers that are too big turn into the largest possible value.
136+
Numbers that are too small produce the smallest possible value (which is
137+
zero). NaN produces zero.
138+
139+
The new API to cast in an unsafe manner is:
140+
141+
```rust
142+
let x: f32 = 1.0;
143+
let y: u8 = unsafe { x.to_int_unchecked() };
144+
```
145+
146+
But as always, you should only use this method as a last resort. Just like
147+
with array access, the compiler can often optimize the checks away, making
148+
the safe and unsafe versions equivalent when the compiler can prove it.
149+
150+
## Stabilizing function-like procedural macros in expressions, patterns, and statements
151+
152+
In [Rust 1.30.0](https://blog.rust-lang.org/2018/10/25/Rust-1.30.0.html), we stabilized
153+
"function-like procedural macros in item position." For example, [the
154+
`gnome-class` crate](https://gitlab.gnome.org/federico/gnome-class):
155+
156+
> Gnome-class is a procedural macro for Rust. Within the macro, we
157+
> define a mini-language which looks as Rust-y as possible, and that has
158+
> extensions to let you define GObject subclasses, their properties,
159+
> signals, interface implementations, and the rest of GObject's
160+
> features. The goal is to require no unsafe code on your part.
161+
162+
This looks like this:
163+
164+
```rust
165+
gobject_gen! {
166+
class MyClass: GObject {
167+
foo: Cell<i32>,
168+
bar: RefCell<String>,
169+
}
170+
171+
impl MyClass {
172+
virtual fn my_virtual_method(&self, x: i32) {
173+
... do something with x ...
174+
}
175+
}
176+
}
177+
```
178+
179+
The "in item position" bit is some jargon, but basically what this means is that
180+
you could only invoke `gobject_gen!` in certain places in your code.
181+
182+
Rust 1.45.0 adds the ability to invoke procedural macros in three new places:
183+
184+
```rust
185+
// imagine we have a procedural macro named "mac"
186+
187+
mac!(); // item position, this was what was stable before
188+
189+
// but these three are new:
190+
fn main() {
191+
let expr = mac!(); // expression position
192+
193+
match expr {
194+
mac!() => {} // pattern position
195+
}
196+
197+
mac!(); // statement position
198+
}
199+
```
200+
201+
Being able to use macros in more places is interesting, but there's another
202+
reason why many Rustaceans have been waiting for this feature for a long time:
203+
[Rocket](https://rocket.rs). Inititally released in December of 2016, Rocket is
204+
a popular web framework for Rust often described as one of the best things the
205+
Rust ecosystem has to offer. Here's the "hello world" example from its upcoming
206+
release:
207+
208+
```rust
209+
#[macro_use] extern crate rocket;
210+
211+
#[get("/<name>/<age>")]
212+
fn hello(name: String, age: u8) -> String {
213+
format!("Hello, {} year old named {}!", age, name)
214+
}
215+
216+
#[launch]
217+
fn rocket() -> rocket::Rocket {
218+
rocket::ignite().mount("/hello", routes![hello])
219+
}
220+
```
221+
222+
Until today, Rocket depended on nightly-only features to deliver on its promise
223+
of flexibility and ergonomics. In fact, as can be seen on the [project's
224+
homepage](https://rocket.rs/v0.4), the same example above in the current version
225+
of Rocket requires the `proc_macro_hygiene` feature to compile. However, as you
226+
may guess from the feature's name, today it ships in stable! [This
227+
issue](https://github.com/SergioBenitez/Rocket/issues/19) tracked the history of
228+
nightly-only features in Rocket. Now, they're all checked off!
229+
230+
This next version of Rocket is still in the works, but when released, many folks
231+
will be very happy :)
232+
233+
### Library changes
234+
235+
In Rust 1.45.0, the following APIs were stabilized:
236+
237+
- [`Arc::as_ptr`]
238+
- [`BTreeMap::remove_entry`]
239+
- [`Rc::as_ptr`]
240+
- [`rc::Weak::as_ptr`]
241+
- [`rc::Weak::from_raw`]
242+
- [`rc::Weak::into_raw`]
243+
- [`str::strip_prefix`]
244+
- [`str::strip_suffix`]
245+
- [`sync::Weak::as_ptr`]
246+
- [`sync::Weak::from_raw`]
247+
- [`sync::Weak::into_raw`]
248+
- [`char::UNICODE_VERSION`]
249+
- [`Span::resolved_at`]
250+
- [`Span::located_at`]
251+
- [`Span::mixed_site`]
252+
- [`unix::process::CommandExt::arg0`]
253+
254+
Additionally, you can [use `char` with
255+
ranges](https://github.com/rust-lang/rust/pull/72413/), to iterate over
256+
codepoints:
257+
258+
```rust
259+
for ch in 'a'..='z' {
260+
print!("{}", ch);
261+
}
262+
println!();
263+
// Prints "abcdefghijklmnopqrstuvwxyz"
264+
```
265+
266+
For a full list of changes, see [the full release notes][notes].
267+
268+
### Other changes
269+
270+
There are other changes in the Rust 1.45.0 release: check out what changed in
271+
[Rust][notes], [Cargo][relnotes-cargo], and [Clippy][relnotes-clippy].
272+
273+
## Contributors to 1.45.0
274+
275+
Many people came together to create Rust 1.45.0. We couldn't have done it
276+
without all of you. [Thanks!](https://thanks.rust-lang.org/rust/1.45.0/)
277+
278+
[relnotes-cargo]: https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-145-2020-07-16
279+
[relnotes-clippy]: https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-145
280+
281+
[`Arc::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.as_ptr
282+
[`BTreeMap::remove_entry`]: https://doc.rust-lang.org/stable/std/collections/struct.BTreeMap.html#method.remove_entry
283+
[`Rc::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html#method.as_ptr
284+
[`rc::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.as_ptr
285+
[`rc::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.from_raw
286+
[`rc::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/rc/struct.Weak.html#method.into_raw
287+
[`sync::Weak::as_ptr`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.as_ptr
288+
[`sync::Weak::from_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.from_raw
289+
[`sync::Weak::into_raw`]: https://doc.rust-lang.org/stable/std/sync/struct.Weak.html#method.into_raw
290+
[`str::strip_prefix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_prefix
291+
[`str::strip_suffix`]: https://doc.rust-lang.org/stable/std/primitive.str.html#method.strip_suffix
292+
[`char::UNICODE_VERSION`]: https://doc.rust-lang.org/stable/std/char/constant.UNICODE_VERSION.html
293+
[`Span::resolved_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.resolved_at
294+
[`Span::located_at`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.located_at
295+
[`Span::mixed_site`]: https://doc.rust-lang.org/stable/proc_macro/struct.Span.html#method.mixed_site
296+
[`unix::process::CommandExt::arg0`]: https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.arg0

0 commit comments

Comments
 (0)