|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "Announcing Rust 1.27" |
| 4 | +author: The Rust Core Team |
| 5 | +--- |
| 6 | + |
| 7 | +The Rust team is happy to announce a new version of Rust, 1.27.0. Rust is a |
| 8 | +systems programming language focused on safety, speed, and concurrency. |
| 9 | + |
| 10 | +If you have a previous version of Rust installed via rustup, getting Rust |
| 11 | +1.27.0 is as easy as: |
| 12 | + |
| 13 | +```bash |
| 14 | +$ rustup update stable |
| 15 | +``` |
| 16 | + |
| 17 | +If you don't have it already, you can [get `rustup`][install] from the |
| 18 | +appropriate page on our website, and check out the [detailed release notes for |
| 19 | +1.27.0][notes] on GitHub. |
| 20 | + |
| 21 | +[install]: https://www.rust-lang.org/install.html |
| 22 | +[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-1270-2018-06-21 |
| 23 | + |
| 24 | +Additionally, we would like to draw attention to something: just before the |
| 25 | +release of 1.27.0, we found [a |
| 26 | +bug](https://github.com/rust-lang/rust/pull/51686) in the 'default match |
| 27 | +bindings' feature introduced in 1.26.0 that can possibly introduce unsoundness. |
| 28 | +Since it was discovered very late in the release process, and has been present |
| 29 | +since 1.26.0, we decided to stick to our release train model. We expect to put |
| 30 | +out a 1.27.1 with that fix applied soon, and if there's demand, possibly a |
| 31 | +1.26.3 as well. More information about the specifics here will come in that |
| 32 | +release announcement. |
| 33 | + |
| 34 | +## What's in 1.27.0 stable |
| 35 | + |
| 36 | +This release has two big language features that people have been waiting for. |
| 37 | +But first, a small comment on documentation: All books in [the Rust |
| 38 | +Bookshelf] are [now searchable]! For example, here's [a search of "The Rust |
| 39 | +Programming Language" for |
| 40 | +'borrow'](https://doc.rust-lang.org/book/second-edition/?search=borrow). |
| 41 | +This will hopefully make it much easier to find what you're looking for. |
| 42 | +Additionally, there's one new book: [the `rustc` Book]. This book explains |
| 43 | +how to use `rustc` directly, as well as some other useful information, like a |
| 44 | +list of all lints. |
| 45 | + |
| 46 | +[the Rust Bookshelf]: https://doc.rust-lang.org/ |
| 47 | +[now searchable]: https://github.com/rust-lang/rust/pull/49623/ |
| 48 | +[the `rustc` Book]: https://github.com/rust-lang/rust/pull/49707/ |
| 49 | + |
| 50 | +### SIMD |
| 51 | + |
| 52 | +Okay, now for the big news: the [basics of SIMD] are now available! SIMD |
| 53 | +stands for "single instruction, multiple data." Consider a function |
| 54 | +like this: |
| 55 | + |
| 56 | +```rust |
| 57 | +pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) { |
| 58 | + for ((a, b), c) in a.iter().zip(b).zip(c) { |
| 59 | + *c = *a + *b; |
| 60 | + } |
| 61 | +} |
| 62 | +``` |
| 63 | + |
| 64 | +[basics of SIMD]: https://github.com/rust-lang/rust/pull/49664/ |
| 65 | + |
| 66 | +Here, we're taking two slices, and adding the numbers together, placing the |
| 67 | +result in a third slice. The simplest possible way to do this would be to do |
| 68 | +exactly what the code does, and loop through each set of elements, add them |
| 69 | +together, and store it in the result. However, compilers can often do better. |
| 70 | +LLVM will often "autovectorize" code like this, which is a fancy term for |
| 71 | +"use SIMD." Imagine that `a` and `b` were both 16 elements long. Each element |
| 72 | +is a `u8`, and so that means that each slice would be 128 bits of data. Using |
| 73 | +SIMD, we could put *both* `a` and `b` into 128 bit registers, add them |
| 74 | +together in a `*single*` instruction, and then copy the resulting 128 bits |
| 75 | +into `c`. That'd be much faster! |
| 76 | + |
| 77 | +While stable Rust has always been able to take advantage of |
| 78 | +autovectorization, sometimes, the compiler just isn't smart enough to realize |
| 79 | +that we can do something like this. Additionally, not every CPU has these |
| 80 | +features, and so LLVM may not use them so your program can be used on a wide |
| 81 | +variety of hardware. So, in Rust 1.27, the addtion of [the `std::arch` |
| 82 | +module] allows us to use these kinds of instructions *directly*, which |
| 83 | +means we don't need to rely on a smart compiler. Additionally, it includes |
| 84 | +some features that allow us to choose a particular implementation based |
| 85 | +on various criteria. For example: |
| 86 | + |
| 87 | +[the `std::arch` module]: https://doc.rust-lang.org/stable/std/arch/ |
| 88 | + |
| 89 | +```rust |
| 90 | +#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), |
| 91 | + target_feature = "avx2"))] |
| 92 | +fn foo() { |
| 93 | + #[cfg(target_arch = "x86")] |
| 94 | + use std::arch::x86::_mm256_add_epi64; |
| 95 | + #[cfg(target_arch = "x86_64")] |
| 96 | + use std::arch::x86_64::_mm256_add_epi64; |
| 97 | + |
| 98 | + unsafe { |
| 99 | + _mm256_add_epi64(...); |
| 100 | + } |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +Here, we use `cfg` flags to choose the correct version based on the machine |
| 105 | +we're targetting; on `x86` we use that version, and on `x86_64` we use |
| 106 | +its version. We can also choose at runtime: |
| 107 | + |
| 108 | +```rust |
| 109 | +fn foo() { |
| 110 | + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] |
| 111 | + { |
| 112 | + if is_x86_feature_detected!("avx2") { |
| 113 | + return unsafe { foo_avx2() }; |
| 114 | + } |
| 115 | + } |
| 116 | + |
| 117 | + foo_fallback(); |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +Here, we have two versions of the function: one which uses `AVX2`, a specific |
| 122 | +kind of SIMD feature that lets you do 256-bit operations. The |
| 123 | +`is_x86_feature_detected!` macro will generate code that detects if your CPU |
| 124 | +supports AVX2, and if so, calls the `foo_avx2` function. If not, then we fall |
| 125 | +back to a non-AVX implementation, `foo_fallback`. This means that our code |
| 126 | +will run super fast on CPUs that support AVX2, but still work on ones that |
| 127 | +don't, albeit slower. |
| 128 | + |
| 129 | +If all of this seems a bit low-level and fiddly, well, it is! `std::arch` is |
| 130 | +specifically *primitives* for building these kinds of things. We hope to |
| 131 | +eventually stabilize a `std::simd` module with higher-level stuff in the |
| 132 | +future. But landing the basics now lets the ecosystem experiment with higher |
| 133 | +level libraries starting today. For example, check out the |
| 134 | +[faster](https://github.com/AdamNiederer/faster) crate. Here's a code |
| 135 | +snippet with no SIMD: |
| 136 | + |
| 137 | +```rust |
| 138 | +let lots_of_3s = (&[-123.456f32; 128][..]).iter() |
| 139 | + .map(|v| { |
| 140 | + 9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0 |
| 141 | + }) |
| 142 | + .collect::<Vec<f32>>(); |
| 143 | +``` |
| 144 | + |
| 145 | +To use SIMD with this code via `faster`, you'd change it to this: |
| 146 | + |
| 147 | +```rust |
| 148 | +let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter() |
| 149 | + .simd_map(f32s(0.0), |v| { |
| 150 | + f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - f32s(4.0) - f32s(2.0) |
| 151 | + }) |
| 152 | + .scalar_collect(); |
| 153 | +``` |
| 154 | + |
| 155 | +It looks almost the same: `simd_iter` instead of `iter`, `simd_map` instead |
| 156 | +of `map`, `f32s(2.0)` instead of `2.0`. But you get a SIMD-ified version |
| 157 | +generated for you. |
| 158 | + |
| 159 | +Beyond *that*, you may never write any of this yourself, but as always, the |
| 160 | +libraries you depend on may. For example, the [regex crate has already added |
| 161 | +support](https://github.com/rust-lang/regex/pull/456), and a new release |
| 162 | +will contain these SIMD speedups without you needing to do anything at all! |
| 163 | + |
| 164 | +### `dyn Trait` |
| 165 | + |
| 166 | +Rust's trait object syntax is one that we ultimately regret. If you'll recall, |
| 167 | +given a trait `Foo`, this is a trait object: |
| 168 | + |
| 169 | +```rust |
| 170 | +Box<Foo> |
| 171 | +``` |
| 172 | + |
| 173 | +However, if `Foo` were a struct, it'd just be a normal struct placed inside a |
| 174 | +`Box<T>`. When designing the language, we though that the similarity here was |
| 175 | +a good thing, but experience has demonstrated that it is confusing. And it's |
| 176 | +not just for the `Box<Trait>` case; `impl SomeTrait for SomeOtherTrait` is |
| 177 | +also technically valid syntax, but you almost always want to write `impl<T> |
| 178 | +SomeTrait for T where T: SomeOtherTrait` instead. Same with `impl SomeTrait`, |
| 179 | +which looks like it would add methods or possibly default implementations |
| 180 | +but in fact adds inherent methods to a trait object. Finally, with the recent |
| 181 | +addition of `impl Trait` syntax, it's `impl Trait` vs `Trait` when explaining |
| 182 | +things, and so that feels like `Trait` is what you should use, given that it's |
| 183 | +shorter, but in reality, that's not always true. |
| 184 | + |
| 185 | +As such, in Rust 1.27, we have stabilized a new syntax, [`dyn Trait`]. A |
| 186 | +trait object now looks like this: |
| 187 | + |
| 188 | +```rust |
| 189 | +// old => new |
| 190 | +Box<Foo> => Box<dyn Foo> |
| 191 | +&Foo => &dyn Foo |
| 192 | +&mut Foo => &mut dyn Foo |
| 193 | +``` |
| 194 | + |
| 195 | +And similarly for other pointer types, `Arc<Foo>` is now `Arc<dyn Foo>`, etc. |
| 196 | +Due to backwards compatibility, we cannot remove the old syntax, but we have |
| 197 | +included a lint, which is set to allow by default, called [`bare-trait-object`]. |
| 198 | +If you want to lint against the older syntax, you can turn it on. We thought that |
| 199 | +it would throw far too many warnings to turn on by default at present. |
| 200 | + |
| 201 | +> Incidentally, we're working on a tool called `rustfix` that can automatically |
| 202 | +> upgrade your code to newer idioms. It uses these sorts of lints to do so. |
| 203 | +> Expect to hear more about `rustfix` in a future announcement. |
| 204 | +
|
| 205 | +[`dyn Trait`]: https://github.com/rust-lang/rfcs/blob/master/text/2113-dyn-trait-syntax.md |
| 206 | +[`bare-trait-object`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#bare-trait-object |
| 207 | + |
| 208 | +### `#[must_use]` on functions |
| 209 | + |
| 210 | +Finally, the `#[must_use]` attribute is getting an upgrade: [it can now be |
| 211 | +used on functions](https://github.com/rust-lang/rust/pull/48925/). |
| 212 | + |
| 213 | +Previously, it only applied to types, like `Result<T, E>`. But now, you can |
| 214 | +do this: |
| 215 | + |
| 216 | +```rust |
| 217 | +#[must_use] |
| 218 | +fn double(x: i32) -> i32 { |
| 219 | + 2 * x |
| 220 | +} |
| 221 | + |
| 222 | +fn main() { |
| 223 | + double(4); // warning: unused return value of `double` which must be used |
| 224 | + |
| 225 | + let _ = double(4); // (no warning) |
| 226 | +} |
| 227 | +``` |
| 228 | + |
| 229 | +We've also [enhanced several bits of the standard |
| 230 | +library](https://github.com/rust-lang/rust/pull/49533/) to make use of this; |
| 231 | +`Clone::clone`, `Iterator::collect`, and `ToOwned::to_owned` will all start |
| 232 | +warning if you don't use their results, helping you notice expensive operations |
| 233 | +you may be throwing away by accident. |
| 234 | + |
| 235 | +See the [detailed release notes][notes] for more. |
| 236 | + |
| 237 | +### Library stabilizations |
| 238 | + |
| 239 | +Several new APIs were stabilized this release: |
| 240 | + |
| 241 | +- [`DoubleEndedIterator::rfind`] |
| 242 | +- [`DoubleEndedIterator::rfold`] |
| 243 | +- [`DoubleEndedIterator::try_rfold`] |
| 244 | +- [`Duration::from_micros`] |
| 245 | +- [`Duration::from_nanos`] |
| 246 | +- [`Duration::subsec_micros`] |
| 247 | +- [`Duration::subsec_millis`] |
| 248 | +- [`HashMap::remove_entry`] |
| 249 | +- [`Iterator::try_fold`] |
| 250 | +- [`Iterator::try_for_each`] |
| 251 | +- [`NonNull::cast`] |
| 252 | +- [`Option::filter`] |
| 253 | +- [`String::replace_range`] |
| 254 | +- [`Take::set_limit`] |
| 255 | +- [`hint::unreachable_unchecked`] |
| 256 | +- [`os::unix::process::parent_id`] |
| 257 | +- [`process::id`] |
| 258 | +- [`ptr::swap_nonoverlapping`] |
| 259 | +- [`slice::rsplit_mut`] |
| 260 | +- [`slice::rsplit`] |
| 261 | +- [`slice::swap_with_slice`] |
| 262 | + |
| 263 | +[`DoubleEndedIterator::rfind`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfind |
| 264 | +[`DoubleEndedIterator::rfold`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfold |
| 265 | +[`DoubleEndedIterator::try_rfold`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.try_rfold |
| 266 | +[`Duration::from_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_micros |
| 267 | +[`Duration::from_nanos`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_nanos |
| 268 | +[`Duration::subsec_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.subsec_micros |
| 269 | +[`Duration::subsec_millis`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.subsec_millis |
| 270 | +[`HashMap::remove_entry`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.remove_entry |
| 271 | +[`Iterator::try_fold`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_fold |
| 272 | +[`Iterator::try_for_each`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_for_each |
| 273 | +[`NonNull::cast`]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.cast |
| 274 | +[`Option::filter`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.filter |
| 275 | +[`String::replace_range`]: https://doc.rust-lang.org/std/string/struct.String.html#method.replace_range |
| 276 | +[`Take::set_limit`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.set_limit |
| 277 | +[`slice::rsplit_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit_mut |
| 278 | +[`slice::rsplit`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit |
| 279 | +[`slice::swap_with_slice`]: https://doc.rust-lang.org/std/primitive.slice.html#method.swap_with_slice |
| 280 | +[`hint::unreachable_unchecked`]: https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html |
| 281 | +[`os::unix::process::parent_id`]: https://doc.rust-lang.org/std/os/unix/process/fn.parent_id.html |
| 282 | +[`ptr::swap_nonoverlapping`]: https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html |
| 283 | +[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html |
| 284 | + |
| 285 | +See the [detailed release notes][notes] for more. |
| 286 | + |
| 287 | +### Cargo features |
| 288 | + |
| 289 | +Cargo has two small upgrades this release. First, it now [takes a |
| 290 | +`--target-dir` flag](https://github.com/rust-lang/cargo/pull/5393/) if you'd |
| 291 | +like to change the target directory for a given invocation. |
| 292 | + |
| 293 | +Additionally, a tweak to the way Cargo deals with targets has landed. Cargo |
| 294 | +will attempt to automatically discover tests, examples, and binaries within |
| 295 | +your project. However, sometimes explicit configuration is needed. But the |
| 296 | +initial implementation had a problem: let's say that you have two examples, |
| 297 | +and Cargo is discovering them both. You want to tweak one of them, and so |
| 298 | +you add a `[[example]]` to your `Cargo.toml` to configure its settings. |
| 299 | +Cargo currently sees that you've set one explicitly, and therefore, doesn't |
| 300 | +attempt to do any autodetection for the others. That's quite surprising. |
| 301 | + |
| 302 | +As such, we've [added several 'auto' keys to |
| 303 | +`Cargo.toml`](https://github.com/rust-lang/cargo/pull/5335/) We can't fix |
| 304 | +this behavior without possibly breaking projects that may have inadvertently |
| 305 | +been relying on it, and so, if you'd like to configure some targets, but not |
| 306 | +others, you can set the `autoexamples` key to `true` in the `[package]` |
| 307 | +section. |
| 308 | + |
| 309 | +See the [detailed release notes][notes] for more. |
| 310 | + |
| 311 | +## Contributors to 1.27.0 |
| 312 | + |
| 313 | +Many people came together to create Rust 1.27. We couldn't have done it |
| 314 | +without all of you. [Thanks!](https://thanks.rust-lang.org/rust/1.27.0) |
0 commit comments