Skip to content

Commit

Permalink
update rust 1.82 draft
Browse files Browse the repository at this point in the history
  • Loading branch information
funkill committed Oct 17, 2024
1 parent 07a3b6a commit 7b1cefa
Showing 1 changed file with 83 additions and 5 deletions.
88 changes: 83 additions & 5 deletions originals/announcements/2024-10-17-Rust-1.82.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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<T: ?Sized> {}
impl<T: ?Sized, U: ?Sized> Captures<T> 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 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<Item = &'a u8> + '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.
Expand Down Expand Up @@ -91,30 +168,31 @@ 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.
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?

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

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:
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)]
Expand Down Expand Up @@ -144,7 +222,7 @@ pub fn unwrap_without_panic<T>(x: Result<T, Infallible>) -> 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<T>(x: &Result<T, Infallible>) -> &T {
Expand Down

0 comments on commit 7b1cefa

Please sign in to comment.