Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize #[repr(transparent)] on enums in Rust 1.42.0 #68122

Merged
merged 2 commits into from
Jan 27, 2020

Conversation

Centril
Copy link
Contributor

@Centril Centril commented Jan 11, 2020

Stabilization report

The following is the stabilization report for #![feature(transparent_enums)].

Tracking issue: #60405
Version target: 1.42 (2020-01-30 => beta, 2020-03-12 => stable).

User guide

A struct with only a single non-ZST field (let's call it foo) can be marked as #[repr(transparent)]. Such a struct has the same layout and ABI as foo. Here, we also extend this ability to enums with only one variant, subject to the same restrictions as for the equivalent struct. That is, you can now write:

#[repr(transparent)]
enum Foo { Bar(u8) }

which, in terms of layout and ABI, is equivalent to:

#[repr(transparent)]
struct Foo(u8);

Motivation

This is not a major feature that will unlock new and important use-cases. The utility of repr(transparent) enums is indeed limited. However, there is still some value in it:

  1. It provides conceptual simplification of the language in terms of treating univariant enums and structs the same, as both are product types. Indeed, languages like Haskell only have data as the only way to construct user-defined ADTs in the language.

  2. In rare occasions, it might be that the user started out with a univariant enum for whatever reason (e.g. they thought they might extend it later). Now they want to make this enum transparent without breaking users by turning it into a struct. By lifting the restriction here, now they can.

Technical specification

The reference specifies repr(transparent) on a struct as:

The transparent Representation

The transparent representation can only be used on structs that have:

  • a single field with non-zero size, and
  • any number of fields with size 0 and alignment 1 (e.g. PhantomData<T>).

Structs with this representation have the same layout and ABI as the single non-zero sized field.

This is different than the C representation because a struct with the C representation will always have the ABI of a C struct while, for example, a struct with the transparent representation with a primitive field will have the ABI of the primitive field.

Because this representation delegates type layout to another type, it cannot be used with any other representation.

Here, we amend this to include univariant enums as well with the same static restrictions and the same effects on dynamic semantics.

Tests

All the relevant tests are adjusted in the PR diff but are recounted here:

  • src/test/ui/repr/repr-transparent.rs checks that repr(transparent) on an enum must be univariant, rather than having zero or more than one variant. Restrictions on the fields inside the only variants, like for those on structs, are also checked here.

  • A number of codegen tests are provided as well:

    • src/test/codegen/repr-transparent.rs (the canonical test)
    • src/test/codegen/repr-transparent-aggregates-1.rs
    • src/test/codegen/repr-transparent-aggregates-2.rs
    • src/test/codegen/repr-transparent-aggregates-3.rs
  • src/test/ui/lint/lint-ctypes-enum.rs tests the interactions with the improper_ctypes lint.

History

Related / possible future work

The remaining work here is to figure out the semantics of #[repr(transparent)] on unions and stabilize those. This work continues to be tracked in #60405.

@Centril Centril added T-lang Relevant to the language team, which will review and decide on the PR/issue. relnotes Marks issues that should be documented in the release notes of the next release. labels Jan 11, 2020
@Centril Centril added this to the 1.42 milestone Jan 11, 2020
@rust-highfive
Copy link
Collaborator

r? @petrochenkov

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 11, 2020
@Centril
Copy link
Contributor Author

Centril commented Jan 11, 2020

Stabilization proposal

Dear community & language team,
I propose that we stabilize #![feature(transparent_enums)].

@rfcbot merge

Tracking issue: #60405
Version target: 1.42 (2020-01-30 => beta, 2020-03-12 => stable).

Please see the attached report above for details.

@rfcbot
Copy link

rfcbot commented Jan 11, 2020

Team member @Centril has proposed to merge this. The next step is review by the rest of the tagged team members:

No concerns currently listed.

Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up!

See this document for info about what commands tagged team members can give me.

@rfcbot rfcbot added proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. labels Jan 11, 2020
@petrochenkov
Copy link
Contributor

r=me on the implementation, waiting for FCP

@petrochenkov petrochenkov added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 11, 2020
@hanna-kruppe
Copy link
Contributor

I'm noticing this very late, but it appears we've all forgotten that, just as with transparent structs, there also needs to be an alignment requirement on the ZST fields. It's not even mentioned in the RFC as far as I can tell, and not in the unstable book chapter added in the implementation PR. The only reason it's implemented is code sharing with transparent structs. I assume this doesn't actually influence the decision to stabilize, but:

  • Whoever ends up writing the documentation for this feature, please don't forget about it (cf. repr(transparent): mention align=1 requirement reference#737).
  • There don't seem to be tests for this restriction, please add some. There are tests for the same restriction on transparent structs (in ui/repr/repr-transparent.rs), so I'm not overly worried about the check getting lost in a refactoring, but it's easy to test and apparently people keep forgetting about it, so...

@Centril Centril added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jan 11, 2020
@Centril
Copy link
Contributor Author

Centril commented Jan 12, 2020

  • There don't seem to be tests for this restriction, please add some.

Thanks for noticing; I've extended the test.

@Centril Centril removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jan 12, 2020
@nikomatsakis
Copy link
Contributor

@rfcbot reviewed

@joshtriplett
Copy link
Member

We should document the behavior of combining repr(u32) and similar with repr(transparent). Right now that's an error, which is reasonable. In the future we might want to define that explicitly.

But the current behavior seems reasonable, so:
@rfcbot reviewed

@Centril
Copy link
Contributor Author

Centril commented Jan 16, 2020

Wake up bot :)

