about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-06-11 11:06:38 +0000
committerbors <bors@rust-lang.org>2019-06-11 11:06:38 +0000
commit8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be (patch)
treecaf2cb5f0b7881b6056c37c37c2e73e46b520aab /src
parent912d22e36965d3c9f6d7f14ca18657182aa1fe54 (diff)
parentdac1c6a731713ec9e90a1e05b3e2c789faf3f2ba (diff)
downloadrust-8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be.tar.gz
rust-8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be.zip
Auto merge of #60463 - mjbshaw:transparent, r=varkor,rkruppe
Implement RFC 2645 (transparent enums and unions)

Tracking issue: #60405
Diffstat (limited to 'src')
-rw-r--r--src/doc/unstable-book/src/language-features/transparent-enums.md93
-rw-r--r--src/doc/unstable-book/src/language-features/transparent-unions.md83
-rw-r--r--src/librustc/hir/check_attr.rs22
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc_lint/types.rs34
-rw-r--r--src/librustc_typeck/check/mod.rs60
-rw-r--r--src/librustc_typeck/error_codes.rs37
-rw-r--r--src/libsyntax/feature_gate.rs6
-rw-r--r--src/libsyntax_pos/symbol.rs2
-rw-r--r--src/test/codegen/repr-transparent-aggregates-1.rs59
-rw-r--r--src/test/codegen/repr-transparent-aggregates-2.rs58
-rw-r--r--src/test/codegen/repr-transparent-aggregates-3.rs58
-rw-r--r--src/test/codegen/repr-transparent.rs43
-rw-r--r--src/test/run-pass/structs-enums/enum-null-pointer-opt.rs12
-rw-r--r--src/test/ui/attr-usage-repr.rs2
-rw-r--r--src/test/ui/attr-usage-repr.stderr4
-rw-r--r--src/test/ui/error-codes/E0517.stderr8
-rw-r--r--src/test/ui/feature-gates/feature-gate-transparent_enums.rs6
-rw-r--r--src/test/ui/feature-gates/feature-gate-transparent_enums.stderr14
-rw-r--r--src/test/ui/feature-gates/feature-gate-transparent_unions.rs7
-rw-r--r--src/test/ui/feature-gates/feature-gate-transparent_unions.stderr15
-rw-r--r--src/test/ui/issues/issue-14309.stderr10
-rw-r--r--src/test/ui/issues/issue-16250.stderr2
-rw-r--r--src/test/ui/issues/issue-31769.rs2
-rw-r--r--src/test/ui/issues/issue-31769.stderr4
-rw-r--r--src/test/ui/issues/issue-43988.stderr8
-rw-r--r--src/test/ui/lint/lint-ctypes-enum.rs18
-rw-r--r--src/test/ui/lint/lint-ctypes-enum.stderr42
-rw-r--r--src/test/ui/lint/lint-ctypes.stderr10
-rw-r--r--src/test/ui/repr/repr-transparent-other-items.rs21
-rw-r--r--src/test/ui/repr/repr-transparent-other-items.stderr64
-rw-r--r--src/test/ui/repr/repr-transparent.rs34
-rw-r--r--src/test/ui/repr/repr-transparent.stderr96
-rw-r--r--src/test/ui/union/union-repr-c.stderr2
34 files changed, 730 insertions, 208 deletions
diff --git a/src/doc/unstable-book/src/language-features/transparent-enums.md b/src/doc/unstable-book/src/language-features/transparent-enums.md
new file mode 100644
index 00000000000..862411ab392
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/transparent-enums.md
@@ -0,0 +1,93 @@
+# `transparent_enums`
+
+The tracking issue for this feature is [#60405]
+
+[60405]: https://github.com/rust-lang/rust/issues/60405
+
+----
+
+The `transparent_enums` feature allows you mark `enum`s as
+`#[repr(transparent)]`. An `enum` may be `#[repr(transparent)]` if it has
+exactly one variant, and that variant matches the same conditions which `struct`
+requires for transparency. Some concrete illustrations follow.
+
+```rust
+#![feature(transparent_enums)]
+
+// This enum has the same representation as `f32`.
+#[repr(transparent)]
+enum SingleFieldEnum {
+    Variant(f32)
+}
+
+// This enum has the same representation as `usize`.
+#[repr(transparent)]
+enum MultiFieldEnum {
+    Variant { field: usize, nothing: () },
+}
+```
+
+For consistency with transparent `struct`s, `enum`s must have exactly one
+non-zero-sized field. If all fields are zero-sized, the `enum` must not be
+`#[repr(transparent)]`:
+
+```rust
+#![feature(transparent_enums)]
+
+// This (non-transparent) enum is already valid in stable Rust:
+pub enum GoodEnum {
+    Nothing,
+}
+
+// Error: transparent enum needs exactly one non-zero-sized field, but has 0
+// #[repr(transparent)]
+// pub enum BadEnum {
+//     Nothing(()),
+// }
+
+// Error: transparent enum needs exactly one non-zero-sized field, but has 0
+// #[repr(transparent)]
+// pub enum BadEmptyEnum {
+//     Nothing,
+// }
+```
+
+The one exception is if the `enum` is generic over `T` and has a field of type
+`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type:
+
+```rust
+#![feature(transparent_enums)]
+
+// This enum has the same representation as `T`.
+#[repr(transparent)]
+pub enum GenericEnum<T> {
+    Variant(T, ()),
+}
+
+// This is okay even though `()` is a zero-sized type.
+pub const THIS_IS_OKAY: GenericEnum<()> = GenericEnum::Variant((), ());
+```
+
+Transparent `enum`s require exactly one variant:
+
+```rust
+// Error: transparent enum needs exactly one variant, but has 0
+// #[repr(transparent)]
+// pub enum TooFewVariants {
+// }
+
+// Error: transparent enum needs exactly one variant, but has 2
+// #[repr(transparent)]
+// pub enum TooManyVariants {
+//     First(usize),
+//     Second,
+// }
+```
+
+Like transarent `struct`s, a transparent `enum` of type `E` has the same layout,
+size, and ABI as its single non-ZST field. If it is generic over a type `T`, and
+all its fields are ZSTs except for exactly one field of type `T`, then it has
+the same layout and ABI as `T` (even if `T` is a ZST when monomorphized).
+
+Like transparent `struct`s, transparent `enum`s are FFI-safe if and only if
+their underlying representation type is also FFI-safe.
diff --git a/src/doc/unstable-book/src/language-features/transparent-unions.md b/src/doc/unstable-book/src/language-features/transparent-unions.md
new file mode 100644
index 00000000000..b731c9ea6d0
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/transparent-unions.md
@@ -0,0 +1,83 @@
+# `transparent_unions`
+
+The tracking issue for this feature is [#60405]
+
+[60405]: https://github.com/rust-lang/rust/issues/60405
+
+----
+
+The `transparent_unions` feature allows you mark `union`s as
+`#[repr(transparent)]`. A `union` may be `#[repr(transparent)]` in exactly the
+same conditions in which a `struct` may be `#[repr(transparent)]` (generally,
+this means the `union` must have exactly one non-zero-sized field). Some
+concrete illustrations follow.
+
+```rust
+#![feature(transparent_unions)]
+
+// This union has the same representation as `f32`.
+#[repr(transparent)]
+union SingleFieldUnion {
+    field: f32,
+}
+
+// This union has the same representation as `usize`.
+#[repr(transparent)]
+union MultiFieldUnion {
+    field: usize,
+    nothing: (),
+}
+```
+
+For consistency with transparent `struct`s, `union`s must have exactly one
+non-zero-sized field. If all fields are zero-sized, the `union` must not be
+`#[repr(transparent)]`:
+
+```rust
+#![feature(transparent_unions)]
+
+// This (non-transparent) union is already valid in stable Rust:
+pub union GoodUnion {
+    pub nothing: (),
+}
+
+// Error: transparent union needs exactly one non-zero-sized field, but has 0
+// #[repr(transparent)]
+// pub union BadUnion {
+//     pub nothing: (),
+// }
+```
+
+The one exception is if the `union` is generic over `T` and has a field of type
+`T`, it may be `#[repr(transparent)]` even if `T` is a zero-sized type:
+
+```rust
+#![feature(transparent_unions)]
+
+// This union has the same representation as `T`.
+#[repr(transparent)]
+pub union GenericUnion<T: Copy> { // Unions with non-`Copy` fields are unstable.
+    pub field: T,
+    pub nothing: (),
+}
+
+// This is okay even though `()` is a zero-sized type.
+pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () };
+```
+
+Like transarent `struct`s, a transparent `union` of type `U` has the same
+layout, size, and ABI as its single non-ZST field. If it is generic over a type
+`T`, and all its fields are ZSTs except for exactly one field of type `T`, then
+it has the same layout and ABI as `T` (even if `T` is a ZST when monomorphized).
+
+Like transparent `struct`s, transparent `union`s are FFI-safe if and only if
+their underlying representation type is also FFI-safe.
+
+A `union` may not be eligible for the same nonnull-style optimizations that a
+`struct` or `enum` (with the same fields) are eligible for. Adding
+`#[repr(transparent)]` to  `union` does not change this. To give a more concrete
+example, it is unspecified whether `size_of::<T>()` is equal to
+`size_of::<Option<T>>()`, where `T` is a `union` (regardless of whether or not
+it is transparent). The Rust compiler is free to perform this optimization if
+possible, but is not required to, and different compiler versions may differ in
+their application of these optimizations.
diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs
index b199eee6dad..f7d1094b3a2 100644
--- a/src/librustc/hir/check_attr.rs
+++ b/src/librustc/hir/check_attr.rs
@@ -181,12 +181,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
             let (article, allowed_targets) = match hint.name_or_empty() {
                 name @ sym::C | name @ sym::align => {
                     is_c |= name == sym::C;
-                    if target != Target::Struct &&
-                            target != Target::Union &&
-                            target != Target::Enum {
-                                ("a", "struct, enum or union")
-                    } else {
-                        continue
+                    match target {
+                        Target::Struct | Target::Union | Target::Enum => continue,
+                        _ => ("a", "struct, enum, or union"),
                     }
                 }
                 sym::packed => {
@@ -207,10 +204,9 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                 }
                 sym::transparent => {
                     is_transparent = true;
-                    if target != Target::Struct {
-                        ("a", "struct")
-                    } else {
-                        continue
+                    match target {
+                        Target::Struct | Target::Union | Target::Enum => continue,
+                        _ => ("a", "struct, enum, or union"),
                     }
                 }
                 sym::i8  | sym::u8  | sym::i16 | sym::u16 |
@@ -241,7 +237,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
         if is_transparent && hints.len() > 1 {
             let hint_spans: Vec<_> = hint_spans.clone().collect();
             span_err!(self.tcx.sess, hint_spans, E0692,
-                      "transparent struct cannot have other repr hints");
+                      "transparent {} cannot have other repr hints", target);
         }
         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
         if (int_reprs > 1)
@@ -277,7 +273,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                         attr.span,
                         stmt.span,
                         "attribute should not be applied to a statement",
-                        "not a struct, enum or union",
+                        "not a struct, enum, or union",
                     );
                 }
             }
