|
| 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