@rfcbot reviewed

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Jan 16, 2020
@rfcbot
Copy link

rfcbot commented Jan 16, 2020

🔔 This is now entering its final comment period, as per the review above. 🔔

@bors

This comment has been minimized.

@Centril Centril force-pushed the stabilize-transparent-enums branch from 10a576f to 25460eb Compare January 20, 2020 10:18
@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this PR / Issue. and removed final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. labels Jan 26, 2020
@rfcbot
Copy link

rfcbot commented Jan 26, 2020

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

The RFC will be merged soon.

@Centril
Copy link
Contributor Author

Centril commented Jan 26, 2020

@bors r=petrochenkov p=3

@bors
Copy link
Contributor

bors commented Jan 26, 2020

📌 Commit 25460eb has been approved by petrochenkov

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). labels Jan 26, 2020
@bors
Copy link
Contributor

bors commented Jan 27, 2020

⌛ Testing commit 25460eb with merge c3681d6...

bors added a commit that referenced this pull request Jan 27, 2020
…enkov

Stabilize `#[repr(transparent)]` on `enum`s in Rust 1.42.0

# Stabilization report

The following is the stabilization report for `#![feature(transparent_enums)]`.

Tracking issue: #60405
[Version target](https://forge.rust-lang.org/#current-release-versions): 1.42 (2020-01-30 => beta, 2020-03-12 => stable).

## User guide

A `struct` with only a single non-ZST field (let's call it `foo`) can be marked as `#[repr(transparent)]`. Such a `struct` has the same layout and ABI as `foo`. Here, we also extend this ability to `enum`s with only one variant, subject to the same restrictions as for the equivalent `struct`. That is, you can now write:

```rust
#[repr(transparent)]
enum Foo { Bar(u8) }
```

which, in terms of layout and ABI, is equivalent to:

```rust
#[repr(transparent)]
struct Foo(u8);
```

## Motivation

This is not a major feature that will unlock new and important use-cases. The utility of `repr(transparent)` `enum`s is indeed limited. However, there is still some value in it:

1. It provides conceptual simplification of the language in terms of treating univariant `enum`s and `struct`s the same, as both are product types. Indeed, languages like Haskell only have `data` as the only way to construct user-defined ADTs in the language.

2. In rare occasions, it might be that the user started out with a univariant `enum` for whatever reason (e.g. they thought they might extend it later). Now they want to make this `enum` `transparent` without breaking users by turning it into a `struct`. By lifting the restriction here, now they can.

## Technical specification

The reference specifies [`repr(transparent)` on a `struct`](https://doc.rust-lang.org/nightly/reference/type-layout.html#the-transparent-representation) as:

> ### The transparent Representation
>
>  The `transparent` representation can only be used on `struct`s that have:
>  - a single field with non-zero size, and
>  - any number of fields with size 0 and alignment 1 (e.g. `PhantomData<T>`).
>
> Structs with this representation have the same layout and ABI as the single non-zero sized field.
>
> This is different than the `C` representation because a struct with the `C` representation will always have the ABI of a `C` `struct` while, for example, a struct with the `transparent` representation with a primitive field will have the ABI of the primitive field.
>
> Because this representation delegates type layout to another type, it cannot be used with any other representation.

Here, we amend this to include univariant `enum`s as well with the same static restrictions and the same effects on dynamic semantics.

## Tests

All the relevant tests are adjusted in the PR diff but are recounted here:

- `src/test/ui/repr/repr-transparent.rs` checks that `repr(transparent)` on an `enum` must be univariant, rather than having zero or more than one variant. Restrictions on the fields inside the only variants, like for those on `struct`s, are also checked here.

- A number of codegen tests are provided as well:
    - `src/test/codegen/repr-transparent.rs` (the canonical test)
    - `src/test/codegen/repr-transparent-aggregates-1.rs`
    - `src/test/codegen/repr-transparent-aggregates-2.rs`
    - `src/test/codegen/repr-transparent-aggregates-3.rs`

- `src/test/ui/lint/lint-ctypes-enum.rs` tests the interactions with the `improper_ctypes` lint.

## History

- 2019-04-30, RFC rust-lang/rfcs#2645
  Author: @mjbshaw
  Reviewers: The Language Team

  This is the RFC that proposes allowing `#[repr(transparent)]` on `enum`s and `union`.

- 2019-06-11, PR #60463
  Author: @mjbshaw
  Reviewers: @varkor and @rkruppe

  The PR implements the RFC aforementioned in full.

- 2019, PR #67323
  Author: @Centril
  Reviewers: @davidtwco

  The PR reorganizes the static checks taking advantage of the fact that `struct`s and `union`s are internally represented as ADTs with a single variant.

- This PR stabilizes `transparent_enums`.

## Related / possible future work

The remaining work here is to figure out the semantics of `#[repr(transparent)]` on `union`s and stabilize those. This work continues to be tracked in #60405.
@bors
Copy link
Contributor

bors commented Jan 27, 2020

☀️ Test successful - checks-azure
Approved by: petrochenkov
Pushing c3681d6 to master...

@bors bors added the merged-by-bors This PR was explicitly merged by bors. label Jan 27, 2020
@bors bors merged commit 25460eb into rust-lang:master Jan 27, 2020
@Centril Centril deleted the stabilize-transparent-enums branch January 27, 2020 13:00
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this pull request Mar 13, 2020
Version 1.42.0 (2020-03-12)
==========================

Language
--------
- [You can now use the slice pattern syntax with subslices.][67712] e.g.
  ```rust
  fn foo(words: &[&str]) {
      match words {
          ["Hello", "World", "!", ..] => println!("Hello World!"),
          ["Foo", "Bar", ..] => println!("Baz"),
          rest => println!("{:?}", rest),
      }
  }
  ```
- [You can now use `#[repr(transparent)]` on univariant `enum`s.][68122] Meaning
  that you can create an enum that has the exact layout and ABI of the type
  it contains.
- [There are some *syntax-only* changes:][67131]
   - `default` is syntactically allowed before items in `trait` definitions.
   - Items in `impl`s (i.e. `const`s, `type`s, and `fn`s) may syntactically
     leave out their bodies in favor of `;`.
   - Bounds on associated types in `impl`s are now syntactically allowed
     (e.g. `type Foo: Ord;`).
   - `...` (the C-variadic type) may occur syntactically directly as the type of
      any function parameter.

  These are still rejected *semantically*, so you will likely receive an error
  but these changes can be seen and parsed by procedural macros and
  conditional compilation.

Compiler
--------
- [Added tier 2* support for `armv7a-none-eabi`.][68253]
- [Added tier 2 support for `riscv64gc-unknown-linux-gnu`.][68339]
- [`Option::{expect,unwrap}` and
   `Result::{expect, expect_err, unwrap, unwrap_err}` now produce panic messages
   pointing to the location where they were called, rather than
   `core`'s internals. ][67887]

* Refer to Rust's [platform support page][forge-platform-support] for more
information on Rust's tiered platform support.

Libraries
---------
- [`iter::Empty<T>` now implements `Send` and `Sync` for any `T`.][68348]
- [`Pin::{map_unchecked, map_unchecked_mut}` no longer require the return type
   to implement `Sized`.][67935]
- [`io::Cursor` now derives `PartialEq` and `Eq`.][67233]
- [`Layout::new` is now `const`.][66254]
- [Added Standard Library support for `riscv64gc-unknown-linux-gnu`.][66899]


Stabilized APIs
---------------
- [`CondVar::wait_while`]
- [`CondVar::wait_timeout_while`]
- [`DebugMap::key`]
- [`DebugMap::value`]
- [`ManuallyDrop::take`]
- [`matches!`]
- [`ptr::slice_from_raw_parts_mut`]
- [`ptr::slice_from_raw_parts`]

Cargo
-----
- [You no longer need to include `extern crate proc_macro;` to be able to
  `use proc_macro;` in the `2018` edition.][cargo/7700]

Compatibility Notes
-------------------
- [`Error::description` has been deprecated, and its use will now produce a
  warning.][66919] It's recommended to use `Display`/`to_string` instead.
- [`use $crate;` inside macros is now a hard error.][37390] The compiler
  emitted forward compatibility warnings since Rust 1.14.0.
- [As previously announced, this release reduces the level of support for
  32-bit Apple targets to tier 3.][apple-32bit-drop]. This means that the
  source code is still available to build, but the targets are no longer tested
  and no release binary is distributed by the Rust project. Please refer to the
  linked blog post for more information.

[37390]: rust-lang/rust#37390
[68253]: rust-lang/rust#68253
[68348]: rust-lang/rust#68348
[67935]: rust-lang/rust#67935
[68339]: rust-lang/rust#68339
[68122]: rust-lang/rust#68122
[67712]: rust-lang/rust#67712
[67887]: rust-lang/rust#67887
[67131]: rust-lang/rust#67131
[67233]: rust-lang/rust#67233
[66899]: rust-lang/rust#66899
[66919]: rust-lang/rust#66919
[66254]: rust-lang/rust#66254
[cargo/7700]: rust-lang/cargo#7700
[`DebugMap::key`]: https://doc.rust-lang.org/stable/std/fmt/struct.DebugMap.html#method.key
[`DebugMap::value`]: https://doc.rust-lang.org/stable/std/fmt/struct.DebugMap.html#method.value
[`ManuallyDrop::take`]: https://doc.rust-lang.org/stable/std/mem/struct.ManuallyDrop.html#method.take
[`matches!`]: https://doc.rust-lang.org/stable/std/macro.matches.html
[`ptr::slice_from_raw_parts_mut`]: https://doc.rust-lang.org/stable/std/ptr/fn.slice_from_raw_parts_mut.html
[`ptr::slice_from_raw_parts`]: https://doc.rust-lang.org/stable/std/ptr/fn.slice_from_raw_parts.html
[`CondVar::wait_while`]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html#method.wait_while
[`CondVar::wait_timeout_while`]: https://doc.rust-lang.org/stable/std/sync/struct.Condvar.html#method.wait_timeout_while
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This issue / PR is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this PR / Issue. merged-by-bors This PR was explicitly merged by bors. relnotes Marks issues that should be documented in the release notes of the next release. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants