From 9d8b8764f9d89c8107ded4648719583fe3e2359d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 15 Oct 2024 16:59:07 -0700 Subject: [PATCH 01/25] Announcing Rust 1.82.0 --- posts/2024-10-17-Rust-1.82.0.md | 320 ++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 posts/2024-10-17-Rust-1.82.0.md diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md new file mode 100644 index 000000000..c720a2066 --- /dev/null +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -0,0 +1,320 @@ +--- +layout: post +title: "Announcing Rust 1.82.0" +author: The Rust Release Team +release: true +--- + +The Rust team is happy to announce a new version of Rust, 1.82.0. Rust is a programming language empowering everyone to build reliable and efficient software. + +If you have a previous version of Rust installed via `rustup`, you can get 1.82.0 with: + +```console +$ rustup update stable +``` + +If you don't have it already, you can [get `rustup`](https://www.rust-lang.org/install.html) from the appropriate page on our website, and check out the [detailed release notes for 1.82.0](https://doc.rust-lang.org/nightly/releases.html#version-1820-2024-10-17). + +If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (`rustup default beta`) or the nightly channel (`rustup default nightly`). Please [report](https://github.com/rust-lang/rust/issues/new/choose) any bugs you might come across! + +## What's in 1.82.0 stable + +### `cargo info` + +Cargo now has an [`info` subcommand](https://doc.rust-lang.org/nightly/cargo/commands/cargo-info.html) to display information about a package in the registry, fulfilling a [long standing request](https://github.com/rust-lang/cargo/issues/948) just shy of its tenth anniversary! Several third-party extensions like this have been written over the years, and this implementation was developed as [cargo-information](https://crates.io/crates/cargo-information) before merging into Cargo itself. + +For example, here's what you could see for `cargo info cc`: + +
+cc #build-dependencies
+A build-time dependency for Cargo build scripts to assist in invoking the native
+C compiler to compile native C code into a static archive to be linked into Rust
+code.
+version: 1.1.23 (latest 1.1.30)
+license: MIT OR Apache-2.0
+rust-version: 1.63
+documentation: https://docs.rs/cc
+homepage: https://github.com/rust-lang/cc-rs
+repository: https://github.com/rust-lang/cc-rs
+crates.io: https://crates.io/crates/cc/1.1.23
+features:
+  jobserver = []
+  parallel  = [dep:libc, dep:jobserver]
+note: to see how you depend on cc, run `cargo tree --invert --package cc@1.1.23`
+
+ +By default `cargo info` describes the package version in the local `Cargo.lock`, if any, but as you can see it will indicate when there's a newer version too, and `cargo info cc@1.1.30` would report on that. The feature list also indicates a `+` next to any that are enabled. + +### Apple target promotions + +#### macOS on ARM64 is now Tier 1 + +The Rust target `aarch64-apple-darwin` for macOS on ARM64 (M1-family or later Apple Silicon CPUs) is now a tier 1 target, indicating our highest guarantee of working properly. As the [platform support](https://doc.rust-lang.org/stable/rustc/platform-support.html) page describes, every change in the Rust repository must pass full tests on every tier 1 target before it can be merged. This ARM64 target was added to tier 2 back in Rust 1.49, making it available in `rustup`, and this new milestone raises it on par with ARM64 Linux and the X86 macOS, Linux, and Windows targets. + +#### Mac Catalyst targets are now Tier 2 + +[Mac Catalyst](https://developer.apple.com/mac-catalyst/) is a technology by Apple that allows running iOS applications natively on the Mac. This is especially useful when testing iOS-specific code, as `cargo test --target=aarch64-apple-ios-macabi --target=x86_64-apple-ios-macabi` mostly just works (in contrast to the usual iOS targets, which need to be bundled using external tooling before they can be run on a native device or in the simulator). + +[The targets](https://doc.rust-lang.org/nightly/rustc/platform-support/apple-ios-macabi.html) are now tier 2, and can be downloaded with `rustup target add aarch64-apple-ios-macabi x86_64-apple-ios-macabi`, so now is an excellent time to update your CI pipeline to test that your code also runs in iOS-like environments. + +### Minimal exhaustive patterns + +Empty patterns can now be omitted in common cases: + +```rust +use std::convert::Infallible; +pub fn safe_unwrap(x: Result) -> T { + let Ok(x) = x; // the `Err` case does not need to appear + x +} +``` + +This works with empty types such as a variant-less `enum Void {}`, or structs and enums with a visible empty field and no `#[non_exhaustive]` attribute. It will also be particularly useful in combination with the never type `!`, although that type is still unstable at this time. + +This feature is "minimal" because there are still some exclusions at this time. For reasons related to uninitialized values and unsafe code, omitting patterns is not allowed if the empty type is accessed through a reference, pointer, or union field: + +```rust +pub fn safe_unwrap_ref(x: &Result) -> &T { + match x { + Ok(x) => x, + // this branch cannot be omitted because of the reference + Err(infallible) => match *infallible {}, + } +} +``` + +To avoid interfering with crates that wish to support several rust versions, branches with empty patterns are not yet warned as "unreachable", despite the fact that they can be removed. + +### Floating-point NaN semantics and `const` + +Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "Not a Number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()`. Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! + +With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced optimization techniques such as NaN boxing to be realized in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). + +With the semantics for NaN values settled, this release also permits the use of floating-point operations in `const fn`. Due to the reasons described above, operations like `(0.0 / 0.0).is_sign_positive()` can produce a different result when executed at compile-time vs at run-time; this is not a bug and code must not rely on a `const fn` always producing the exact same result. + +### Native syntax for creating a raw pointer + +Unsafe code sometimes has to deal with pointers that may dangle, may be misaligned, or may not point to valid data. A common case where this comes up are packed structs. In such a case, it is important to avoid creating a reference, as that would cause undefined behavior. This means the usual `&` and `&mut` operators cannot be used, as those create a reference -- even if the reference is immediately cast to a raw pointer, it's too late to avoid the undefined behavior. + +For several years, the macros `std::ptr::addr_of!` and `std::ptr::addr_of_mut!` have served this purpose. Now the time has come to provide a proper native syntax for this operation: `addr_of!(expr)` becomes `&raw const expr`, and `addr_of_mut!(expr)` becomes `&raw mut expr`. For example: + +```rust +#[repr(packed)] +struct Packed { + not_aligned_field: i32, +} + +fn main() { + let p = Packed { not_aligned_field: 1_82 }; + + // This would be undefined behavior! + // It is rejected by the compiler. + //let ptr = &p.not_aligned_field as *const i32; + + // This is the old way of creating a pointer. + let ptr = std::ptr::addr_of!(p.not_aligned_field); + + // This is the new way. + let ptr = &raw const p.not_aligned_field; + + // Accessing the pointer has not changed. + // Note that `val = *ptr` would be undefined behavior because + // the pointer is not aligned! + let val = unsafe { ptr.read_unaligned() }; +} +``` + +The native syntax makes it more clear that the operand expression of these operators is interpreted as a [place expression](https://www.ralfj.de/blog/2024/08/14/places.html). It also avoids the term "address-of" when referring to the action of creating a pointer. A pointer is [more than just an address](https://rust-lang.github.io/rfcs/3559-rust-has-provenance.html), so Rust is moving away from terms like "address-of" that reaffirm a false equivalence of pointers and addresses. + +### Safely addressing unsafe `static`s + +This code is now allowed: + +```rust +static mut STATIC_MUT: Type = Type::new(); +extern "C" { + static EXTERN_STATIC: Type; +} +fn main() { + let static_mut_ptr = std::ptr::addr_of_mut!(STATIC_MUT); + let extern_static_ptr = &raw const EXTERN_STATIC; +} +``` + +In an expression context, `STATIC_MUT` and `EXTERN_STATIC` are [place expressions](https://doc.rust-lang.org/reference/expressions.html#place-expressions-and-value-expressions). Previously, the compiler's safety checks were not aware that the raw ref operator did not actually affect the operand's place, treating it as a possible read or write to a pointer. No unsafety is actually present, however, as it just creates a pointer. + +Relaxing this may cause problems where some unsafe blocks are now reported as unused if you deny the `unused_unsafe` lint, but they are now only useful on older versions. Annotate these unsafe blocks with `#[allow(unused_unsafe)]` if you wish to support multiple versions of Rust, as in this example diff: + +```diff + static mut STATIC_MUT: Type = Type::new(); + fn main() { ++ #[allow(unused_unsafe)] + let static_mut_ptr = unsafe { std::ptr::addr_of_mut!(STATIC_MUT) }; + } +``` + +A future version of Rust is expected to generalize this to other expressions which would be safe in this position, not just statics. + +### Unsafe attributes + +Some Rust attributes, such as `no_mangle`, can be used to [cause Undefined Behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this was regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: + +```rust +#[unsafe(no_mangle)] +pub fn my_global_function() { } +``` + +The old form of the attribute (without `unsafe`) is currently still accepted, but might be linted against at some point in the future, and will be a hard error in a future edition. + +This affects the following attributes: +- `no_mangle` +- `link_section` +- `export_name` + +### Constants as assembly immediates + +The `const` assembly operand now provides a way to use integers as immediates +without first storing them in a register. As an example, we implement a syscall to +[`write`](https://man7.org/linux/man-pages/man2/write.2.html) by hand: + +```rust +const WRITE_SYSCALL: c_int = 0x01; // syscall 1 is `write` +const STDOUT_HANDLE: c_int = 0x01; // `stdout` has file handle 1 +const MSG: &str = "Hello, world!\n"; + +let written: usize; + +// Signature: `ssize_t write(int fd, const void buf[], size_t count)` +unsafe { + core::arch::asm!( + "mov rax, {SYSCALL} // rax holds the syscall number", + "mov rdi, {OUTPUT} // rdi is `fd` (first argument)", + "mov rdx, {LEN} // rdx is `count` (third argument)", + "syscall // invoke the syscall", + "mov {written}, rax // save the return value", + SYSCALL = const WRITE_SYSCALL, + OUTPUT = const STDOUT_HANDLE, + LEN = const MSG.len(), + in("rsi") MSG.as_ptr(), // rsi is `buf *` (second argument) + written = out(reg) written, + ); +} + +assert_eq!(written, MSG.len()); +``` + +Output: + +```text +Hello, world! +``` + +[Playground link](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0cf8e21335b38011b49156c6c65929bc). + +In the above, a statement such as `LEN = const MSG.len()` populates the format +specifier `LEN` with an immediate that takes the value of `MSG.len()`. This can be seen +in the generated assembly (the value is `14`): + +```asm +lea rsi, [rip + .L__unnamed_3] +mov rax, 1 # rax holds the syscall number +mov rdi, 1 # rdi is `fd` (first argument) +mov rdx, 14 # rdx is `count` (third argument) +syscall # invoke the syscall +mov rax, rax # save the return value +``` + +See [the reference](https://doc.rust-lang.org/reference/inline-assembly.html) +for more details. + +### Stabilized APIs + +- [`std::thread::Builder::spawn_unchecked`](https://doc.rust-lang.org/stable/std/thread/struct.Builder.html#method.spawn_unchecked) +- [`std::str::CharIndices::offset`](https://doc.rust-lang.org/nightly/std/str/struct.CharIndices.html#method.offset) +- [`std::option::Option::is_none_or`](https://doc.rust-lang.org/nightly/std/option/enum.Option.html#method.is_none_or) +- [`[T]::is_sorted`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.is_sorted) +- [`[T]::is_sorted_by`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.is_sorted_by) +- [`[T]::is_sorted_by_key`](https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.is_sorted_by_key) +- [`Iterator::is_sorted`](https://doc.rust-lang.org/nightly/std/iter/trait.Iterator.html#method.is_sorted) +- [`Iterator::is_sorted_by`](https://doc.rust-lang.org/nightly/std/iter/trait.Iterator.html#method.is_sorted_by) +- [`Iterator::is_sorted_by_key`](https://doc.rust-lang.org/nightly/std/iter/trait.Iterator.html#method.is_sorted_by_key) +- [`std::future::Ready::into_inner`](https://doc.rust-lang.org/nightly/std/future/struct.Ready.html#method.into_inner) +- [`std::iter::repeat_n`](https://doc.rust-lang.org/nightly/std/iter/fn.repeat_n.html) +- [`impl DoubleEndedIterator for Take>`](https://doc.rust-lang.org/nightly/std/iter/struct.Take.html#impl-DoubleEndedIterator-for-Take%3CRepeat%3CT%3E%3E) +- [`impl ExactSizeIterator for Take>`](https://doc.rust-lang.org/nightly/std/iter/struct.Take.html#impl-ExactSizeIterator-for-Take%3CRepeat%3CT%3E%3E) +- [`impl ExactSizeIterator for Take>`](https://doc.rust-lang.org/nightly/std/iter/struct.Take.html#impl-ExactSizeIterator-for-Take%3CRepeatWith%3CF%3E%3E) +- [`impl Default for std::collections::binary_heap::Iter`](https://doc.rust-lang.org/nightly/std/collections/binary_heap/struct.Iter.html#impl-Default-for-Iter%3C'_,+T%3E) +- [`impl Default for std::collections::btree_map::RangeMut`](https://doc.rust-lang.org/nightly/std/collections/btree_map/struct.RangeMut.html#impl-Default-for-RangeMut%3C'_,+K,+V%3E) +- [`impl Default for std::collections::btree_map::ValuesMut`](https://doc.rust-lang.org/nightly/std/collections/btree_map/struct.ValuesMut.html#impl-Default-for-ValuesMut%3C'_,+K,+V%3E) +- [`impl Default for std::collections::vec_deque::Iter`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.Iter.html#impl-Default-for-Iter%3C'_,+T%3E) +- [`impl Default for std::collections::vec_deque::IterMut`](https://doc.rust-lang.org/nightly/std/collections/vec_deque/struct.IterMut.html#impl-Default-for-IterMut%3C'_,+T%3E) +- [`Rc::new_uninit`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit) +- [`Rc::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init) +- [`Rc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new_uninit_slice) +- [`Rc<[MaybeUninit]>::assume_init`](https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.assume_init-1) +- [`Arc::new_uninit`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit) +- [`Arc::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init) +- [`Arc<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.new_uninit_slice) +- [`Arc<[MaybeUninit]>::assume_init`](https://doc.rust-lang.org/nightly/std/sync/struct.Arc.html#method.assume_init-1) +- [`Box::new_uninit`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit) +- [`Box::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init) +- [`Box<[T]>::new_uninit_slice`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.new_uninit_slice) +- [`Box<[MaybeUninit]>::assume_init`](https://doc.rust-lang.org/nightly/std/boxed/struct.Box.html#method.assume_init-1) +- [`core::arch::x86_64::_bextri_u64`](https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bextri_u64.html) +- [`core::arch::x86_64::_bextri_u32`](https://doc.rust-lang.org/stable/core/arch/x86_64/fn._bextri_u32.html) +- [`core::arch::x86::_mm_broadcastsi128_si256`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_broadcastsi128_si256.html) +- [`core::arch::x86::_mm256_stream_load_si256`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm256_stream_load_si256.html) +- [`core::arch::x86::_tzcnt_u16`](https://doc.rust-lang.org/stable/core/arch/x86/fn._tzcnt_u16.html) +- [`core::arch::x86::_mm_extracti_si64`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_extracti_si64.html) +- [`core::arch::x86::_mm_inserti_si64`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_inserti_si64.html) +- [`core::arch::x86::_mm_storeu_si16`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_storeu_si16.html) +- [`core::arch::x86::_mm_storeu_si32`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_storeu_si32.html) +- [`core::arch::x86::_mm_storeu_si64`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_storeu_si64.html) +- [`core::arch::x86::_mm_loadu_si16`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_loadu_si16.html) +- [`core::arch::x86::_mm_loadu_si32`](https://doc.rust-lang.org/stable/core/arch/x86/fn._mm_loadu_si32.html) +- [`core::arch::wasm32::u8x16_relaxed_swizzle`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u8x16_relaxed_swizzle.html) +- [`core::arch::wasm32::i8x16_relaxed_swizzle`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i8x16_relaxed_swizzle.html) +- [`core::arch::wasm32::i32x4_relaxed_trunc_f32x4`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i32x4_relaxed_trunc_f32x4.html) +- [`core::arch::wasm32::u32x4_relaxed_trunc_f32x4`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u32x4_relaxed_trunc_f32x4.html) +- [`core::arch::wasm32::i32x4_relaxed_trunc_f64x2_zero`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i32x4_relaxed_trunc_f64x2_zero.html) +- [`core::arch::wasm32::u32x4_relaxed_trunc_f64x2_zero`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u32x4_relaxed_trunc_f64x2_zero.html) +- [`core::arch::wasm32::f32x4_relaxed_madd`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f32x4_relaxed_madd.html) +- [`core::arch::wasm32::f32x4_relaxed_nmadd`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f32x4_relaxed_nmadd.html) +- [`core::arch::wasm32::f64x2_relaxed_madd`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f64x2_relaxed_madd.html) +- [`core::arch::wasm32::f64x2_relaxed_nmadd`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f64x2_relaxed_nmadd.html) +- [`core::arch::wasm32::i8x16_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i8x16_relaxed_laneselect.html) +- [`core::arch::wasm32::u8x16_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u8x16_relaxed_laneselect.html) +- [`core::arch::wasm32::i16x8_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i16x8_relaxed_laneselect.html) +- [`core::arch::wasm32::u16x8_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u16x8_relaxed_laneselect.html) +- [`core::arch::wasm32::i32x4_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i32x4_relaxed_laneselect.html) +- [`core::arch::wasm32::u32x4_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u32x4_relaxed_laneselect.html) +- [`core::arch::wasm32::i64x2_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i64x2_relaxed_laneselect.html) +- [`core::arch::wasm32::u64x2_relaxed_laneselect`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u64x2_relaxed_laneselect.html) +- [`core::arch::wasm32::f32x4_relaxed_min`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f32x4_relaxed_min.html) +- [`core::arch::wasm32::f32x4_relaxed_max`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f32x4_relaxed_max.html) +- [`core::arch::wasm32::f64x2_relaxed_min`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f64x2_relaxed_min.html) +- [`core::arch::wasm32::f64x2_relaxed_max`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.f64x2_relaxed_max.html) +- [`core::arch::wasm32::i16x8_relaxed_q15mulr`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i16x8_relaxed_q15mulr.html) +- [`core::arch::wasm32::u16x8_relaxed_q15mulr`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u16x8_relaxed_q15mulr.html) +- [`core::arch::wasm32::i16x8_relaxed_dot_i8x16_i7x16`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i16x8_relaxed_dot_i8x16_i7x16.html) +- [`core::arch::wasm32::u16x8_relaxed_dot_i8x16_i7x16`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u16x8_relaxed_dot_i8x16_i7x16.html) +- [`core::arch::wasm32::i32x4_relaxed_dot_i8x16_i7x16_add`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.i32x4_relaxed_dot_i8x16_i7x16_add.html) +- [`core::arch::wasm32::u32x4_relaxed_dot_i8x16_i7x16_add`](https://doc.rust-lang.org/nightly/core/arch/wasm32/fn.u32x4_relaxed_dot_i8x16_i7x16_add.html) + +These APIs are now stable in const contexts: + +- [`std::task::Waker::from_raw`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw) +- [`std::task::Waker::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw) +- [`std::task::Context::from_waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.from_waker) +- [`std::task::Context::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.waker) +- [`$integer::from_str_radix`](https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.from_str_radix) +- [`std::num::ParseIntError::kind`](https://doc.rust-lang.org/nightly/std/num/struct.ParseIntError.html#method.kind) + +### Other changes + +Check out everything that changed in [Rust](https://github.com/rust-lang/rust/releases/tag/1.82.0), [Cargo](https://github.com/rust-lang/cargo/blob/master/CHANGELOG.md#cargo-182-2024-10-17), and [Clippy](https://github.com/rust-lang/rust-clippy/blob/master/CHANGELOG.md#rust-182). + +## Contributors to 1.82.0 + +Many people came together to create Rust 1.82.0. We couldn't have done it without all of you. [Thanks!](https://thanks.rust-lang.org/rust/1.82.0/) From c4b85e3221374bd7bff6276868f603002e967727 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 10:46:08 -0700 Subject: [PATCH 02/25] Update the `min_exhaustive_patterns` section Co-authored-by: Kevin Reid --- posts/2024-10-17-Rust-1.82.0.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index c720a2066..c2d11a107 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -57,13 +57,13 @@ The Rust target `aarch64-apple-darwin` for macOS on ARM64 (M1-family or later Ap [The targets](https://doc.rust-lang.org/nightly/rustc/platform-support/apple-ios-macabi.html) are now tier 2, and can be downloaded with `rustup target add aarch64-apple-ios-macabi x86_64-apple-ios-macabi`, so now is an excellent time to update your CI pipeline to test that your code also runs in iOS-like environments. -### Minimal exhaustive patterns +### Omitting empty types in pattern matching -Empty patterns can now be omitted in common cases: +Patterns which match empty (a.k.a. uninhabited) types by value can now be omitted: ```rust use std::convert::Infallible; -pub fn safe_unwrap(x: Result) -> T { +pub fn unwrap_without_panic(x: Result) -> T { let Ok(x) = x; // the `Err` case does not need to appear x } @@ -71,19 +71,19 @@ pub fn safe_unwrap(x: Result) -> T { This works with empty types such as a variant-less `enum Void {}`, or structs and enums with a visible empty field and no `#[non_exhaustive]` attribute. It will also be particularly useful in combination with the never type `!`, although that type is still unstable at this time. -This feature is "minimal" because there are still some exclusions at this time. For reasons related to uninitialized values and unsafe code, omitting patterns is not allowed if the empty type is accessed through a reference, pointer, or union field: +There are still some cases where empty patterns must still be written. For reasons related to uninitialized values and unsafe code, omitting patterns is not allowed if the empty type is accessed through a reference, pointer, or union field: ```rust -pub fn safe_unwrap_ref(x: &Result) -> &T { +pub fn unwrap_ref_without_panic(x: &Result) -> &T { match x { Ok(x) => x, - // this branch cannot be omitted because of the reference + // this arm cannot be omitted because of the reference Err(infallible) => match *infallible {}, } } ``` -To avoid interfering with crates that wish to support several rust versions, branches with empty patterns are not yet warned as "unreachable", despite the fact that they can be removed. +To avoid interfering with crates that wish to support several Rust versions, `match` arms with empty patterns are not yet reported as “unreachable code” warnings, despite the fact that they can be removed. ### Floating-point NaN semantics and `const` From e6c56014ede654e841fffb09a257eefc29cb781c Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 11:01:09 -0700 Subject: [PATCH 03/25] Don't call "NaN boxing" an optimization Co-authored-by: Kevin Reid --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index c2d11a107..da8d02715 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -89,7 +89,7 @@ To avoid interfering with crates that wish to support several Rust versions, `ma Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "Not a Number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()`. Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! -With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced optimization techniques such as NaN boxing to be realized in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). +With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced data representation techniques such as NaN boxing to be implemented in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). With the semantics for NaN values settled, this release also permits the use of floating-point operations in `const fn`. Due to the reasons described above, operations like `(0.0 / 0.0).is_sign_positive()` can produce a different result when executed at compile-time vs at run-time; this is not a bug and code must not rely on a `const fn` always producing the exact same result. From a8658a586b769bd2e86e66452d86253858716f81 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 11:03:04 -0700 Subject: [PATCH 04/25] Spell out `repr(packed)` structs Co-authored-by: Kevin Reid --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index da8d02715..af444e0b8 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -95,7 +95,7 @@ With the semantics for NaN values settled, this release also permits the use of ### Native syntax for creating a raw pointer -Unsafe code sometimes has to deal with pointers that may dangle, may be misaligned, or may not point to valid data. A common case where this comes up are packed structs. In such a case, it is important to avoid creating a reference, as that would cause undefined behavior. This means the usual `&` and `&mut` operators cannot be used, as those create a reference -- even if the reference is immediately cast to a raw pointer, it's too late to avoid the undefined behavior. +Unsafe code sometimes has to deal with pointers that may dangle, may be misaligned, or may not point to valid data. A common case where this comes up are `repr(packed)` structs. In such a case, it is important to avoid creating a reference, as that would cause undefined behavior. This means the usual `&` and `&mut` operators cannot be used, as those create a reference -- even if the reference is immediately cast to a raw pointer, it's too late to avoid the undefined behavior. For several years, the macros `std::ptr::addr_of!` and `std::ptr::addr_of_mut!` have served this purpose. Now the time has come to provide a proper native syntax for this operation: `addr_of!(expr)` becomes `&raw const expr`, and `addr_of_mut!(expr)` becomes `&raw mut expr`. For example: From 3426f0e8b17637122e49a0a1019aa718592953e8 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 11:04:06 -0700 Subject: [PATCH 05/25] Link to `no_mangle` in the reference Co-authored-by: Kevin Reid --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index af444e0b8..b392a6847 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -158,7 +158,7 @@ A future version of Rust is expected to generalize this to other expressions whi ### Unsafe attributes -Some Rust attributes, such as `no_mangle`, can be used to [cause Undefined Behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this was regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: +Some Rust attributes, such as [`no_mangle`](https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute), can be used to [cause Undefined Behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this was regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: ```rust #[unsafe(no_mangle)] From c51207ae9ae4b83301634ff16a982396edf6ed8e Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 11:14:53 -0700 Subject: [PATCH 06/25] Remove `Waker::waker` --- posts/2024-10-17-Rust-1.82.0.md | 1 - 1 file changed, 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index b392a6847..58ef05b6d 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -305,7 +305,6 @@ for more details. These APIs are now stable in const contexts: - [`std::task::Waker::from_raw`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw) -- [`std::task::Waker::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Waker.html#method.from_raw) - [`std::task::Context::from_waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.from_waker) - [`std::task::Context::waker`](https://doc.rust-lang.org/nightly/std/task/struct.Context.html#method.waker) - [`$integer::from_str_radix`](https://doc.rust-lang.org/nightly/std/primitive.u32.html#method.from_str_radix) From 414e454b4cb24ed9bdded85e6d1c93ee505e38fa Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 11:49:28 -0700 Subject: [PATCH 07/25] Avoid ARM64/AArch64 by calling it 64-bit ARM --- posts/2024-10-17-Rust-1.82.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 58ef05b6d..0b4099b47 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -47,9 +47,9 @@ By default `cargo info` describes the package version in the local `Cargo.lock`, ### Apple target promotions -#### macOS on ARM64 is now Tier 1 +#### macOS on 64-bit ARM is now Tier 1 -The Rust target `aarch64-apple-darwin` for macOS on ARM64 (M1-family or later Apple Silicon CPUs) is now a tier 1 target, indicating our highest guarantee of working properly. As the [platform support](https://doc.rust-lang.org/stable/rustc/platform-support.html) page describes, every change in the Rust repository must pass full tests on every tier 1 target before it can be merged. This ARM64 target was added to tier 2 back in Rust 1.49, making it available in `rustup`, and this new milestone raises it on par with ARM64 Linux and the X86 macOS, Linux, and Windows targets. +The Rust target `aarch64-apple-darwin` for macOS on 64-bit ARM (M1-family or later Apple Silicon CPUs) is now a tier 1 target, indicating our highest guarantee of working properly. As the [platform support](https://doc.rust-lang.org/stable/rustc/platform-support.html) page describes, every change in the Rust repository must pass full tests on every tier 1 target before it can be merged. This target was introduced as tier 2 back in Rust 1.49, making it available in `rustup`. This new milestone puts the `aarch64-apple-darwin` target on par with the 64-bit ARM Linux and the X86 macOS, Linux, and Windows targets. #### Mac Catalyst targets are now Tier 2 From 27e63bd0c2e68dd8b4eb06b67194cc4c2a9e84be Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 12:13:51 -0700 Subject: [PATCH 08/25] Use `&raw mut STATIC_MUT` in forward-looking code Co-authored-by: Travis Cross --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 0b4099b47..96828692d 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -137,7 +137,7 @@ extern "C" { static EXTERN_STATIC: Type; } fn main() { - let static_mut_ptr = std::ptr::addr_of_mut!(STATIC_MUT); + let static_mut_ptr = &raw mut STATIC_MUT; let extern_static_ptr = &raw const EXTERN_STATIC; } ``` From 6a1bf3c2e83eb5aecbe240e495acea5f2e4ccc82 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 17:22:06 -0700 Subject: [PATCH 09/25] Lowercase "not a number" Co-authored-by: Travis Cross --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 96828692d..4fa50541f 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -87,7 +87,7 @@ To avoid interfering with crates that wish to support several Rust versions, `ma ### Floating-point NaN semantics and `const` -Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "Not a Number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()`. Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! +Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "not a number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()`. Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced data representation techniques such as NaN boxing to be implemented in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). From d950248fb516bd3442b706f77a87446c836ebf5a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 17:23:27 -0700 Subject: [PATCH 10/25] Update unsafe attributes Co-authored-by: Travis Cross --- posts/2024-10-17-Rust-1.82.0.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 4fa50541f..652c571f1 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -165,13 +165,15 @@ Some Rust attributes, such as [`no_mangle`](https://doc.rust-lang.org/reference/ pub fn my_global_function() { } ``` -The old form of the attribute (without `unsafe`) is currently still accepted, but might be linted against at some point in the future, and will be a hard error in a future edition. +The old form of the attribute (without `unsafe`) is currently still accepted, but might be linted against at some point in the future, and will be a hard error in Rust 2024. This affects the following attributes: - `no_mangle` - `link_section` - `export_name` +For further details, see the ["Unsafe attributes"](https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html) chapter of the edition guide. + ### Constants as assembly immediates The `const` assembly operand now provides a way to use integers as immediates From d735b97d6a04cb5820fa5be4e411d446442b376f Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 17:27:42 -0700 Subject: [PATCH 11/25] Tweak wording of `cargo info` versions, and drop feature callout --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 652c571f1..516227f52 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -43,7 +43,7 @@ code. note: to see how you depend on cc, run `cargo tree --invert --package cc@1.1.23` -By default `cargo info` describes the package version in the local `Cargo.lock`, if any, but as you can see it will indicate when there's a newer version too, and `cargo info cc@1.1.30` would report on that. The feature list also indicates a `+` next to any that are enabled. +By default, `cargo info` describes the package version in the local `Cargo.lock`, if any. As you can see, it will indicate when there's a newer version too, and `cargo info cc@1.1.30` would report on that. ### Apple target promotions From ead205c8cc621ddc28423d09bdd8723af6f22a53 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 17:46:03 -0700 Subject: [PATCH 12/25] Add a section for unsafe extern Co-authored-by: Travis Cross --- posts/2024-10-17-Rust-1.82.0.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 516227f52..55fbc1cba 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -156,6 +156,27 @@ Relaxing this may cause problems where some unsafe blocks are now reported as un A future version of Rust is expected to generalize this to other expressions which would be safe in this position, not just statics. +### Unsafe extern + +Rust code can use functions and statics from foreign code. The type signatures of these foreign items are provided in `extern` blocks. Historically, all items within `extern` blocks have been unsafe to call, but we didn't have to write `unsafe` anywhere on the `extern` block itself. + +However, if a signature within the `extern` block is incorrect, then using that item will result in undefined behavior. Would that be the fault of the person who wrote the `extern` block, or the person who used that item? + +We've decided that it's the responsibility of the person writing the `extern` block to ensure that all signatures contained within it are correct, and so we now allow writing `unsafe extern`: + +```rust +unsafe extern { + pub safe fn sqrt(x: f64) -> f64; + pub unsafe fn strlen(p: *const u8) -> usize; +} +``` + +One benefit of this is that items within an `unsafe extern` block can be marked as safe to call. In the above example, we can call `sqrt` without using `unsafe`. Items that aren't marked with either `safe` or `unsafe` are conservatively assumed to be `unsafe`. + +In future releases, we'll be encouraging the use of `unsafe extern` with lints. Starting in Rust 2024, using `unsafe extern` will be required. + +For further details, see [RFC 3484](https://github.com/rust-lang/rfcs/blob/master/text/3484-unsafe-extern-blocks.md) and the ["Unsafe extern blocks"](https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-extern.html) chapter of the edition guide. + ### Unsafe attributes Some Rust attributes, such as [`no_mangle`](https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute), can be used to [cause Undefined Behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this was regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: From 26498abf6f93c221d8a8dc385162a67001da1dd1 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 17:47:04 -0700 Subject: [PATCH 13/25] Re-title unsafe extern --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 55fbc1cba..f3429ec6d 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -156,7 +156,7 @@ Relaxing this may cause problems where some unsafe blocks are now reported as un A future version of Rust is expected to generalize this to other expressions which would be safe in this position, not just statics. -### Unsafe extern +### Safe items in `unsafe extern` Rust code can use functions and statics from foreign code. The type signatures of these foreign items are provided in `extern` blocks. Historically, all items within `extern` blocks have been unsafe to call, but we didn't have to write `unsafe` anywhere on the `extern` block itself. From 0d73760828d777b4fc84e6fb5044f939c2364ee3 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 17:50:45 -0700 Subject: [PATCH 14/25] Reorder lang sections --- posts/2024-10-17-Rust-1.82.0.md | 130 ++++++++++++++++---------------- 1 file changed, 65 insertions(+), 65 deletions(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index f3429ec6d..93452be38 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -57,42 +57,6 @@ The Rust target `aarch64-apple-darwin` for macOS on 64-bit ARM (M1-family or lat [The targets](https://doc.rust-lang.org/nightly/rustc/platform-support/apple-ios-macabi.html) are now tier 2, and can be downloaded with `rustup target add aarch64-apple-ios-macabi x86_64-apple-ios-macabi`, so now is an excellent time to update your CI pipeline to test that your code also runs in iOS-like environments. -### Omitting empty types in pattern matching - -Patterns which match empty (a.k.a. uninhabited) types by value can now be omitted: - -```rust -use std::convert::Infallible; -pub fn unwrap_without_panic(x: Result) -> T { - let Ok(x) = x; // the `Err` case does not need to appear - x -} -``` - -This works with empty types such as a variant-less `enum Void {}`, or structs and enums with a visible empty field and no `#[non_exhaustive]` attribute. It will also be particularly useful in combination with the never type `!`, although that type is still unstable at this time. - -There are still some cases where empty patterns must still be written. For reasons related to uninitialized values and unsafe code, omitting patterns is not allowed if the empty type is accessed through a reference, pointer, or union field: - -```rust -pub fn unwrap_ref_without_panic(x: &Result) -> &T { - match x { - Ok(x) => x, - // this arm cannot be omitted because of the reference - Err(infallible) => match *infallible {}, - } -} -``` - -To avoid interfering with crates that wish to support several Rust versions, `match` arms with empty patterns are not yet reported as “unreachable code” warnings, despite the fact that they can be removed. - -### Floating-point NaN semantics and `const` - -Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "not a number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()`. Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! - -With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced data representation techniques such as NaN boxing to be implemented in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). - -With the semantics for NaN values settled, this release also permits the use of floating-point operations in `const fn`. Due to the reasons described above, operations like `(0.0 / 0.0).is_sign_positive()` can produce a different result when executed at compile-time vs at run-time; this is not a bug and code must not rely on a `const fn` always producing the exact same result. - ### Native syntax for creating a raw pointer Unsafe code sometimes has to deal with pointers that may dangle, may be misaligned, or may not point to valid data. A common case where this comes up are `repr(packed)` structs. In such a case, it is important to avoid creating a reference, as that would cause undefined behavior. This means the usual `&` and `&mut` operators cannot be used, as those create a reference -- even if the reference is immediately cast to a raw pointer, it's too late to avoid the undefined behavior. @@ -127,35 +91,6 @@ fn main() { The native syntax makes it more clear that the operand expression of these operators is interpreted as a [place expression](https://www.ralfj.de/blog/2024/08/14/places.html). It also avoids the term "address-of" when referring to the action of creating a pointer. A pointer is [more than just an address](https://rust-lang.github.io/rfcs/3559-rust-has-provenance.html), so Rust is moving away from terms like "address-of" that reaffirm a false equivalence of pointers and addresses. -### Safely addressing unsafe `static`s - -This code is now allowed: - -```rust -static mut STATIC_MUT: Type = Type::new(); -extern "C" { - static EXTERN_STATIC: Type; -} -fn main() { - let static_mut_ptr = &raw mut STATIC_MUT; - let extern_static_ptr = &raw const EXTERN_STATIC; -} -``` - -In an expression context, `STATIC_MUT` and `EXTERN_STATIC` are [place expressions](https://doc.rust-lang.org/reference/expressions.html#place-expressions-and-value-expressions). Previously, the compiler's safety checks were not aware that the raw ref operator did not actually affect the operand's place, treating it as a possible read or write to a pointer. No unsafety is actually present, however, as it just creates a pointer. - -Relaxing this may cause problems where some unsafe blocks are now reported as unused if you deny the `unused_unsafe` lint, but they are now only useful on older versions. Annotate these unsafe blocks with `#[allow(unused_unsafe)]` if you wish to support multiple versions of Rust, as in this example diff: - -```diff - static mut STATIC_MUT: Type = Type::new(); - fn main() { -+ #[allow(unused_unsafe)] - let static_mut_ptr = unsafe { std::ptr::addr_of_mut!(STATIC_MUT) }; - } -``` - -A future version of Rust is expected to generalize this to other expressions which would be safe in this position, not just statics. - ### Safe items in `unsafe extern` Rust code can use functions and statics from foreign code. The type signatures of these foreign items are provided in `extern` blocks. Historically, all items within `extern` blocks have been unsafe to call, but we didn't have to write `unsafe` anywhere on the `extern` block itself. @@ -195,6 +130,42 @@ This affects the following attributes: For further details, see the ["Unsafe attributes"](https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html) chapter of the edition guide. +### Omitting empty types in pattern matching + +Patterns which match empty (a.k.a. uninhabited) types by value can now be omitted: + +```rust +use std::convert::Infallible; +pub fn unwrap_without_panic(x: Result) -> T { + let Ok(x) = x; // the `Err` case does not need to appear + x +} +``` + +This works with empty types such as a variant-less `enum Void {}`, or structs and enums with a visible empty field and no `#[non_exhaustive]` attribute. It will also be particularly useful in combination with the never type `!`, although that type is still unstable at this time. + +There are still some cases where empty patterns must still be written. For reasons related to uninitialized values and unsafe code, omitting patterns is not allowed if the empty type is accessed through a reference, pointer, or union field: + +```rust +pub fn unwrap_ref_without_panic(x: &Result) -> &T { + match x { + Ok(x) => x, + // this arm cannot be omitted because of the reference + Err(infallible) => match *infallible {}, + } +} +``` + +To avoid interfering with crates that wish to support several Rust versions, `match` arms with empty patterns are not yet reported as “unreachable code” warnings, despite the fact that they can be removed. + +### Floating-point NaN semantics and `const` + +Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "not a number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()`. Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! + +With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced data representation techniques such as NaN boxing to be implemented in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). + +With the semantics for NaN values settled, this release also permits the use of floating-point operations in `const fn`. Due to the reasons described above, operations like `(0.0 / 0.0).is_sign_positive()` can produce a different result when executed at compile-time vs at run-time; this is not a bug and code must not rely on a `const fn` always producing the exact same result. + ### Constants as assembly immediates The `const` assembly operand now provides a way to use integers as immediates @@ -251,6 +222,35 @@ mov rax, rax # save the return value See [the reference](https://doc.rust-lang.org/reference/inline-assembly.html) for more details. +### Safely addressing unsafe `static`s + +This code is now allowed: + +```rust +static mut STATIC_MUT: Type = Type::new(); +extern "C" { + static EXTERN_STATIC: Type; +} +fn main() { + let static_mut_ptr = &raw mut STATIC_MUT; + let extern_static_ptr = &raw const EXTERN_STATIC; +} +``` + +In an expression context, `STATIC_MUT` and `EXTERN_STATIC` are [place expressions](https://doc.rust-lang.org/reference/expressions.html#place-expressions-and-value-expressions). Previously, the compiler's safety checks were not aware that the raw ref operator did not actually affect the operand's place, treating it as a possible read or write to a pointer. No unsafety is actually present, however, as it just creates a pointer. + +Relaxing this may cause problems where some unsafe blocks are now reported as unused if you deny the `unused_unsafe` lint, but they are now only useful on older versions. Annotate these unsafe blocks with `#[allow(unused_unsafe)]` if you wish to support multiple versions of Rust, as in this example diff: + +```diff + static mut STATIC_MUT: Type = Type::new(); + fn main() { ++ #[allow(unused_unsafe)] + let static_mut_ptr = unsafe { std::ptr::addr_of_mut!(STATIC_MUT) }; + } +``` + +A future version of Rust is expected to generalize this to other expressions which would be safe in this position, not just statics. + ### Stabilized APIs - [`std::thread::Builder::spawn_unchecked`](https://doc.rust-lang.org/stable/std/thread/struct.Builder.html#method.spawn_unchecked) From 2d61ada0f01c371702538757d8cc3422c1b31dff Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Wed, 16 Oct 2024 18:06:48 -0700 Subject: [PATCH 15/25] Add code tags to `cargo info` output --- posts/2024-10-17-Rust-1.82.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 93452be38..95b6cc1cf 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -26,7 +26,7 @@ Cargo now has an [`info` subcommand](https://doc.rust-lang.org/nightly/cargo/com For example, here's what you could see for `cargo info cc`:
-cc #build-dependencies
+cc #build-dependencies
 A build-time dependency for Cargo build scripts to assist in invoking the native
 C compiler to compile native C code into a static archive to be linked into Rust
 code.
@@ -41,7 +41,7 @@ code.
   jobserver = []
   parallel  = [dep:libc, dep:jobserver]
 note: to see how you depend on cc, run `cargo tree --invert --package cc@1.1.23`
-
+ By default, `cargo info` describes the package version in the local `Cargo.lock`, if any. As you can see, it will indicate when there's a newer version too, and `cargo info cc@1.1.30` would report on that. From 307525a99c2358c20ce6ca9f8cf478b848b7377e Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 13:38:09 +0000 Subject: [PATCH 16/25] Clarify NaN behavior wrt `==` Co-authored-by: Ralf Jung --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 95b6cc1cf..fed5d292f 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -160,7 +160,7 @@ To avoid interfering with crates that wish to support several Rust versions, `ma ### Floating-point NaN semantics and `const` -Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "not a number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()`. Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! +Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "not a number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()` -- however, both are entirely ignored by `==` (which always returns `false` on a NaN). Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced data representation techniques such as NaN boxing to be implemented in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). From 8970b99dae799adc7124baf3032735828f74efa8 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 14:36:46 +0000 Subject: [PATCH 17/25] Add section on precise capturing `use<..>` syntax Thanks to CE for details on the compiler's use-case that informs an example here. --- posts/2024-10-17-Rust-1.82.0.md | 77 +++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index fed5d292f..0a9fd78b6 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -57,6 +57,83 @@ The Rust target `aarch64-apple-darwin` for macOS on 64-bit ARM (M1-family or lat [The targets](https://doc.rust-lang.org/nightly/rustc/platform-support/apple-ios-macabi.html) are now tier 2, and can be downloaded with `rustup target add aarch64-apple-ios-macabi x86_64-apple-ios-macabi`, so now is an excellent time to update your CI pipeline to test that your code also runs in iOS-like environments. +### Precise capturing `use<..>` syntax + +Rust now supports `use<..>` syntax within certain impl Trait bounds to control which generic lifetime parameters are captured. + +Return-position impl Trait (RPIT) types in Rust *capture* certain generic parameters. Capturing a generic parameter allows that parameter to be used in the hidden type. That in turn affects borrow checking. + +In Rust 2021 and earlier editions, lifetime parameters are not captured in opaque types on bare functions and on functions and methods of inherent impls unless those lifetime parameters are mentioned syntactically in the opaque type. E.g., this is an error: + +```rust +//@ edition: 2021 +fn f(x: &()) -> impl Sized { x } +``` + +``` +error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds + --> src/main.rs:1:30 + | +1 | fn f(x: &()) -> impl Sized { x } + | --- ---------- ^ + | | | + | | opaque type defined here + | hidden type `&()` captures the anonymous lifetime defined here + | +help: add a `use<...>` bound to explicitly capture `'_` + | +1 | fn f(x: &()) -> impl Sized + use<'_> { x } + | +++++++++ +``` + +With the new `use<..>` syntax, we can fix this, as suggested in the error, by writing: + +```rust +fn f(x: &()) -> impl Sized + use<'_> { x } +``` + +Previously, correctly fixing this class of error required defining a dummy trait, conventionally called `Captures`, and using it as follows: + +```rust +trait Captures {} +impl Captures for U {} + +fn f(x: &()) -> impl Sized + Captures<&'_ ()> { x } +``` + +That was called ["the `Captures` trick"](https://github.com/rust-lang/rfcs/blob/master/text/3498-lifetime-capture-rules-2024.md#the-captures-trick), and it was a bit baroque and subtle. It's no longer needed. + +There was a less correct way but more convenient way to fix this that was often used called ["the outlives trick"](https://github.com/rust-lang/rfcs/blob/master/text/3498-lifetime-capture-rules-2024.md#the-outlives-trick). The compiler even previously suggested doing this. That trick looked like this: + +```rust +fn f(x: &()) -> impl Sized + '_ { x } +``` + +In this simple case, the trick is exactly equivalent to `+ use<'_>` for subtle reasons explained in [RFC 3498](https://github.com/rust-lang/rfcs/blob/master/text/3498-lifetime-capture-rules-2024.md). However, in real life cases, this overconstrains the bounds on the returned opaque type, leading to problems. For example, consider this code, which is inspired by a real case in the Rust compiler: + +```rust +struct Ctx<'cx>(&'cx u8); + +fn f<'cx, 'a>( + cx: Ctx<'cx>, + x: &'a u8, +) -> impl Iterator + 'cx { + core::iter::once_with(move || { + eprintln!("LOG: {}", cx.0); + x + }) +//~^ ERROR lifetime may not live long enough +} +``` + +We can't remove the `+ 'cx`, since the lifetime is used in the hidden type and so must be captured. Neither can we add a bound of `'a: 'cx`, since these lifetimes are not actually related and it won't in general be true that `'a` outlives `'cx`. If we write `+ use<'cx, 'a>` instead, however, this will work and have the correct bounds. + +There are some limitations to what we're stabilizing today. The `use<..>` syntax cannot currently appear within traits or within trait impls (but note that there, in-scope lifetime parameters are already captured by default), and it must list all in-scope generic type and const parameters. We hope to lift these restrictions over time. + +Note that in Rust 2024, the examples above will "just work" without needing `use<..>` syntax (or any tricks). This is because in the new edition, opaque types will automatically capture all lifetime parameters in scope. This is a better default, and we've seen a lot of evidence about how this cleans up code. In Rust 2024, `use<..>` syntax will serve as an important way of opting-out of that default. + +For more details about `use<..>` syntax, capturing, and how this applies to Rust 2024, see the ["RPIT lifetime capture rules"](https://doc.rust-lang.org/nightly/edition-guide/rust-2024/rpit-lifetime-capture.html) chapter of the edition guide. For details about the overall direction, see our recent blog post, ["Changes to `impl Trait` in Rust 2024"](https://blog.rust-lang.org/2024/09/05/impl-trait-capture-rules.html). + ### Native syntax for creating a raw pointer Unsafe code sometimes has to deal with pointers that may dangle, may be misaligned, or may not point to valid data. A common case where this comes up are `repr(packed)` structs. In such a case, it is important to avoid creating a reference, as that would cause undefined behavior. This means the usual `&` and `&mut` operators cannot be used, as those create a reference -- even if the reference is immediately cast to a raw pointer, it's too late to avoid the undefined behavior. From 2b4aef0cbeca656a275b6808530aa04035c21bd7 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 14:48:37 +0000 Subject: [PATCH 18/25] Tweak wording in header about `unsafe extern` Since we're adding `unsafe extern` in this release, saying "safe items with unsafe extern" rather than "safe items in unsafe extern" here sounds more right to my ear. --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 0a9fd78b6..c56ec5eab 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -168,7 +168,7 @@ fn main() { The native syntax makes it more clear that the operand expression of these operators is interpreted as a [place expression](https://www.ralfj.de/blog/2024/08/14/places.html). It also avoids the term "address-of" when referring to the action of creating a pointer. A pointer is [more than just an address](https://rust-lang.github.io/rfcs/3559-rust-has-provenance.html), so Rust is moving away from terms like "address-of" that reaffirm a false equivalence of pointers and addresses. -### Safe items in `unsafe extern` +### Safe items with `unsafe extern` Rust code can use functions and statics from foreign code. The type signatures of these foreign items are provided in `extern` blocks. Historically, all items within `extern` blocks have been unsafe to call, but we didn't have to write `unsafe` anywhere on the `extern` block itself. From 632ea501c3f62cffe08948d30ec94c4668470d5b Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 14:54:09 +0000 Subject: [PATCH 19/25] Remove stray word --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index c56ec5eab..f9ed42137 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -103,7 +103,7 @@ fn f(x: &()) -> impl Sized + Captures<&'_ ()> { x } That was called ["the `Captures` trick"](https://github.com/rust-lang/rfcs/blob/master/text/3498-lifetime-capture-rules-2024.md#the-captures-trick), and it was a bit baroque and subtle. It's no longer needed. -There was a less correct way but more convenient way to fix this that was often used called ["the outlives trick"](https://github.com/rust-lang/rfcs/blob/master/text/3498-lifetime-capture-rules-2024.md#the-outlives-trick). The compiler even previously suggested doing this. That trick looked like this: +There was a less correct but more convenient way to fix this that was often used called ["the outlives trick"](https://github.com/rust-lang/rfcs/blob/master/text/3498-lifetime-capture-rules-2024.md#the-outlives-trick). The compiler even previously suggested doing this. That trick looked like this: ```rust fn f(x: &()) -> impl Sized + '_ { x } From de10a887b12479fbaa30376a140d3beb95162cc2 Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 17 Oct 2024 08:03:26 -0700 Subject: [PATCH 20/25] Remove a redundant "still" --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index f9ed42137..606911371 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -221,7 +221,7 @@ pub fn unwrap_without_panic(x: Result) -> T { This works with empty types such as a variant-less `enum Void {}`, or structs and enums with a visible empty field and no `#[non_exhaustive]` attribute. It will also be particularly useful in combination with the never type `!`, although that type is still unstable at this time. -There are still some cases where empty patterns must still be written. For reasons related to uninitialized values and unsafe code, omitting patterns is not allowed if the empty type is accessed through a reference, pointer, or union field: +There are some cases where empty patterns must still be written. For reasons related to uninitialized values and unsafe code, omitting patterns is not allowed if the empty type is accessed through a reference, pointer, or union field: ```rust pub fn unwrap_ref_without_panic(x: &Result) -> &T { From 28d1fb5b8a5890d814fab45d754fe943f3b0f2e4 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 15:05:44 +0000 Subject: [PATCH 21/25] Say "use" rather than "call" for `unsafe extern` items We can have static items as well as function items within an `extern` block, so let's say "use" rather than "call" when referring to these. Let's also give an example of a static item to show how `safe` allows for safe access to these items. --- posts/2024-10-17-Rust-1.82.0.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 606911371..6213ceff7 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -170,7 +170,7 @@ The native syntax makes it more clear that the operand expression of these opera ### Safe items with `unsafe extern` -Rust code can use functions and statics from foreign code. The type signatures of these foreign items are provided in `extern` blocks. Historically, all items within `extern` blocks have been unsafe to call, but we didn't have to write `unsafe` anywhere on the `extern` block itself. +Rust code can use functions and statics from foreign code. The type signatures of these foreign items are provided in `extern` blocks. Historically, all items within `extern` blocks have been unsafe to use, but we didn't have to write `unsafe` anywhere on the `extern` block itself. However, if a signature within the `extern` block is incorrect, then using that item will result in undefined behavior. Would that be the fault of the person who wrote the `extern` block, or the person who used that item? @@ -178,12 +178,13 @@ We've decided that it's the responsibility of the person writing the `extern` bl ```rust unsafe extern { + pub safe static TAU: f64; pub safe fn sqrt(x: f64) -> f64; pub unsafe fn strlen(p: *const u8) -> usize; } ``` -One benefit of this is that items within an `unsafe extern` block can be marked as safe to call. In the above example, we can call `sqrt` without using `unsafe`. Items that aren't marked with either `safe` or `unsafe` are conservatively assumed to be `unsafe`. +One benefit of this is that items within an `unsafe extern` block can be marked as safe to use. In the above example, we can call `sqrt` or read `TAU` without using `unsafe`. Items that aren't marked with either `safe` or `unsafe` are conservatively assumed to be `unsafe`. In future releases, we'll be encouraging the use of `unsafe extern` with lints. Starting in Rust 2024, using `unsafe extern` will be required. From a0e67b9dedadd4ded161e5689e1fc6d474919dbb Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 15:10:13 +0000 Subject: [PATCH 22/25] Lowercase "undefined behavior" --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 6213ceff7..646fe2f9c 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -192,7 +192,7 @@ For further details, see [RFC 3484](https://github.com/rust-lang/rfcs/blob/maste ### Unsafe attributes -Some Rust attributes, such as [`no_mangle`](https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute), can be used to [cause Undefined Behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this was regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: +Some Rust attributes, such as [`no_mangle`](https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute), can be used to [cause undefined behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this was regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: ```rust #[unsafe(no_mangle)] From a89f927257bbf135972568770236c617c3388e5a Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 15:11:04 +0000 Subject: [PATCH 23/25] Use subjunctive mood It's more correct to say "were" rather than "was" here, and it sounds better to my ear. --- posts/2024-10-17-Rust-1.82.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 646fe2f9c..cd6177903 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -192,7 +192,7 @@ For further details, see [RFC 3484](https://github.com/rust-lang/rfcs/blob/maste ### Unsafe attributes -Some Rust attributes, such as [`no_mangle`](https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute), can be used to [cause undefined behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this was regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: +Some Rust attributes, such as [`no_mangle`](https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute), can be used to [cause undefined behavior without any `unsafe` block](https://github.com/rust-lang/rust/issues/28179). If this were regular code we would require them to be placed in an `unsafe {}` block, but so far attributes have not had comparable syntax. To reflect the fact that these attributes can undermine Rust's safety guarantees, they are now considered "unsafe" and should be written as follows: ```rust #[unsafe(no_mangle)] From 4b6db4e1bb71e333be62da0d23019740fccf4f5a Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Thu, 17 Oct 2024 08:50:24 -0700 Subject: [PATCH 24/25] Put backticks around `impl Trait` --- posts/2024-10-17-Rust-1.82.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index cd6177903..81439dce7 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -59,9 +59,9 @@ The Rust target `aarch64-apple-darwin` for macOS on 64-bit ARM (M1-family or lat ### Precise capturing `use<..>` syntax -Rust now supports `use<..>` syntax within certain impl Trait bounds to control which generic lifetime parameters are captured. +Rust now supports `use<..>` syntax within certain `impl Trait` bounds to control which generic lifetime parameters are captured. -Return-position impl Trait (RPIT) types in Rust *capture* certain generic parameters. Capturing a generic parameter allows that parameter to be used in the hidden type. That in turn affects borrow checking. +Return-position `impl Trait` (RPIT) types in Rust *capture* certain generic parameters. Capturing a generic parameter allows that parameter to be used in the hidden type. That in turn affects borrow checking. In Rust 2021 and earlier editions, lifetime parameters are not captured in opaque types on bare functions and on functions and methods of inherent impls unless those lifetime parameters are mentioned syntactically in the opaque type. E.g., this is an error: From d307a986683b48c773d06daf58148646fb3de7cc Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Thu, 17 Oct 2024 15:51:43 +0000 Subject: [PATCH 25/25] Improve some copy in the floats section There were some long and grammatically involved sentences that it makes sense to refactor a bit here for better readability. --- posts/2024-10-17-Rust-1.82.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/posts/2024-10-17-Rust-1.82.0.md b/posts/2024-10-17-Rust-1.82.0.md index 81439dce7..62d302af1 100644 --- a/posts/2024-10-17-Rust-1.82.0.md +++ b/posts/2024-10-17-Rust-1.82.0.md @@ -238,11 +238,11 @@ To avoid interfering with crates that wish to support several Rust versions, `ma ### Floating-point NaN semantics and `const` -Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of "NaN values": this is short for "not a number", and is used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists: a NaN value has a sign that can be checked with `f.is_sign_positive()`, and it has a "payload" that can be extracted with `f.to_bits()` -- however, both are entirely ignored by `==` (which always returns `false` on a NaN). Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! +Operations on floating-point values (of type `f32` and `f64`) are famously subtle. One of the reasons for this is the existence of NaN ("not a number") values which are used to represent e.g. the result of `0.0 / 0.0`. What makes NaN values subtle is that more than one possible NaN value exists. A NaN value has a sign (that can be checked with `f.is_sign_positive()`) and a payload (that can be extracted with `f.to_bits()`). However, both the sign and payload of NaN values are entirely ignored by `==` (which always returns `false`). Despite very successful efforts to standardize the behavior of floating-point operations across hardware architectures, the details of when a NaN is positive or negative and what its exact payload is differ across architectures. To make matters even more complicated, Rust and its LLVM backend apply optimizations to floating-point operations when the exact numeric result is guaranteed not to change, but those optimizations can change which NaN value is produced. For instance, `f * 1.0` may be optimized to just `f`. However, if `f` is a NaN, this can change the exact bit pattern of the result! With this release, Rust standardizes on a set of rules for how NaN values behave. This set of rules is *not* fully deterministic, which means that the result of operations like `(0.0 / 0.0).is_sign_positive()` can differ depending on the hardware architecture, optimization levels, and the surrounding code. Code that aims to be fully portable should avoid using `to_bits` and should use `f.signum() == 1.0` instead of `f.is_sign_positive()`. However, the rules are carefully chosen to still allow advanced data representation techniques such as NaN boxing to be implemented in Rust code. For more details on what the exact rules are, check out our [documentation](https://doc.rust-lang.org/std/primitive.f32.html#nan-bit-patterns). -With the semantics for NaN values settled, this release also permits the use of floating-point operations in `const fn`. Due to the reasons described above, operations like `(0.0 / 0.0).is_sign_positive()` can produce a different result when executed at compile-time vs at run-time; this is not a bug and code must not rely on a `const fn` always producing the exact same result. +With the semantics for NaN values settled, this release also permits the use of floating-point operations in `const fn`. Due to the reasons described above, operations like `(0.0 / 0.0).is_sign_positive()` can produce a different result when executed at compile-time vs at run-time. This is not a bug, and code must not rely on a `const fn` always producing the exact same result. ### Constants as assembly immediates