@@ -298,7 +294,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> {
                     attr.span,
                     expr.span,
                     "attribute should not be applied to an expression",
-                    "not defining a struct, enum or union",
+                    "not defining a struct, enum, or union",
                 );
             }
         }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 69bf05c66f3..80781dd9bc7 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2303,7 +2303,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     /// Returns an iterator over all fields contained
     /// by this ADT.
     #[inline]
-    pub fn all_fields<'s>(&'s self) -> impl Iterator<Item = &'s FieldDef> {
+    pub fn all_fields<'s>(&'s self) -> impl Iterator<Item = &'s FieldDef> + Clone {
         self.variants.iter().flat_map(|v| v.fields.iter())
     }
 
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index ac18e131c4a..f89a772bef5 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -531,8 +531,8 @@ fn ty_is_known_nonnull<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> b
     match ty.sty {
         ty::FnPtr(_) => true,
         ty::Ref(..) => true,
-        ty::Adt(field_def, substs) if field_def.repr.transparent() && field_def.is_struct() => {
-            for field in &field_def.non_enum_variant().fields {
+        ty::Adt(field_def, substs) if field_def.repr.transparent() && !field_def.is_union() => {
+            for field in field_def.all_fields() {
                 let field_ty = tcx.normalize_erasing_regions(
                     ParamEnv::reveal_all(),
                     field.ty(tcx, substs),
@@ -627,8 +627,8 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                             return FfiUnsafe {
                                 ty: ty,
                                 reason: "this struct has unspecified layout",
-                                help: Some("consider adding a #[repr(C)] or #[repr(transparent)] \
-                                            attribute to this struct"),
+                                help: Some("consider adding a `#[repr(C)]` or \
+                                            `#[repr(transparent)]` attribute to this struct"),
                             };
                         }
 
@@ -668,11 +668,12 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         if all_phantom { FfiPhantom(ty) } else { FfiSafe }
                     }
                     AdtKind::Union => {
-                        if !def.repr.c() {
+                        if !def.repr.c() && !def.repr.transparent() {
                             return FfiUnsafe {
                                 ty: ty,
                                 reason: "this union has unspecified layout",
-                                help: Some("consider adding a #[repr(C)] attribute to this union"),
+                                help: Some("consider adding a `#[repr(C)]` or \
+                                            `#[repr(transparent)]` attribute to this union"),
                             };
                         }
 
@@ -690,6 +691,11 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                                 ParamEnv::reveal_all(),
                                 field.ty(cx, substs),
                             );
+                            // repr(transparent) types are allowed to have arbitrary ZSTs, not just
+                            // PhantomData -- skip checking all ZST fields.
+                            if def.repr.transparent() && is_zst(cx, field.did, field_ty) {
+                                continue;
+                            }
                             let r = self.check_type_for_ffi(cache, field_ty);
                             match r {
                                 FfiSafe => {
@@ -712,14 +718,15 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
 
                         // Check for a repr() attribute to specify the size of the
                         // discriminant.
-                        if !def.repr.c() && def.repr.int.is_none() {
+                        if !def.repr.c() && !def.repr.transparent() && def.repr.int.is_none() {
                             // Special-case types like `Option<extern fn()>`.
                             if !is_repr_nullable_ptr(cx, ty, def, substs) {
                                 return FfiUnsafe {
                                     ty: ty,
                                     reason: "enum has no representation hint",
-                                    help: Some("consider adding a #[repr(...)] attribute \
-                                                to this enum"),
+                                    help: Some("consider adding a `#[repr(C)]`, \
+                                                `#[repr(transparent)]`, or integer `#[repr(...)]` \
+                                                attribute to this enum"),
                                 };
                             }
                         }
@@ -727,11 +734,16 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                         // Check the contained variants.
                         for variant in &def.variants {
                             for field in &variant.fields {
-                                let arg = cx.normalize_erasing_regions(
+                                let field_ty = cx.normalize_erasing_regions(
                                     ParamEnv::reveal_all(),
                                     field.ty(cx, substs),
                                 );
-                                let r = self.check_type_for_ffi(cache, arg);
+                                // repr(transparent) types are allowed to have arbitrary ZSTs, not
+                                // just PhantomData -- skip checking all ZST fields.
+                                if def.repr.transparent() && is_zst(cx, field.did, field_ty) {
+                                    continue;
+                                }
+                                let r = self.check_type_for_ffi(cache, field_ty);
                                 match r {
                                     FfiSafe => {}
                                     FfiUnsafe { .. } => {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 0b558a20ed4..2e53b380cb7 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1310,7 +1310,7 @@ fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let def = tcx.adt_def(def_id);
     def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
-
+    check_transparent(tcx, span, def_id);
     check_packed(tcx, span, def_id);
 }
 
@@ -1807,8 +1807,43 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
         return;
     }
 
+    if adt.is_enum() {
+        if !tcx.features().transparent_enums {
+            emit_feature_err(&tcx.sess.parse_sess,
+                             sym::transparent_enums,
+                             sp,
+                             GateIssue::Language,
+                             "transparent enums are unstable");
+        }
+        if adt.variants.len() != 1 {
+            let variant_spans: Vec<_> = adt.variants.iter().map(|variant| {
+                tcx.hir().span_if_local(variant.def_id).unwrap()
+            }).collect();
+            let mut err = struct_span_err!(tcx.sess, sp, E0731,
+                            "transparent enum needs exactly one variant, but has {}",
+                            adt.variants.len());
+            if !variant_spans.is_empty() {
+                err.span_note(variant_spans, &format!("the following variants exist on `{}`",
+                                                      tcx.def_path_str(def_id)));
+            }
+            err.emit();
+            if adt.variants.is_empty() {
+                // Don't bother checking the fields. No variants (and thus no fields) exist.
+                return;
+            }
+        }
+    }
+
+    if adt.is_union() && !tcx.features().transparent_unions {
+        emit_feature_err(&tcx.sess.parse_sess,
+                         sym::transparent_unions,
+                         sp,
+                         GateIssue::Language,
+                         "transparent unions are unstable");
+    }
+
     // For each field, figure out if it's known to be a ZST and align(1)
-    let field_infos = adt.non_enum_variant().fields.iter().map(|field| {
+    let field_infos = adt.all_fields().map(|field| {
         let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
         let param_env = tcx.param_env(field.did);
         let layout = tcx.layout_of(param_env.and(ty));
@@ -1823,16 +1858,24 @@ fn check_transparent<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: De
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count != 1 {
         let field_spans: Vec<_> = non_zst_fields.map(|(span, _zst, _align1)| span).collect();
-        struct_span_err!(tcx.sess, sp, E0690,
-                         "transparent struct needs exactly one non-zero-sized field, but has {}",
-                         non_zst_count)
-        .span_note(field_spans, "non-zero-sized field")
-        .emit();
+
+        let mut err = struct_span_err!(tcx.sess, sp, E0690,
+                         "{}transparent {} needs exactly one non-zero-sized field, but has {}",
+                         if adt.is_enum() { "the variant of a " } else { "" },
+                         adt.descr(),
+                         non_zst_count);
+        if !field_spans.is_empty() {
+            err.span_note(field_spans,
+                          &format!("the following non-zero-sized fields exist on `{}`:",
+                                   tcx.def_path_str(def_id)));
+        }
+        err.emit();
     }
     for (span, zst, align1) in field_infos {
         if zst && !align1 {
             span_err!(tcx.sess, span, E0691,
-                      "zero-sized field in transparent struct has alignment larger than 1");
+                      "zero-sized field in transparent {} has alignment larger than 1",
+                      adt.descr());
         }
     }
 }
@@ -1899,6 +1942,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     check_representable(tcx, sp, def_id);
+    check_transparent(tcx, sp, def_id);
 }
 
 fn report_unexpected_variant_res<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
diff --git a/src/librustc_typeck/error_codes.rs b/src/librustc_typeck/error_codes.rs
index 66e9a6e6b2a..0b618cdf1db 100644
--- a/src/librustc_typeck/error_codes.rs
+++ b/src/librustc_typeck/error_codes.rs
@@ -4484,7 +4484,7 @@ let _ = (2.0 as f32).neg();
 
 E0690: r##"
 A struct with the representation hint `repr(transparent)` had zero or more than
-on fields that were not guaranteed to be zero-sized.
+one fields that were not guaranteed to be zero-sized.
 
 Erroneous code example:
 
@@ -4519,8 +4519,8 @@ struct LengthWithUnit<U> {
 "##,
 
 E0691: r##"
-A struct with the `repr(transparent)` representation hint contains a zero-sized
-field that requires non-trivial alignment.
+A struct, enum, or union with the `repr(transparent)` representation hint
+contains a zero-sized field that requires non-trivial alignment.
 
 Erroneous code example:
 
@@ -4535,11 +4535,11 @@ struct Wrapper(f32, ForceAlign32); // error: zero-sized field in transparent
                                    //        struct has alignment larger than 1
 ```
 
-A transparent struct is supposed to be represented exactly like the piece of
-data it contains. Zero-sized fields with different alignment requirements
-potentially conflict with this property. In the example above, `Wrapper` would
-have to be aligned to 32 bytes even though `f32` has a smaller alignment
-requirement.
+A transparent struct, enum, or union is supposed to be represented exactly like
+the piece of data it contains. Zero-sized fields with different alignment
+requirements potentially conflict with this property. In the example above,
+`Wrapper` would have to be aligned to 32 bytes even though `f32` has a smaller
+alignment requirement.
 
 Consider removing the over-aligned zero-sized field:
 
@@ -4569,7 +4569,6 @@ the alignment of the zero-sized type is less than or equal to the data field's
 alignment.
 "##,
 
-
 E0699: r##"
 A method was called on a raw pointer whose inner type wasn't completely known.
 
@@ -4680,6 +4679,26 @@ match r {
 ```
 "##,
 
+E0731: r##"
+An enum with the representation hint `repr(transparent)` had zero or more than
+one variants.
+
+Erroneous code example:
+
+```compile_fail,E0731
+#[repr(transparent)]
+enum Status { // error: transparent enum needs exactly one variant, but has 2
+    Errno(u32),
+    Ok,
+}
+```
+
+Because transparent enums are represented exactly like one of their variants at
+run time, said variant must be uniquely determined. If there is no variant, or
+if there are multiple variants, it is not clear how the enum should be
+represented.
+"##,
+
 }
 
 register_diagnostics! {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index bbb297e3c4f..044c4b18905 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -561,6 +561,12 @@ declare_features! (
     // FIXME Create issue
     (active, const_constructor, "1.37.0", Some(61456), None),
 
+    // #[repr(transparent)] on enums.
+    (active, transparent_enums, "1.37.0", Some(60405), None),
+
+    // #[repr(transparent)] on unions.
+    (active, transparent_unions, "1.37.0", Some(60405), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 302b3c75263..875c286bd8a 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -623,6 +623,8 @@ symbols! {
         trait_alias,
         transmute,
         transparent,
+        transparent_enums,
+        transparent_unions,
         trivial_bounds,
         Try,
         try_blocks,
diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs
index fb88f2a69ca..e7c4b6193bc 100644
--- a/src/test/codegen/repr-transparent-aggregates-1.rs
+++ b/src/test/codegen/repr-transparent-aggregates-1.rs
@@ -1,4 +1,5 @@
 // compile-flags: -C no-prepopulate-passes
+// ignore-tidy-linelength
 
 // ignore-arm
 // ignore-mips
@@ -7,36 +8,76 @@
 // ignore-powerpc64
 // See repr-transparent.rs
 
+#![feature(transparent_enums, transparent_unions)]
+
 #![crate_type="lib"]
 
 
+#[derive(Clone, Copy)]
 #[repr(C)]
-pub struct Big([u32; 16]);
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
 
 #[repr(transparent)]
-pub struct BigW(Big);
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], %BigS* [[BIGS_ARG_ATTRS:.*]])
+#[no_mangle]
+pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], %TsBigS* [[BIGS_ARG_ATTRS]])
+#[no_mangle]
+pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
 
-// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], %Big* [[BIG_ARG_ATTRS:.*]])
+// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], %TuBigS* [[BIGS_ARG_ATTRS]])
 #[no_mangle]
-pub extern fn test_Big(_: Big) -> Big { loop {} }
+pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
 
-// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], %BigW* [[BIG_ARG_ATTRS]])
+// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], %"TeBigS::Variant"* [[BIGS_ARG_ATTRS]])
 #[no_mangle]
-pub extern fn test_BigW(_: BigW) -> BigW { loop {} }
+pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
 
 
+#[derive(Clone, Copy)]
 #[repr(C)]
 pub union BigU {
     foo: [u32; 16],
 }
 
 #[repr(transparent)]
-pub struct BigUw(BigU);
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
 
 // CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], %BigU* [[BIGU_ARG_ATTRS:.*]])
 #[no_mangle]
 pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
 
-// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], %BigUw* [[BIGU_ARG_ATTRS]])
+// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], %TsBigU* [[BIGU_ARG_ATTRS]])
+#[no_mangle]
+pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], %TuBigU* [[BIGU_ARG_ATTRS]])
+#[no_mangle]
+pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], %"TeBigU::Variant"* [[BIGU_ARG_ATTRS]])
 #[no_mangle]
-pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} }
+pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/src/test/codegen/repr-transparent-aggregates-2.rs b/src/test/codegen/repr-transparent-aggregates-2.rs
index 6c628ac035f..5521c3c849f 100644
--- a/src/test/codegen/repr-transparent-aggregates-2.rs
+++ b/src/test/codegen/repr-transparent-aggregates-2.rs
@@ -14,36 +14,76 @@
 // ignore-x86_64
 // See repr-transparent.rs
 
+#![feature(transparent_enums, transparent_unions)]
+
 #![crate_type="lib"]
 
 
+#[derive(Clone, Copy)]
 #[repr(C)]
-pub struct Big([u32; 16]);
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
 
 #[repr(transparent)]
-pub struct BigW(Big);
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
 
-// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], [16 x i32]
+// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], [16 x i32]
 #[no_mangle]
-pub extern fn test_Big(_: Big) -> Big { loop {} }
+pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
 
-// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], [16 x i32]
+// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], [16 x i32]
 #[no_mangle]
-pub extern fn test_BigW(_: BigW) -> BigW { loop {} }
+pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
 
 
+#[derive(Clone, Copy)]
 #[repr(C)]
 pub union BigU {
     foo: [u32; 16],
 }
 
 #[repr(transparent)]
-pub struct BigUw(BigU);
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
 
 // CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], [16 x i32]
 #[no_mangle]
 pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
 
-// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], [16 x i32]
+// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], [16 x i32]
+#[no_mangle]
+pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], [16 x i32]
 #[no_mangle]
-pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} }
+pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/src/test/codegen/repr-transparent-aggregates-3.rs b/src/test/codegen/repr-transparent-aggregates-3.rs
index cd740dc9b82..1a59c9b48b9 100644
--- a/src/test/codegen/repr-transparent-aggregates-3.rs
+++ b/src/test/codegen/repr-transparent-aggregates-3.rs
@@ -3,36 +3,76 @@
 // only-mips64
 // See repr-transparent.rs
 
+#![feature(transparent_enums, transparent_unions)]
+
 #![crate_type="lib"]
 
 
+#[derive(Clone, Copy)]
 #[repr(C)]
-pub struct Big([u32; 16]);
+pub struct BigS([u32; 16]);
+
+#[repr(transparent)]
+pub struct TsBigS(BigS);
+
+#[repr(transparent)]
+pub union TuBigS {
+    field: BigS,
+}
 
 #[repr(transparent)]
-pub struct BigW(Big);
+pub enum TeBigS {
+    Variant(BigS),
+}
+
+// CHECK: define void @test_BigS(%BigS* [[BIGS_RET_ATTRS:.*]], [8 x i64]
+#[no_mangle]
+pub extern fn test_BigS(_: BigS) -> BigS { loop {} }
+
+// CHECK: define void @test_TsBigS(%TsBigS* [[BIGS_RET_ATTRS]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TsBigS(_: TsBigS) -> TsBigS { loop {} }
 
-// CHECK: define void @test_Big(%Big* [[BIG_RET_ATTRS:.*]], [8 x i64]
+// CHECK: define void @test_TuBigS(%TuBigS* [[BIGS_RET_ATTRS]], [8 x i64]
 #[no_mangle]
-pub extern fn test_Big(_: Big) -> Big { loop {} }
+pub extern fn test_TuBigS(_: TuBigS) -> TuBigS { loop {} }
 
-// CHECK: define void @test_BigW(%BigW* [[BIG_RET_ATTRS]], [8 x i64]
+// CHECK: define void @test_TeBigS(%"TeBigS::Variant"* [[BIGS_RET_ATTRS]], [8 x i64]
 #[no_mangle]
-pub extern fn test_BigW(_: BigW) -> BigW { loop {} }
+pub extern fn test_TeBigS(_: TeBigS) -> TeBigS { loop {} }
 
 
+#[derive(Clone, Copy)]
 #[repr(C)]
 pub union BigU {
     foo: [u32; 16],
 }
 
 #[repr(transparent)]
-pub struct BigUw(BigU);
+pub struct TsBigU(BigU);
+
+#[repr(transparent)]
+pub union TuBigU {
+    field: BigU,
+}
+
+#[repr(transparent)]
+pub enum TeBigU {
+    Variant(BigU),
+}
 
 // CHECK: define void @test_BigU(%BigU* [[BIGU_RET_ATTRS:.*]], [8 x i64]
 #[no_mangle]
 pub extern fn test_BigU(_: BigU) -> BigU { loop {} }
 
-// CHECK: define void @test_BigUw(%BigUw* [[BIGU_RET_ATTRS]], [8 x i64]
+// CHECK: define void @test_TsBigU(%TsBigU* [[BIGU_RET_ATTRS:.*]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TsBigU(_: TsBigU) -> TsBigU { loop {} }
+
+// CHECK: define void @test_TuBigU(%TuBigU* [[BIGU_RET_ATTRS]], [8 x i64]
+#[no_mangle]
+pub extern fn test_TuBigU(_: TuBigU) -> TuBigU { loop {} }
+
+// CHECK: define void @test_TeBigU(%"TeBigU::Variant"* [[BIGU_RET_ATTRS]], [8 x i64]
 #[no_mangle]
-pub extern fn test_BigUw(_: BigUw) -> BigUw { loop {} }
+pub extern fn test_TeBigU(_: TeBigU) -> TeBigU { loop {} }
diff --git a/src/test/codegen/repr-transparent.rs b/src/test/codegen/repr-transparent.rs
index fd655261ab8..c9f38375658 100644
--- a/src/test/codegen/repr-transparent.rs
+++ b/src/test/codegen/repr-transparent.rs
@@ -1,13 +1,16 @@
 // compile-flags: -C no-prepopulate-passes
 
 #![crate_type="lib"]
-#![feature(repr_simd)]
+#![feature(repr_simd, transparent_enums, transparent_unions)]
 
 use std::marker::PhantomData;
 
+#[derive(Copy, Clone)]
 pub struct Zst1;
+#[derive(Copy, Clone)]
 pub struct Zst2(());
 
+#[derive(Copy, Clone)]
 #[repr(transparent)]
 pub struct F32(f32);
 
@@ -112,6 +115,44 @@ pub struct StructWithProjection(<f32 as Mirror>::It);
 #[no_mangle]
 pub extern fn test_Projection(_: StructWithProjection) -> StructWithProjection { loop {} }
 
+#[repr(transparent)]
+pub enum EnumF32 {
+    Variant(F32)
+}
+
+// CHECK: define float @test_EnumF32(float %arg0)
+#[no_mangle]
+pub extern fn test_EnumF32(_: EnumF32) -> EnumF32 { loop {} }
+
+#[repr(transparent)]
+pub enum EnumF32WithZsts {
+    Variant(Zst1, F32, Zst2)
+}
+
+// CHECK: define float @test_EnumF32WithZsts(float %arg0)
+#[no_mangle]
+pub extern fn test_EnumF32WithZsts(_: EnumF32WithZsts) -> EnumF32WithZsts { loop {} }
+
+#[repr(transparent)]
+pub union UnionF32 {
+    field: F32,
+}
+
+// CHECK: define float @test_UnionF32(float %arg0)
+#[no_mangle]
+pub extern fn test_UnionF32(_: UnionF32) -> UnionF32 { loop {} }
+
+#[repr(transparent)]
+pub union UnionF32WithZsts {
+    zst1: Zst1,
+    field: F32,
+    zst2: Zst2,
+}
+
+// CHECK: define float @test_UnionF32WithZsts(float %arg0)
+#[no_mangle]
+pub extern fn test_UnionF32WithZsts(_: UnionF32WithZsts) -> UnionF32WithZsts { loop {} }
+
 
 // All that remains to be tested are aggregates. They are tested in separate files called repr-
 // transparent-*.rs  with `only-*` or `ignore-*` directives, because the expected LLVM IR
diff --git a/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs b/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs
index 87629665bc2..f871c218558 100644
--- a/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs
+++ b/src/test/run-pass/structs-enums/enum-null-pointer-opt.rs
@@ -1,4 +1,6 @@
 // run-pass
+#![feature(transparent_unions)]
+
 use std::mem::size_of;
 use std::num::NonZeroUsize;
 use std::ptr::NonNull;
@@ -10,6 +12,11 @@ trait Mirror { type Image; }
 impl<T> Mirror for T { type Image = T; }
 struct ParamTypeStruct<T>(T);
 struct AssocTypeStruct<T>(<T as Mirror>::Image);
+#[repr(transparent)]
+union MaybeUninitUnion<T: Copy> {
+    _value: T,
+    _uninit: (),
+}
 
 fn main() {
     // Functions
@@ -29,9 +36,12 @@ fn main() {
     // Pointers - Box<T>
     assert_eq!(size_of::<Box<isize>>(), size_of::<Option<Box<isize>>>());
 
-    // The optimization can't apply to raw pointers
+    // The optimization can't apply to raw pointers or unions with a ZST field.
     assert!(size_of::<Option<*const isize>>() != size_of::<*const isize>());
     assert!(Some(0 as *const isize).is_some()); // Can't collapse None to null
+    assert_ne!(size_of::<fn(isize)>(), size_of::<Option<MaybeUninitUnion<fn(isize)>>>());
+    assert_ne!(size_of::<&str>(), size_of::<Option<MaybeUninitUnion<&str>>>());
+    assert_ne!(size_of::<NonNull<isize>>(), size_of::<Option<MaybeUninitUnion<NonNull<isize>>>>());
 
     struct Foo {
         _a: Box<isize>
diff --git a/src/test/ui/attr-usage-repr.rs b/src/test/ui/attr-usage-repr.rs
index ef64dfe20bc..a0b82375e77 100644
--- a/src/test/ui/attr-usage-repr.rs
+++ b/src/test/ui/attr-usage-repr.rs
@@ -1,6 +1,6 @@
 #![feature(repr_simd)]
 
-#[repr(C)] //~ ERROR: attribute should be applied to struct, enum or union
+#[repr(C)] //~ ERROR: attribute should be applied to struct, enum, or union
 fn f() {}
 
 #[repr(C)]
diff --git a/src/test/ui/attr-usage-repr.stderr b/src/test/ui/attr-usage-repr.stderr
index d1f4f3bfeb2..82d80d8d0b1 100644
--- a/src/test/ui/attr-usage-repr.stderr
+++ b/src/test/ui/attr-usage-repr.stderr
@@ -1,10 +1,10 @@
-error[E0517]: attribute should be applied to struct, enum or union
+error[E0517]: attribute should be applied to struct, enum, or union
   --> $DIR/attr-usage-repr.rs:3:8
    |
 LL | #[repr(C)]
    |        ^
 LL | fn f() {}
-   | --------- not a struct, enum or union
+   | --------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to enum
   --> $DIR/attr-usage-repr.rs:15:8
diff --git a/src/test/ui/error-codes/E0517.stderr b/src/test/ui/error-codes/E0517.stderr
index e256c07de26..2cfca1724c8 100644
--- a/src/test/ui/error-codes/E0517.stderr
+++ b/src/test/ui/error-codes/E0517.stderr
@@ -1,10 +1,10 @@
-error[E0517]: attribute should be applied to struct, enum or union
+error[E0517]: attribute should be applied to struct, enum, or union
   --> $DIR/E0517.rs:1:8
    |
 LL | #[repr(C)]
    |        ^
 LL | type Foo = u8;
-   | -------------- not a struct, enum or union
+   | -------------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to struct or union
   --> $DIR/E0517.rs:4:8
@@ -22,14 +22,14 @@ LL | #[repr(u8)]
 LL | struct Foo3 {bar: bool, baz: bool}
    | ---------------------------------- not an enum
 
-error[E0517]: attribute should be applied to struct, enum or union
+error[E0517]: attribute should be applied to struct, enum, or union
   --> $DIR/E0517.rs:10:8
    |
 LL |   #[repr(C)]
    |          ^
 LL | / impl Foo3 {
 LL | | }
-   | |_- not a struct, enum or union
+   | |_- not a struct, enum, or union
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/feature-gates/feature-gate-transparent_enums.rs b/src/test/ui/feature-gates/feature-gate-transparent_enums.rs
new file mode 100644
index 00000000000..0a7a73a168e
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-transparent_enums.rs
@@ -0,0 +1,6 @@
+#[repr(transparent)]
+enum OkButUnstableEnum { //~ ERROR transparent enums are unstable
+    Foo((), String, ()),
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr
new file mode 100644
index 00000000000..4b22654e9e4
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-transparent_enums.stderr
@@ -0,0 +1,14 @@
+error[E0658]: transparent enums are unstable
+  --> $DIR/feature-gate-transparent_enums.rs:2:1
+   |
+LL | / enum OkButUnstableEnum {
+LL | |     Foo((), String, ()),
+LL | | }
+   | |_^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/60405
+   = help: add #![feature(transparent_enums)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-transparent_unions.rs b/src/test/ui/feature-gates/feature-gate-transparent_unions.rs
new file mode 100644
index 00000000000..73cac0a4914
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-transparent_unions.rs
@@ -0,0 +1,7 @@
+#[repr(transparent)]
+union OkButUnstableUnion { //~ ERROR transparent unions are unstable
+    field: u8,
+    zst: (),
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr
new file mode 100644
index 00000000000..933b227de63
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-transparent_unions.stderr
@@ -0,0 +1,15 @@
+error[E0658]: transparent unions are unstable
+  --> $DIR/feature-gate-transparent_unions.rs:2:1
+   |
+LL | / union OkButUnstableUnion {
+LL | |     field: u8,
+LL | |     zst: (),
+LL | | }
+   | |_^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/60405
+   = help: add #![feature(transparent_unions)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/issues/issue-14309.stderr b/src/test/ui/issues/issue-14309.stderr
index 4376876ecd6..e0491093a72 100644
--- a/src/test/ui/issues/issue-14309.stderr
+++ b/src/test/ui/issues/issue-14309.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -24,7 +24,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe
 LL |     fn bar(x: B);
    |               ^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -39,7 +39,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe
 LL |     fn qux(x: A2);
    |               ^^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -54,7 +54,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe
 LL |     fn quux(x: B2);
    |                ^^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
@@ -69,7 +69,7 @@ error: `extern` block uses type `A` which is not FFI-safe: this struct has unspe
 LL |     fn fred(x: D);
    |                ^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/issue-14309.rs:4:1
    |
diff --git a/src/test/ui/issues/issue-16250.stderr b/src/test/ui/issues/issue-16250.stderr
index a8ff2548b73..142d8e21532 100644
--- a/src/test/ui/issues/issue-16250.stderr
+++ b/src/test/ui/issues/issue-16250.stderr
@@ -10,7 +10,7 @@ note: lint level defined here
 LL | #![deny(warnings)]
    |         ^^^^^^^^
    = note: #[deny(improper_ctypes)] implied by #[deny(warnings)]
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/issue-16250.rs:3:1
    |
diff --git a/src/test/ui/issues/issue-31769.rs b/src/test/ui/issues/issue-31769.rs
index 794c1d19893..45eb5e40080 100644
--- a/src/test/ui/issues/issue-31769.rs
+++ b/src/test/ui/issues/issue-31769.rs
@@ -1,4 +1,4 @@
 fn main() {
     #[inline] struct Foo;  //~ ERROR attribute should be applied to function or closure
-    #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum or union
+    #[repr(C)] fn foo() {} //~ ERROR attribute should be applied to struct, enum, or union
 }
diff --git a/src/test/ui/issues/issue-31769.stderr b/src/test/ui/issues/issue-31769.stderr
index 51d1f51d1c9..20534e1ae82 100644
--- a/src/test/ui/issues/issue-31769.stderr
+++ b/src/test/ui/issues/issue-31769.stderr
@@ -4,11 +4,11 @@ error[E0518]: attribute should be applied to function or closure
 LL |     #[inline] struct Foo;
    |     ^^^^^^^^^ ----------- not a function or closure
 
-error[E0517]: attribute should be applied to struct, enum or union
+error[E0517]: attribute should be applied to struct, enum, or union
   --> $DIR/issue-31769.rs:3:12
    |
 LL |     #[repr(C)] fn foo() {}
-   |            ^   ----------- not a struct, enum or union
+   |            ^   ----------- not a struct, enum, or union
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-43988.stderr b/src/test/ui/issues/issue-43988.stderr
index c2f0cc6f0ff..339c1a3b8f6 100644
--- a/src/test/ui/issues/issue-43988.stderr
+++ b/src/test/ui/issues/issue-43988.stderr
@@ -32,7 +32,7 @@ error[E0517]: attribute should not be applied to a statement
 LL |     #[repr(nothing)]
    |     ^^^^^^^^^^^^^^^^
 LL |     let _x = 0;
-   |     ----------- not a struct, enum or union
+   |     ----------- not a struct, enum, or union
 
 error[E0517]: attribute should not be applied to an expression
   --> $DIR/issue-43988.rs:18:5
@@ -42,7 +42,7 @@ LL |       #[repr(something_not_real)]
 LL | /     loop {
 LL | |         ()
 LL | |     };
-   | |_____- not defining a struct, enum or union
+   | |_____- not defining a struct, enum, or union
 
 error[E0517]: attribute should not be applied to a statement
   --> $DIR/issue-43988.rs:24:5
@@ -50,7 +50,7 @@ error[E0517]: attribute should not be applied to a statement
 LL |     #[repr]
    |     ^^^^^^^
 LL |     let _y = "123";
-   |     --------------- not a struct, enum or union
+   |     --------------- not a struct, enum, or union
 
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43988.rs:31:5
@@ -64,7 +64,7 @@ error[E0517]: attribute should not be applied to an expression
   --> $DIR/issue-43988.rs:35:14
    |
 LL |     let _z = #[repr] 1;
-   |              ^^^^^^^ - not defining a struct, enum or union
+   |              ^^^^^^^ - not defining a struct, enum, or union
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs
index d3e11d2f7ed..45eeffff7a6 100644
--- a/src/test/ui/lint/lint-ctypes-enum.rs
+++ b/src/test/ui/lint/lint-ctypes-enum.rs
@@ -1,3 +1,4 @@
+#![feature(transparent_enums, transparent_unions)]
 #![deny(improper_ctypes)]
 #![allow(dead_code)]
 
@@ -18,7 +19,17 @@ enum U8 { A, B, C }
 enum Isize { A, B, C }
 
 #[repr(transparent)]
-struct Transparent<T>(T, std::marker::PhantomData<Z>);
+struct TransparentStruct<T>(T, std::marker::PhantomData<Z>);
+
+#[repr(transparent)]
+enum TransparentEnum<T> {
+   Variant(T, std::marker::PhantomData<Z>),
+}
+
+#[repr(transparent)]
+union TransparentUnion<T: Copy> {
+   field: T,
+}
 
 struct Rust<T>(T);
 
@@ -47,7 +58,10 @@ extern {
    fn nonzero_i128(x: Option<num::NonZeroI128>);
    //~^ ERROR 128-bit integers don't currently have a known stable ABI
    fn nonzero_isize(x: Option<num::NonZeroIsize>);
-   fn repr_transparent(x: Option<Transparent<num::NonZeroU8>>);
+   fn transparent_struct(x: Option<TransparentStruct<num::NonZeroU8>>);
+   fn transparent_enum(x: Option<TransparentEnum<num::NonZeroU8>>);
+   fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>);
+   //~^ ERROR enum has no representation hint
    fn repr_rust(x: Option<Rust<num::NonZeroU8>>); //~ ERROR enum has no representation hint
    fn no_result(x: Result<(), num::NonZeroI32>); //~ ERROR enum has no representation hint
 }
diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr
index 6b807f48aaa..2a60cd12d99 100644
--- a/src/test/ui/lint/lint-ctypes-enum.stderr
+++ b/src/test/ui/lint/lint-ctypes-enum.stderr
@@ -1,74 +1,82 @@
 error: `extern` block uses type `U` which is not FFI-safe: enum has no representation hint
-  --> $DIR/lint-ctypes-enum.rs:27:13
+  --> $DIR/lint-ctypes-enum.rs:38:13
    |
 LL |    fn uf(x: U);
    |             ^
    |
 note: lint level defined here
-  --> $DIR/lint-ctypes-enum.rs:1:9
+  --> $DIR/lint-ctypes-enum.rs:2:9
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
-   = help: consider adding a #[repr(...)] attribute to this enum
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 note: type defined here
-  --> $DIR/lint-ctypes-enum.rs:7:1
+  --> $DIR/lint-ctypes-enum.rs:8:1
    |
 LL | enum U { A }
    | ^^^^^^^^^^^^
 
 error: `extern` block uses type `B` which is not FFI-safe: enum has no representation hint
-  --> $DIR/lint-ctypes-enum.rs:28:13
+  --> $DIR/lint-ctypes-enum.rs:39:13
    |
 LL |    fn bf(x: B);
    |             ^
    |
-   = help: consider adding a #[repr(...)] attribute to this enum
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 note: type defined here
-  --> $DIR/lint-ctypes-enum.rs:8:1
+  --> $DIR/lint-ctypes-enum.rs:9:1
    |
 LL | enum B { C, D }
    | ^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `T` which is not FFI-safe: enum has no representation hint
-  --> $DIR/lint-ctypes-enum.rs:29:13
+  --> $DIR/lint-ctypes-enum.rs:40:13
    |
 LL |    fn tf(x: T);
    |             ^
    |
-   = help: consider adding a #[repr(...)] attribute to this enum
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 note: type defined here
-  --> $DIR/lint-ctypes-enum.rs:9:1
+  --> $DIR/lint-ctypes-enum.rs:10:1
    |
 LL | enum T { E, F, G }
    | ^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `u128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
-  --> $DIR/lint-ctypes-enum.rs:40:23
+  --> $DIR/lint-ctypes-enum.rs:51:23
    |
 LL |    fn nonzero_u128(x: Option<num::NonZeroU128>);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
-  --> $DIR/lint-ctypes-enum.rs:47:23
+  --> $DIR/lint-ctypes-enum.rs:58:23
    |
 LL |    fn nonzero_i128(x: Option<num::NonZeroI128>);
    |                       ^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: `extern` block uses type `std::option::Option<TransparentUnion<std::num::NonZeroU8>>` which is not FFI-safe: enum has no representation hint
+  --> $DIR/lint-ctypes-enum.rs:63:28
+   |
+LL |    fn transparent_union(x: Option<TransparentUnion<num::NonZeroU8>>);
+   |                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+
 error: `extern` block uses type `std::option::Option<Rust<std::num::NonZeroU8>>` which is not FFI-safe: enum has no representation hint
-  --> $DIR/lint-ctypes-enum.rs:51:20
+  --> $DIR/lint-ctypes-enum.rs:65:20
    |
 LL |    fn repr_rust(x: Option<Rust<num::NonZeroU8>>);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider adding a #[repr(...)] attribute to this enum
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 
 error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>` which is not FFI-safe: enum has no representation hint
-  --> $DIR/lint-ctypes-enum.rs:52:20
+  --> $DIR/lint-ctypes-enum.rs:66:20
    |
 LL |    fn no_result(x: Result<(), num::NonZeroI32>);
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: consider adding a #[repr(...)] attribute to this enum
+   = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
 
-error: aborting due to 7 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr
index 03c18e4530b..c78463beb65 100644
--- a/src/test/ui/lint/lint-ctypes.stderr
+++ b/src/test/ui/lint/lint-ctypes.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/lint-ctypes.rs:24:1
    |
@@ -22,7 +22,7 @@ error: `extern` block uses type `Foo` which is not FFI-safe: this struct has uns
 LL |     pub fn ptr_type2(size: *const Foo);
    |                            ^^^^^^^^^^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 note: type defined here
   --> $DIR/lint-ctypes.rs:24:1
    |
@@ -51,7 +51,7 @@ error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: th
 LL |     pub fn box_type(p: Box<u32>);
    |                        ^^^^^^^^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 
 error: `extern` block uses type `char` which is not FFI-safe: the `char` type has no C equivalent
   --> $DIR/lint-ctypes.rs:51:25
@@ -142,7 +142,7 @@ error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: th
 LL |     pub fn fn_contained(p: RustBadRet);
    |                            ^^^^^^^^^^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 
 error: `extern` block uses type `i128` which is not FFI-safe: 128-bit integers don't currently have a known stable ABI
   --> $DIR/lint-ctypes.rs:64:32
@@ -164,7 +164,7 @@ error: `extern` block uses type `std::boxed::Box<u32>` which is not FFI-safe: th
 LL |     pub fn transparent_fn(p: TransparentBadFn);
    |                              ^^^^^^^^^^^^^^^^
    |
-   = help: consider adding a #[repr(C)] or #[repr(transparent)] attribute to this struct
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
 
 error: aborting due to 20 previous errors
 
diff --git a/src/test/ui/repr/repr-transparent-other-items.rs b/src/test/ui/repr/repr-transparent-other-items.rs
index 392e7c9de4d..c3d772f6266 100644
--- a/src/test/ui/repr/repr-transparent-other-items.rs
+++ b/src/test/ui/repr/repr-transparent-other-items.rs
@@ -1,26 +1,5 @@
 // See also repr-transparent.rs
 
-#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
-enum Void {}         //~| ERROR should be applied to struct
-
-#[repr(transparent)] //~ ERROR should be applied to struct
-enum FieldlessEnum {
-    Foo,
-    Bar,
-}
-
-#[repr(transparent)] //~ ERROR should be applied to struct
-enum Enum {
-    Foo(String),
-    Bar(u32),
-}
-
-#[repr(transparent)] //~ ERROR should be applied to struct
-union Foo {
-    u: u32,
-    s: i32
-}
-
 #[repr(transparent)] //~ ERROR should be applied to struct
 fn cant_repr_this() {}
 
diff --git a/src/test/ui/repr/repr-transparent-other-items.stderr b/src/test/ui/repr/repr-transparent-other-items.stderr
index 24fa309a2fb..03df3569b42 100644
--- a/src/test/ui/repr/repr-transparent-other-items.stderr
+++ b/src/test/ui/repr/repr-transparent-other-items.stderr
@@ -1,69 +1,19 @@
-error[E0517]: attribute should be applied to struct
+error[E0517]: attribute should be applied to struct, enum, or union
   --> $DIR/repr-transparent-other-items.rs:3:8
    |
 LL | #[repr(transparent)]
    |        ^^^^^^^^^^^
-LL | enum Void {}
-   | ------------ not a struct
-
-error[E0517]: attribute should be applied to struct
-  --> $DIR/repr-transparent-other-items.rs:6:8
-   |
-LL |   #[repr(transparent)]
-   |          ^^^^^^^^^^^
-LL | / enum FieldlessEnum {
-LL | |     Foo,
-LL | |     Bar,
-LL | | }
-   | |_- not a struct
-
-error[E0517]: attribute should be applied to struct
-  --> $DIR/repr-transparent-other-items.rs:12:8
-   |
-LL |   #[repr(transparent)]
-   |          ^^^^^^^^^^^
-LL | / enum Enum {
-LL | |     Foo(String),
-LL | |     Bar(u32),
-LL | | }
-   | |_- not a struct
-
-error[E0517]: attribute should be applied to struct
-  --> $DIR/repr-transparent-other-items.rs:18:8
-   |
-LL |   #[repr(transparent)]
-   |          ^^^^^^^^^^^
-LL | / union Foo {
-LL | |     u: u32,
-LL | |     s: i32
-LL | | }
-   | |_- not a struct
-
-error[E0517]: attribute should be applied to struct
-  --> $DIR/repr-transparent-other-items.rs:24:8
-   |
-LL | #[repr(transparent)]
-   |        ^^^^^^^^^^^
 LL | fn cant_repr_this() {}
-   | ---------------------- not a struct
+   | ---------------------- not a struct, enum, or union
 
-error[E0517]: attribute should be applied to struct
-  --> $DIR/repr-transparent-other-items.rs:27:8
+error[E0517]: attribute should be applied to struct, enum, or union
+  --> $DIR/repr-transparent-other-items.rs:6:8
    |
 LL | #[repr(transparent)]
    |        ^^^^^^^^^^^
 LL | static CANT_REPR_THIS: u32 = 0;
-   | ------------------------------- not a struct
-
-error[E0084]: unsupported representation for zero-variant enum
-  --> $DIR/repr-transparent-other-items.rs:3:1
-   |
-LL | #[repr(transparent)]
-   | ^^^^^^^^^^^^^^^^^^^^
-LL | enum Void {}
-   | ------------ zero-variant enum
+   | ------------------------------- not a struct, enum, or union
 
-error: aborting due to 7 previous errors
+error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0084, E0517.
-For more information about an error, try `rustc --explain E0084`.
+For more information about this error, try `rustc --explain E0517`.
diff --git a/src/test/ui/repr/repr-transparent.rs b/src/test/ui/repr/repr-transparent.rs
index 66d39ff9bb5..730d428ff50 100644
--- a/src/test/ui/repr/repr-transparent.rs
+++ b/src/test/ui/repr/repr-transparent.rs
@@ -3,7 +3,7 @@
 // - repr-transparent-other-reprs.rs
 // - repr-transparent-other-items.rs
 
-#![feature(repr_align)]
+#![feature(repr_align, transparent_enums, transparent_unions)]
 
 use std::marker::PhantomData;
 
@@ -39,4 +39,36 @@ struct ZstAlign32<T>(PhantomData<T>);
 #[repr(transparent)]
 struct GenericAlign<T>(ZstAlign32<T>, u32); //~ ERROR alignment larger than 1
 
+#[repr(transparent)] //~ ERROR unsupported representation for zero-variant enum
+enum Void {}
+//~^ ERROR transparent enum needs exactly one variant, but has 0
+
+#[repr(transparent)]
+enum FieldlessEnum { //~ ERROR transparent enum needs exactly one non-zero-sized field, but has 0
+    Foo,
+}
+
+#[repr(transparent)]
+enum TooManyFieldsEnum {
+    Foo(u32, String),
+}
+//~^^^ ERROR transparent enum needs exactly one non-zero-sized field, but has 2
+
+#[repr(transparent)]
+enum TooManyVariants { //~ ERROR transparent enum needs exactly one variant, but has 2
+    Foo(String),
+    Bar,
+}
+
+#[repr(transparent)]
+union UnitUnion { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 0
+    u: (),
+}
+
+#[repr(transparent)]
+union TooManyFields { //~ ERROR transparent union needs exactly one non-zero-sized field, but has 2
+    u: u32,
+    s: i32
+}
+
 fn main() {}
diff --git a/src/test/ui/repr/repr-transparent.stderr b/src/test/ui/repr/repr-transparent.stderr
index 2542a842fe8..ea16bdf5378 100644
--- a/src/test/ui/repr/repr-transparent.stderr
+++ b/src/test/ui/repr/repr-transparent.stderr
@@ -3,32 +3,24 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has
    |
 LL | struct NoFields;
    | ^^^^^^^^^^^^^^^^
-   |
-   = note: non-zero-sized field
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:14:1
    |
 LL | struct ContainsOnlyZst(());
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: non-zero-sized field
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:17:1
    |
 LL | struct ContainsOnlyZstArray([bool; 0]);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: non-zero-sized field
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 0
   --> $DIR/repr-transparent.rs:20:1
    |
 LL | struct ContainsMultipleZst(PhantomData<*const i32>, NoFields);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: non-zero-sized field
 
 error[E0690]: transparent struct needs exactly one non-zero-sized field, but has 2
   --> $DIR/repr-transparent.rs:24:1
@@ -36,7 +28,7 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has
 LL | struct MultipleNonZst(u8, u8);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: non-zero-sized field
+note: the following non-zero-sized fields exist on `MultipleNonZst`:
   --> $DIR/repr-transparent.rs:24:23
    |
 LL | struct MultipleNonZst(u8, u8);
@@ -48,7 +40,7 @@ error[E0690]: transparent struct needs exactly one non-zero-sized field, but has
 LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-note: non-zero-sized field
+note: the following non-zero-sized fields exist on `StructWithProjection`:
   --> $DIR/repr-transparent.rs:30:33
    |
 LL | pub struct StructWithProjection(f32, <f32 as Mirror>::It);
@@ -66,7 +58,85 @@ error[E0691]: zero-sized field in transparent struct has alignment larger than 1
 LL | struct GenericAlign<T>(ZstAlign32<T>, u32);
    |                        ^^^^^^^^^^^^^
 
-error: aborting due to 8 previous errors
+error[E0084]: unsupported representation for zero-variant enum
+  --> $DIR/repr-transparent.rs:42:1
+   |
+LL | #[repr(transparent)]
+   | ^^^^^^^^^^^^^^^^^^^^
+LL | enum Void {}
+   | ------------ zero-variant enum
+
+error[E0731]: transparent enum needs exactly one variant, but has 0
+  --> $DIR/repr-transparent.rs:43:1
+   |
+LL | enum Void {}
+   | ^^^^^^^^^^^^
+
+error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 0
+  --> $DIR/repr-transparent.rs:47:1
+   |
+LL | / enum FieldlessEnum {
+LL | |     Foo,
+LL | | }
+   | |_^
+
+error[E0690]: the variant of a transparent enum needs exactly one non-zero-sized field, but has 2
+  --> $DIR/repr-transparent.rs:52:1
+   |
+LL | / enum TooManyFieldsEnum {
+LL | |     Foo(u32, String),
+LL | | }
+   | |_^
+   |
+note: the following non-zero-sized fields exist on `TooManyFieldsEnum`:
+  --> $DIR/repr-transparent.rs:53:9
+   |
+LL |     Foo(u32, String),
+   |         ^^^  ^^^^^^
+
+error[E0731]: transparent enum needs exactly one variant, but has 2
+  --> $DIR/repr-transparent.rs:58:1
+   |
+LL | / enum TooManyVariants {
+LL | |     Foo(String),
+LL | |     Bar,
+LL | | }
+   | |_^
+   |
+note: the following variants exist on `TooManyVariants`
+  --> $DIR/repr-transparent.rs:59:5
+   |
+LL |     Foo(String),
+   |     ^^^^^^^^^^^
+LL |     Bar,
+   |     ^^^
+
+error[E0690]: transparent union needs exactly one non-zero-sized field, but has 0
+  --> $DIR/repr-transparent.rs:64:1
+   |
+LL | / union UnitUnion {
+LL | |     u: (),
+LL | | }
+   | |_^
+
+error[E0690]: transparent union needs exactly one non-zero-sized field, but has 2
+  --> $DIR/repr-transparent.rs:69:1
+   |
+LL | / union TooManyFields {
+LL | |     u: u32,
+LL | |     s: i32
+LL | | }
+   | |_^
+   |
+note: the following non-zero-sized fields exist on `TooManyFields`:
+  --> $DIR/repr-transparent.rs:70:5
+   |
+LL |     u: u32,
+   |     ^^^^^^
+LL |     s: i32
+   |     ^^^^^^
+
+error: aborting due to 15 previous errors
 
-Some errors have detailed explanations: E0690, E0691.
-For more information about an error, try `rustc --explain E0690`.
+Some errors have detailed explanations: E0084, E0690, E0691, E0731.
+For more information about an error, try `rustc --explain E0084`.
diff --git a/src/test/ui/union/union-repr-c.stderr b/src/test/ui/union/union-repr-c.stderr
index 40d9a50f1fa..c60817a849a 100644
--- a/src/test/ui/union/union-repr-c.stderr
+++ b/src/test/ui/union/union-repr-c.stderr
@@ -9,7 +9,7 @@ note: lint level defined here
    |
 LL | #![deny(improper_ctypes)]
    |         ^^^^^^^^^^^^^^^
-   = help: consider adding a #[repr(C)] attribute to this union
+   = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
 note: type defined here
   --> $DIR/union-repr-c.rs:9:1
    |