Skip to content

Commit

Permalink
Auto merge of #68122 - Centril:stabilize-transparent-enums, r=petroch…
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
bors committed Jan 27, 2020
2 parents a237641 + 25460eb commit c3681d6
Show file tree
Hide file tree
Showing 13 changed files with 33 additions and 133 deletions.
93 changes: 0 additions & 93 deletions src/doc/unstable-book/src/language-features/transparent-enums.md

This file was deleted.

2 changes: 2 additions & 0 deletions src/librustc_feature/accepted.rs
Expand Up @@ -257,6 +257,8 @@ declare_features! (
/// Allows relaxing the coherence rules such that
/// `impl<T> ForeignTrait<LocalType> for ForeignType<T>` is permitted.
(accepted, re_rebalance_coherence, "1.41.0", Some(55437), None),
/// Allows #[repr(transparent)] on univariant enums (RFC 2645).
(accepted, transparent_enums, "1.42.0", Some(60405), None),
/// Allows using subslice patterns, `[a, .., b]` and `[a, xs @ .., b]`.
(accepted, slice_patterns, "1.42.0", Some(62254), None),

Expand Down
3 changes: 0 additions & 3 deletions src/librustc_feature/active.rs
Expand Up @@ -468,9 +468,6 @@ declare_features! (
/// Allows `if/while p && let q = r && ...` chains.
(active, let_chains, "1.37.0", Some(53667), None),

/// Allows #[repr(transparent)] on enums (RFC 2645).
(active, transparent_enums, "1.37.0", Some(60405), None),

/// Allows #[repr(transparent)] on unions (RFC 2645).
(active, transparent_unions, "1.37.0", Some(60405), None),

Expand Down
10 changes: 0 additions & 10 deletions src/librustc_typeck/check/mod.rs
Expand Up @@ -2434,16 +2434,6 @@ fn check_transparent(tcx: TyCtxt<'_>, sp: Span, def_id: DefId) {
}
let sp = tcx.sess.source_map().def_span(sp);

if adt.is_enum() && !tcx.features().transparent_enums {
feature_err(
&tcx.sess.parse_sess,
sym::transparent_enums,
sp,
"transparent enums are unstable",
)
.emit();
}

if adt.is_union() && !tcx.features().transparent_unions {
feature_err(
&tcx.sess.parse_sess,
Expand Down
2 changes: 1 addition & 1 deletion src/test/codegen/repr-transparent-aggregates-1.rs
Expand Up @@ -10,7 +10,7 @@
// ignore-windows
// See repr-transparent.rs

#![feature(transparent_enums, transparent_unions)]
#![feature(transparent_unions)]

#![crate_type="lib"]

Expand Down
2 changes: 1 addition & 1 deletion src/test/codegen/repr-transparent-aggregates-2.rs
Expand Up @@ -13,7 +13,7 @@
// ignore-x86_64
// See repr-transparent.rs

#![feature(transparent_enums, transparent_unions)]
#![feature(transparent_unions)]

#![crate_type="lib"]

Expand Down
2 changes: 1 addition & 1 deletion src/test/codegen/repr-transparent-aggregates-3.rs
Expand Up @@ -3,7 +3,7 @@
// only-mips64
// See repr-transparent.rs

#![feature(transparent_enums, transparent_unions)]
#![feature(transparent_unions)]

#![crate_type="lib"]

Expand Down
2 changes: 1 addition & 1 deletion src/test/codegen/repr-transparent.rs
@@ -1,7 +1,7 @@
// compile-flags: -C no-prepopulate-passes

#![crate_type="lib"]
#![feature(repr_simd, transparent_enums, transparent_unions)]
#![feature(repr_simd, transparent_unions)]

use std::marker::PhantomData;

Expand Down
6 changes: 0 additions & 6 deletions src/test/ui/feature-gates/feature-gate-transparent_enums.rs

This file was deleted.

12 changes: 0 additions & 12 deletions src/test/ui/feature-gates/feature-gate-transparent_enums.stderr

This file was deleted.

2 changes: 1 addition & 1 deletion src/test/ui/lint/lint-ctypes-enum.rs
@@ -1,4 +1,4 @@
#![feature(transparent_enums, transparent_unions)]
#![feature(transparent_unions)]
#![feature(ptr_internals)]
#![deny(improper_ctypes)]
#![allow(dead_code)]
Expand Down
12 changes: 11 additions & 1 deletion src/test/ui/repr/repr-transparent.rs
Expand Up @@ -3,7 +3,7 @@
// - repr-transparent-other-reprs.rs
// - repr-transparent-other-items.rs

#![feature(repr_align, transparent_enums, transparent_unions)]
#![feature(transparent_unions)]

use std::marker::PhantomData;

Expand Down Expand Up @@ -60,6 +60,16 @@ enum TooManyVariants { //~ ERROR transparent enum needs exactly one variant, but
Bar,
}

#[repr(transparent)]
enum NontrivialAlignZstEnum {
Foo(u32, [u16; 0]), //~ ERROR alignment larger than 1
}

#[repr(transparent)]
enum GenericAlignEnum<T> {
Foo { bar: ZstAlign32<T>, baz: u32 } //~ ERROR alignment larger than 1
}

#[repr(transparent)]
union UnitUnion { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 0
u: (),
Expand Down
18 changes: 15 additions & 3 deletions src/test/ui/repr/repr-transparent.stderr
Expand Up @@ -94,14 +94,26 @@ LL | Foo(String),
LL | Bar,
| --- too many variants in `TooManyVariants`

error[E0691]: zero-sized field in transparent enum has alignment larger than 1
--> $DIR/repr-transparent.rs:65:14
|
LL | Foo(u32, [u16; 0]),
| ^^^^^^^^ has alignment larger than 1

error[E0691]: zero-sized field in transparent enum has alignment larger than 1
--> $DIR/repr-transparent.rs:70:11
|
LL | Foo { bar: ZstAlign32<T>, baz: u32 }
| ^^^^^^^^^^^^^^^^^^ has alignment larger than 1

error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0
--> $DIR/repr-transparent.rs:64:1
--> $DIR/repr-transparent.rs:74:1
|
LL | union UnitUnion {
| ^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 0

error[E0690]: transparent union needs exactly one non-zero-sized field, but has 2
--> $DIR/repr-transparent.rs:69:1
--> $DIR/repr-transparent.rs:79:1
|
LL | union TooManyFields {
| ^^^^^^^^^^^^^^^^^^^ needs exactly one non-zero-sized field, but has 2
Expand All @@ -110,7 +122,7 @@ LL | u: u32,
LL | s: i32
| ------ this field is non-zero-sized

error: aborting due to 15 previous errors
error: aborting due to 17 previous errors

Some errors have detailed explanations: E0084, E0690, E0691, E0731.
For more information about an error, try `rustc --explain E0084`.

0 comments on commit c3681d6

Please sign in to comment.