diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index ce7c0eb72cd24..6673d75d99df0 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -856,7 +856,6 @@ pub enum ReprAttr {
     ReprSimd,
     ReprTransparent,
     ReprAlign(u32),
-    ReprNoNiche,
 }
 
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
@@ -904,7 +903,6 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     sym::packed => Some(ReprPacked(1)),
                     sym::simd => Some(ReprSimd),
                     sym::transparent => Some(ReprTransparent),
-                    sym::no_niche => Some(ReprNoNiche),
                     sym::align => {
                         let mut err = struct_span_err!(
                             diagnostic,
@@ -943,7 +941,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                         Ok(literal) => acc.push(ReprPacked(literal)),
                         Err(message) => literal_error = Some(message),
                     };
-                } else if matches!(name, sym::C | sym::simd | sym::transparent | sym::no_niche)
+                } else if matches!(name, sym::C | sym::simd | sym::transparent)
                     || int_type_of_word(name).is_some()
                 {
                     recognised = true;
@@ -1001,7 +999,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     } else {
                         if matches!(
                             meta_item.name_or_empty(),
-                            sym::C | sym::simd | sym::transparent | sym::no_niche
+                            sym::C | sym::simd | sym::transparent
                         ) || int_type_of_word(meta_item.name_or_empty()).is_some()
                         {
                             recognised = true;
@@ -1039,7 +1037,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                         .emit();
                     } else if matches!(
                         meta_item.name_or_empty(),
-                        sym::C | sym::simd | sym::transparent | sym::no_niche
+                        sym::C | sym::simd | sym::transparent
                     ) || int_type_of_word(meta_item.name_or_empty()).is_some()
                     {
                         recognised = true;
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 9dfdafcb38e0b..7616e7a63d107 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -217,7 +217,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
         }
 
         if let Some(def) = mplace.layout.ty.ty_adt_def() {
-            if Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type() {
+            if def.is_unsafe_cell() {
                 // We are crossing over an `UnsafeCell`, we can mutate again. This means that
                 // References we encounter inside here are interned as pointing to mutable
                 // allocations.
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 08102585a7b74..2901bfb634a49 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -821,7 +821,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
         // Special check preventing `UnsafeCell` in the inner part of constants
         if let Some(def) = op.layout.ty.ty_adt_def() {
             if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. }))
-                && Some(def.did()) == self.ecx.tcx.lang_items().unsafe_cell_type()
+                && def.is_unsafe_cell()
             {
                 throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
             }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 0aa7b117b89ba..a6f21ccef6d20 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -96,13 +96,13 @@ impl Qualif for HasMutInterior {
     }
 
     fn in_adt_inherently<'tcx>(
-        cx: &ConstCx<'_, 'tcx>,
+        _cx: &ConstCx<'_, 'tcx>,
         adt: AdtDef<'tcx>,
         _: SubstsRef<'tcx>,
     ) -> bool {
         // Exactly one type, `UnsafeCell`, has the `HasMutInterior` qualif inherently.
         // It arises structurally for all other types.
-        Some(adt.did()) == cx.tcx.lang_items().unsafe_cell_type()
+        adt.is_unsafe_cell()
     }
 }
 
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index b54f0ef361a8d..1fc4d09eb0a1b 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -156,9 +156,6 @@ declare_features! (
     (active, intrinsics, "1.0.0", None, None),
     /// Allows using `#[lang = ".."]` attribute for linking items to special compiler logic.
     (active, lang_items, "1.0.0", None, None),
-    /// Allows `#[repr(no_niche)]` (an implementation detail of `rustc`,
-    /// it is not on path for eventual stabilization).
-    (active, no_niche, "1.42.0", None, None),
     /// Allows using `#[omit_gdb_pretty_printer_section]`.
     (active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
     /// Allows using `#[prelude_import]` on glob `use` items.
@@ -528,13 +525,6 @@ declare_features! (
     (incomplete, unsized_locals, "1.30.0", Some(48055), None),
     /// Allows unsized tuple coercion.
     (active, unsized_tuple_coercion, "1.20.0", Some(42877), None),
-    /// Allows `union`s to implement `Drop`. Moreover, `union`s may now include fields
-    /// that don't implement `Copy` as long as they don't have any drop glue.
-    /// This is checked recursively. On encountering type variable where no progress can be made,
-    /// `T: Copy` is used as a substitute for "no drop glue".
-    ///
-    /// NOTE: A limited form of `union U { ... }` was accepted in 1.19.0.
-    (active, untagged_unions, "1.13.0", Some(55149), None),
     /// Allows using the `#[used(linker)]` (or `#[used(compiler)]`) attribute.
     (active, used_with_arg, "1.60.0", Some(93798), None),
     /// Allows `extern "wasm" fn`
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 54626caaf53ea..2ddaf9201098e 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -180,6 +180,9 @@ declare_features! (
     /// Allows using items which are missing stability attributes
     (removed, unmarked_api, "1.0.0", None, None, None),
     (removed, unsafe_no_drop_flag, "1.0.0", None, None, None),
+    /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
+    (removed, untagged_unions, "1.13.0", Some(55149), None,
+     Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")),
     /// Allows `#[unwind(..)]`.
     ///
     /// Permits specifying whether a function should permit unwinding or abort on unwind.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index be4843c7ff153..aca481df2e113 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -703,9 +703,8 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi
                 return true;
             }
 
-            // Types with a `#[repr(no_niche)]` attribute have their niche hidden.
-            // The attribute is used by the UnsafeCell for example (the only use so far).
-            if def.repr().hide_niche() {
+            // `UnsafeCell` has its niche hidden.
+            if def.is_unsafe_cell() {
                 return false;
             }
 
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9fc2249b29019..49155f76800ce 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3132,6 +3132,59 @@ declare_lint! {
     "detects unexpected names and values in `#[cfg]` conditions",
 }
 
+declare_lint! {
+    /// The `repr_transparent_external_private_fields` lint
+    /// detects types marked `#[repr(trasparent)]` that (transitively)
+    /// contain an external ZST type marked `#[non_exhaustive]`
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs external crate)
+    /// #![deny(repr_transparent_external_private_fields)]
+    /// use foo::NonExhaustiveZst;
+    ///
+    /// #[repr(transparent)]
+    /// struct Bar(u32, ([u32; 0], NonExhaustiveZst));
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+    ///  --> src/main.rs:5:28
+    ///   |
+    /// 5 | struct Bar(u32, ([u32; 0], NonExhaustiveZst));
+    ///   |                            ^^^^^^^^^^^^^^^^
+    ///   |
+    /// note: the lint level is defined here
+    ///  --> src/main.rs:1:9
+    ///   |
+    /// 1 | #![deny(repr_transparent_external_private_fields)]
+    ///   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ///   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    ///   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+    ///   = note: this struct contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Previous, Rust accepted fields that contain external private zero-sized types,
+    /// even though it should not be a breaking change to add a non-zero-sized field to
+    /// that private type.
+    ///
+    /// This is a [future-incompatible] lint to transition this
+    /// to a hard error in the future. See [issue #78586] for more details.
+    ///
+    /// [issue #78586]: https://github.com/rust-lang/rust/issues/78586
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+    Warn,
+    "tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>",
+    };
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -3237,6 +3290,7 @@ declare_lint_pass! {
         DEPRECATED_WHERE_CLAUSE_LOCATION,
         TEST_UNSTABLE_LINT,
         FFI_UNWIND_CALLS,
+        REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
     ]
 }
 
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 620f0380d53b7..6a6ed3dc728d9 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -35,7 +35,6 @@ pub enum UnsafetyViolationDetails {
     UseOfMutableStatic,
     UseOfExternStatic,
     DerefOfRawPointer,
-    AssignToDroppingUnionField,
     AccessToUnionField,
     MutationOfLayoutConstrainedField,
     BorrowOfLayoutConstrainedField,
@@ -78,11 +77,6 @@ impl UnsafetyViolationDetails {
                 "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
                  and cause data races: all of these are undefined behavior",
             ),
-            AssignToDroppingUnionField => (
-                "assignment to union field that might need dropping",
-                "the previous content of the field will be dropped, which causes undefined \
-                 behavior if the field was not properly initialized",
-            ),
             AccessToUnionField => (
                 "access to union field",
                 "the field may not be properly initialized: using uninitialized data will cause \
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 4cac767073577..809406aff1878 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -52,6 +52,8 @@ bitflags! {
         /// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
         /// (i.e., this flag is never set unless this ADT is an enum).
         const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
+        /// Indicates whether the type is `UnsafeCell`.
+        const IS_UNSAFE_CELL              = 1 << 9;
     }
 }
 
@@ -247,6 +249,9 @@ impl AdtDefData {
         if Some(did) == tcx.lang_items().manually_drop() {
             flags |= AdtFlags::IS_MANUALLY_DROP;
         }
+        if Some(did) == tcx.lang_items().unsafe_cell_type() {
+            flags |= AdtFlags::IS_UNSAFE_CELL;
+        }
 
         AdtDefData { did, variants, flags, repr }
     }
@@ -333,6 +338,12 @@ impl<'tcx> AdtDef<'tcx> {
         self.flags().contains(AdtFlags::IS_BOX)
     }
 
+    /// Returns `true` if this is UnsafeCell<T>.
+    #[inline]
+    pub fn is_unsafe_cell(self) -> bool {
+        self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
+    }
+
     /// Returns `true` if this is `ManuallyDrop<T>`.
     #[inline]
     pub fn is_manually_drop(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index f87b6e4212d29..1ed41db099ca0 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -542,14 +542,12 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
             debug!("univariant offset: {:?} field: {:#?}", offset, field);
             offsets[i as usize] = offset;
 
-            if !repr.hide_niche() {
-                if let Some(mut niche) = field.largest_niche {
-                    let available = niche.available(dl);
-                    if available > largest_niche_available {
-                        largest_niche_available = available;
-                        niche.offset += offset;
-                        largest_niche = Some(niche);
-                    }
+            if let Some(mut niche) = field.largest_niche {
+                let available = niche.available(dl);
+                if available > largest_niche_available {
+                    largest_niche_available = available;
+                    niche.offset += offset;
+                    largest_niche = Some(niche);
                 }
             }
 
@@ -1078,6 +1076,29 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
                     let mut st = self.univariant_uninterned(ty, &variants[v], &def.repr(), kind)?;
                     st.variants = Variants::Single { index: v };
+
+                    if def.is_unsafe_cell() {
+                        let hide_niches = |scalar: &mut _| match scalar {
+                            Scalar::Initialized { value, valid_range } => {
+                                *valid_range = WrappingRange::full(value.size(dl))
+                            }
+                            // Already doesn't have any niches
+                            Scalar::Union { .. } => {}
+                        };
+                        match &mut st.abi {
+                            Abi::Uninhabited => {}
+                            Abi::Scalar(scalar) => hide_niches(scalar),
+                            Abi::ScalarPair(a, b) => {
+                                hide_niches(a);
+                                hide_niches(b);
+                            }
+                            Abi::Vector { element, count: _ } => hide_niches(element),
+                            Abi::Aggregate { sized: _ } => {}
+                        }
+                        st.largest_niche = None;
+                        return Ok(tcx.intern_layout(st));
+                    }
+
                     let (start, end) = self.tcx.layout_scalar_valid_range(def.did());
                     match st.abi {
                         Abi::Scalar(ref mut scalar) | Abi::ScalarPair(ref mut scalar, _) => {
@@ -1106,11 +1127,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
                             }
 
                             // Update `largest_niche` if we have introduced a larger niche.
-                            let niche = if def.repr().hide_niche() {
-                                None
-                            } else {
-                                Niche::from_scalar(dl, Size::ZERO, *scalar)
-                            };
+                            let niche = Niche::from_scalar(dl, Size::ZERO, *scalar);
                             if let Some(niche) = niche {
                                 match st.largest_niche {
                                     Some(largest_niche) => {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index f15108fb7501a..c2c7b3df844ad 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1720,11 +1720,9 @@ bitflags! {
         const IS_TRANSPARENT     = 1 << 2;
         // Internal only for now. If true, don't reorder fields.
         const IS_LINEAR          = 1 << 3;
-        // If true, don't expose any niche to type's context.
-        const HIDE_NICHE         = 1 << 4;
         // If true, the type's layout can be randomized using
         // the seed stored in `ReprOptions.layout_seed`
-        const RANDOMIZE_LAYOUT   = 1 << 5;
+        const RANDOMIZE_LAYOUT   = 1 << 4;
         // Any of these flags being set prevent field reordering optimisation.
         const IS_UNOPTIMISABLE   = ReprFlags::IS_C.bits
                                  | ReprFlags::IS_SIMD.bits
@@ -1781,7 +1779,6 @@ impl ReprOptions {
                         ReprFlags::empty()
                     }
                     attr::ReprTransparent => ReprFlags::IS_TRANSPARENT,
-                    attr::ReprNoNiche => ReprFlags::HIDE_NICHE,
                     attr::ReprSimd => ReprFlags::IS_SIMD,
                     attr::ReprInt(i) => {
                         size = Some(i);
@@ -1834,11 +1831,6 @@ impl ReprOptions {
         self.flags.contains(ReprFlags::IS_LINEAR)
     }
 
-    #[inline]
-    pub fn hide_niche(&self) -> bool {
-        self.flags.contains(ReprFlags::HIDE_NICHE)
-    }
-
     /// Returns the discriminant type, given these `repr` options.
     /// This must only be called on enums!
     pub fn discr_type(&self) -> attr::IntType {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 8585199faaf5a..54d3b7cdda62c 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -431,16 +431,9 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 let lhs = &self.thir[lhs];
                 if let ty::Adt(adt_def, _) = lhs.ty.kind() && adt_def.is_union() {
                     if let Some((assigned_ty, assignment_span)) = self.assignment_info {
-                        // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
-                        if !(assigned_ty
-                            .ty_adt_def()
-                            .map_or(false, |adt| adt.is_manually_drop())
-                            || assigned_ty
-                                .is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env))
-                        {
-                            self.requires_unsafe(assignment_span, AssignToDroppingUnionField);
-                        } else {
-                            // write to non-drop union field, safe
+                        if assigned_ty.needs_drop(self.tcx, self.tcx.param_env(adt_def.did())) {
+                            // This would be unsafe, but should be outright impossible since we reject such unions.
+                            self.tcx.sess.delay_span_bug(assignment_span, "union fields that need dropping should be impossible");
                         }
                     } else {
                         self.requires_unsafe(expr.span, AccessToUnionField);
@@ -537,7 +530,6 @@ enum UnsafeOpKind {
     UseOfMutableStatic,
     UseOfExternStatic,
     DerefOfRawPointer,
-    AssignToDroppingUnionField,
     AccessToUnionField,
     MutationOfLayoutConstrainedField,
     BorrowOfLayoutConstrainedField,
@@ -555,7 +547,6 @@ impl UnsafeOpKind {
             UseOfMutableStatic => "use of mutable static",
             UseOfExternStatic => "use of extern static",
             DerefOfRawPointer => "dereference of raw pointer",
-            AssignToDroppingUnionField => "assignment to union field that might need dropping",
             AccessToUnionField => "access to union field",
             MutationOfLayoutConstrainedField => "mutation of layout constrained field",
             BorrowOfLayoutConstrainedField => {
@@ -600,11 +591,6 @@ impl UnsafeOpKind {
                 "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \
                  and cause data races: all of these are undefined behavior",
             ),
-            AssignToDroppingUnionField => (
-                Cow::Borrowed(self.simple_description()),
-                "the previous content of the field will be dropped, which causes undefined \
-                 behavior if the field was not properly initialized",
-            ),
             AccessToUnionField => (
                 Cow::Borrowed(self.simple_description()),
                 "the field may not be properly initialized: using uninitialized data will cause \
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index 1f73b7da815c5..ded1f0462cb01 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -219,22 +219,15 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                     // We have to check the actual type of the assignment, as that determines if the
                     // old value is being dropped.
                     let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty;
-                    // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
-                    let manually_drop = assigned_ty
-                        .ty_adt_def()
-                        .map_or(false, |adt_def| adt_def.is_manually_drop());
-                    let nodrop = manually_drop
-                        || assigned_ty.is_copy_modulo_regions(
-                            self.tcx.at(self.source_info.span),
-                            self.param_env,
+                    if assigned_ty.needs_drop(
+                        self.tcx,
+                        self.tcx.param_env(base_ty.ty_adt_def().unwrap().did()),
+                    ) {
+                        // This would be unsafe, but should be outright impossible since we reject such unions.
+                        self.tcx.sess.delay_span_bug(
+                            self.source_info.span,
+                            "union fields that need dropping should be impossible",
                         );
-                    if !nodrop {
-                        self.require_unsafe(
-                            UnsafetyViolationKind::General,
-                            UnsafetyViolationDetails::AssignToDroppingUnionField,
-                        );
-                    } else {
-                        // write to non-drop union field, safe
                     }
                 } else {
                     self.require_unsafe(
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d0723c68a77e8..20d03d797fed1 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1808,21 +1808,6 @@ impl CheckAttrVisitor<'_> {
                         _ => ("a", "struct, enum, or union"),
                     }
                 }
-                sym::no_niche => {
-                    if !self.tcx.features().enabled(sym::no_niche) {
-                        feature_err(
-                            &self.tcx.sess.parse_sess,
-                            sym::no_niche,
-                            hint.span(),
-                            "the attribute `repr(no_niche)` is currently unstable",
-                        )
-                        .emit();
-                    }
-                    match target {
-                        Target::Struct | Target::Enum => continue,
-                        _ => ("a", "struct or enum"),
-                    }
-                }
                 sym::i8
                 | sym::u8
                 | sym::i16
@@ -1870,10 +1855,8 @@ impl CheckAttrVisitor<'_> {
         // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
         let hint_spans = hints.iter().map(|hint| hint.span());
 
-        // Error on repr(transparent, <anything else apart from no_niche>).
-        let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche;
-        let non_no_niche_count = hints.iter().filter(non_no_niche).count();
-        if is_transparent && non_no_niche_count > 1 {
+        // Error on repr(transparent, <anything else>).
+        if is_transparent && hints.len() > 1 {
             let hint_spans: Vec<_> = hint_spans.clone().collect();
             struct_span_err!(
                 self.tcx.sess,
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 12050dceb60a6..a06213ca5f442 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -13,13 +13,12 @@ use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind,
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
-use rustc_middle::ty::{self, query::Providers, TyCtxt};
+use rustc_middle::ty::{query::Providers, TyCtxt};
 use rustc_session::lint;
 use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
-use rustc_session::parse::feature_err;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 use std::cmp::Ordering;
@@ -766,39 +765,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                 }
             }
 
-            // There's no good place to insert stability check for non-Copy unions,
-            // so semi-randomly perform it here in stability.rs
-            hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => {
-                let ty = self.tcx.type_of(item.def_id);
-                let ty::Adt(adt_def, substs) = ty.kind() else { bug!() };
-
-                // Non-`Copy` fields are unstable, except for `ManuallyDrop`.
-                let param_env = self.tcx.param_env(item.def_id);
-                for field in &adt_def.non_enum_variant().fields {
-                    let field_ty = field.ty(self.tcx, substs);
-                    if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop())
-                        && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env)
-                    {
-                        if field_ty.needs_drop(self.tcx, param_env) {
-                            // Avoid duplicate error: This will error later anyway because fields
-                            // that need drop are not allowed.
-                            self.tcx.sess.delay_span_bug(
-                                item.span,
-                                "union should have been rejected due to potentially dropping field",
-                            );
-                        } else {
-                            feature_err(
-                                &self.tcx.sess.parse_sess,
-                                sym::untagged_unions,
-                                self.tcx.def_span(field.did),
-                                "unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable",
-                            )
-                            .emit();
-                        }
-                    }
-                }
-            }
-
             _ => (/* pass */),
         }
         intravisit::walk_item(self, item);
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 9b6967621f1dc..99912b491cb7d 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -980,7 +980,6 @@ symbols! {
         no_link,
         no_main,
         no_mangle,
-        no_niche,
         no_sanitize,
         no_stack_check,
         no_start,
@@ -1153,7 +1152,6 @@ symbols! {
         repr128,
         repr_align,
         repr_align_enum,
-        repr_no_niche,
         repr_packed,
         repr_simd,
         repr_transparent,
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index e9709b64d930e..dfcd35d2178e7 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -17,6 +17,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
+use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::subst::GenericArgKind;
@@ -401,11 +402,37 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
     let item_type = tcx.type_of(item_def_id);
     if let ty::Adt(def, substs) = item_type.kind() {
         assert!(def.is_union());
-        let fields = &def.non_enum_variant().fields;
+
+        fn allowed_union_field<'tcx>(
+            ty: Ty<'tcx>,
+            tcx: TyCtxt<'tcx>,
+            param_env: ty::ParamEnv<'tcx>,
+            span: Span,
+        ) -> bool {
+            // We don't just accept all !needs_drop fields, due to semver concerns.
+            match ty.kind() {
+                ty::Ref(..) => true, // references never drop (even mutable refs, which are non-Copy and hence fail the later check)
+                ty::Tuple(tys) => {
+                    // allow tuples of allowed types
+                    tys.iter().all(|ty| allowed_union_field(ty, tcx, param_env, span))
+                }
+                ty::Array(elem, _len) => {
+                    // Like `Copy`, we do *not* special-case length 0.
+                    allowed_union_field(*elem, tcx, param_env, span)
+                }
+                _ => {
+                    // Fallback case: allow `ManuallyDrop` and things that are `Copy`.
+                    ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
+                        || ty.is_copy_modulo_regions(tcx.at(span), param_env)
+                }
+            }
+        }
+
         let param_env = tcx.param_env(item_def_id);
-        for field in fields {
+        for field in &def.non_enum_variant().fields {
             let field_ty = field.ty(tcx, substs);
-            if field_ty.needs_drop(tcx, param_env) {
+
+            if !allowed_union_field(field_ty, tcx, param_env, span) {
                 let (field_span, ty_span) = match tcx.hir().get_if_local(field.did) {
                     // We are currently checking the type this field came from, so it must be local.
                     Some(Node::Field(field)) => (field.span, field.ty.span),
@@ -432,6 +459,9 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                 )
                 .emit();
                 return false;
+            } else if field_ty.needs_drop(tcx, param_env) {
+                // This should never happen. But we can get here e.g. in case of name resolution errors.
+                tcx.sess.delay_span_bug(span, "we should never accept maybe-dropping union fields");
             }
         }
     } else {
@@ -1318,7 +1348,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         }
     }
 
-    // For each field, figure out if it's known to be a ZST and align(1)
+    // For each field, figure out if it's known to be a ZST and align(1), with "known"
+    // respecting #[non_exhaustive] attributes.
     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);
@@ -1327,16 +1358,56 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         let span = tcx.hir().span_if_local(field.did).unwrap();
         let zst = layout.map_or(false, |layout| layout.is_zst());
         let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1);
-        (span, zst, align1)
+        if !zst {
+            return (span, zst, align1, None);
+        }
+
+        fn check_non_exhaustive<'tcx>(
+            tcx: TyCtxt<'tcx>,
+            t: Ty<'tcx>,
+        ) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> {
+            match t.kind() {
+                ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
+                ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
+                ty::Adt(def, subst) => {
+                    if !def.did().is_local() {
+                        let non_exhaustive = def.is_variant_list_non_exhaustive()
+                            || def
+                                .variants()
+                                .iter()
+                                .any(ty::VariantDef::is_field_list_non_exhaustive);
+                        let has_priv = def.all_fields().any(|f| !f.vis.is_public());
+                        if non_exhaustive || has_priv {
+                            return ControlFlow::Break((
+                                def.descr(),
+                                def.did(),
+                                subst,
+                                non_exhaustive,
+                            ));
+                        }
+                    }
+                    def.all_fields()
+                        .map(|field| field.ty(tcx, subst))
+                        .try_for_each(|t| check_non_exhaustive(tcx, t))
+                }
+                _ => ControlFlow::Continue(()),
+            }
+        }
+
+        (span, zst, align1, check_non_exhaustive(tcx, ty).break_value())
     });
 
-    let non_zst_fields =
-        field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
+    let non_zst_fields = field_infos
+        .clone()
+        .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count >= 2 {
         bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
     }
-    for (span, zst, align1) in field_infos {
+    let incompatible_zst_fields =
+        field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
+    let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
+    for (span, zst, align1, non_exhaustive) in field_infos {
         if zst && !align1 {
             struct_span_err!(
                 tcx.sess,
@@ -1348,6 +1419,25 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
             .span_label(span, "has alignment larger than 1")
             .emit();
         }
+        if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive {
+            tcx.struct_span_lint_hir(
+                REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+                tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
+                span,
+                |lint| {
+                    let note = if non_exhaustive {
+                        "is marked with `#[non_exhaustive]`"
+                    } else {
+                        "contains private fields"
+                    };
+                    let field_ty = tcx.def_path_str_with_substs(def_id, substs);
+                    lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
+                        .note(format!("this {descr} contains `{field_ty}`, which {note}, \
+                            and makes it not a breaking change to become non-zero-sized in the future."))
+                        .emit();
+                },
+            )
+        }
     }
 }
 
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index dd712fd7ed71d..f98ae46c58730 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -72,6 +72,7 @@ This API is completely unstable and subject to change.
 #![feature(once_cell)]
 #![feature(slice_partition_dedup)]
 #![feature(try_blocks)]
+#![feature(is_some_with)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 63c83ddb6f7cf..8a37fadc56f4c 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1856,7 +1856,6 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 #[lang = "unsafe_cell"]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[repr(transparent)]
-#[repr(no_niche)] // rust-lang/rust#68303.
 pub struct UnsafeCell<T: ?Sized> {
     value: T,
 }
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index bd256cec8a147..f24a7ab61ae89 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -191,7 +191,6 @@
 #![feature(never_type)]
 #![feature(no_core)]
 #![feature(no_coverage)] // rust-lang/rust#84605
-#![feature(no_niche)] // rust-lang/rust#68303
 #![feature(platform_intrinsics)]
 #![feature(prelude_import)]
 #![feature(repr_simd)]
diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs
index e1dc6f8f4b63d..6e464f69510ec 100644
--- a/src/test/ui/associated-type-bounds/duplicate.rs
+++ b/src/test/ui/associated-type-bounds/duplicate.rs
@@ -1,8 +1,8 @@
 #![feature(associated_type_bounds)]
 #![feature(type_alias_impl_trait)]
-#![feature(untagged_unions)]
 
 use std::iter;
+use std::mem::ManuallyDrop;
 
 struct SI1<T: Iterator<Item: Copy, Item: Send>> {
     //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
@@ -74,36 +74,36 @@ where
 
 union UI1<T: Iterator<Item: Copy, Item: Send>> {
     //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-    f: T,
+    f: ManuallyDrop<T>,
 }
 union UI2<T: Iterator<Item: Copy, Item: Copy>> {
     //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-    f: T,
+    f: ManuallyDrop<T>,
 }
 union UI3<T: Iterator<Item: 'static, Item: 'static>> {
     //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
-    f: T,
+    f: ManuallyDrop<T>,
 }
 union UW1<T>
 where
     T: Iterator<Item: Copy, Item: Send>,
     //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 {
-    f: T,
+    f: ManuallyDrop<T>,
 }
 union UW2<T>
 where
     T: Iterator<Item: Copy, Item: Copy>,
     //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 {
-    f: T,
+    f: ManuallyDrop<T>,
 }
 union UW3<T>
 where
     T: Iterator<Item: 'static, Item: 'static>,
     //~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719]
 {
-    f: T,
+    f: ManuallyDrop<T>,
 }
 
 fn FI1<T: Iterator<Item: Copy, Item: Send>>() {}
diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs
index 5af057387509d..f26037f070766 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.rs
+++ b/src/test/ui/associated-type-bounds/inside-adt.rs
@@ -1,5 +1,6 @@
 #![feature(associated_type_bounds)]
-#![feature(untagged_unions)]
+
+use std::mem::ManuallyDrop;
 
 struct S1 { f: dyn Iterator<Item: Copy> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
@@ -17,12 +18,12 @@ enum E3 { V(dyn Iterator<Item: 'static>) }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
 //~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)`
 
-union U1 { f: dyn Iterator<Item: Copy> }
+union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
 //~| ERROR the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)`
-union U2 { f: Box<dyn Iterator<Item: Copy>> }
+union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
-union U3 { f: dyn Iterator<Item: 'static> }
+union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
 //~^ ERROR associated type bounds are not allowed within structs, enums, or unions
 //~| ERROR the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)`
 
diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr
index 0cacd78724732..978390fa71235 100644
--- a/src/test/ui/associated-type-bounds/inside-adt.stderr
+++ b/src/test/ui/associated-type-bounds/inside-adt.stderr
@@ -1,59 +1,59 @@
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:4:29
+  --> $DIR/inside-adt.rs:5:29
    |
 LL | struct S1 { f: dyn Iterator<Item: Copy> }
    |                             ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:6:33
+  --> $DIR/inside-adt.rs:7:33
    |
 LL | struct S2 { f: Box<dyn Iterator<Item: Copy>> }
    |                                 ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:8:29
+  --> $DIR/inside-adt.rs:9:29
    |
 LL | struct S3 { f: dyn Iterator<Item: 'static> }
    |                             ^^^^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:11:26
+  --> $DIR/inside-adt.rs:12:26
    |
 LL | enum E1 { V(dyn Iterator<Item: Copy>) }
    |                          ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:14:30
+  --> $DIR/inside-adt.rs:15:30
    |
 LL | enum E2 { V(Box<dyn Iterator<Item: Copy>>) }
    |                              ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:16:26
+  --> $DIR/inside-adt.rs:17:26
    |
 LL | enum E3 { V(dyn Iterator<Item: 'static>) }
    |                          ^^^^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:20:28
+  --> $DIR/inside-adt.rs:21:41
    |
-LL | union U1 { f: dyn Iterator<Item: Copy> }
-   |                            ^^^^^^^^^^
+LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
+   |                                         ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:23:32
+  --> $DIR/inside-adt.rs:24:45
    |
-LL | union U2 { f: Box<dyn Iterator<Item: Copy>> }
-   |                                ^^^^^^^^^^
+LL | union U2 { f: ManuallyDrop<Box<dyn Iterator<Item: Copy>>> }
+   |                                             ^^^^^^^^^^
 
 error: associated type bounds are not allowed within structs, enums, or unions
-  --> $DIR/inside-adt.rs:25:28
+  --> $DIR/inside-adt.rs:26:41
    |
-LL | union U3 { f: dyn Iterator<Item: 'static> }
-   |                            ^^^^^^^^^^^^^
+LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
+   |                                         ^^^^^^^^^^^^^
 
 error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:11:13
+  --> $DIR/inside-adt.rs:12:13
    |
 LL | enum E1 { V(dyn Iterator<Item: Copy>) }
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -71,7 +71,7 @@ LL | enum E1 { V(Box<dyn Iterator<Item: Copy>>) }
    |             ++++                        +
 
 error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:16:13
+  --> $DIR/inside-adt.rs:17:13
    |
 LL | enum E3 { V(dyn Iterator<Item: 'static>) }
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -89,40 +89,42 @@ LL | enum E3 { V(Box<dyn Iterator<Item: 'static>>) }
    |             ++++                           +
 
 error[E0277]: the size for values of type `(dyn Iterator<Item = impl Copy> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:20:15
+  --> $DIR/inside-adt.rs:21:15
    |
-LL | union U1 { f: dyn Iterator<Item: Copy> }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+LL | union U1 { f: ManuallyDrop<dyn Iterator<Item: Copy>> }
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)`
+   = help: within `ManuallyDrop<(dyn Iterator<Item = impl Copy> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Copy> + 'static)`
+   = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Copy> + 'static)>`
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
    |
-LL | union U1 { f: &dyn Iterator<Item: Copy> }
+LL | union U1 { f: &ManuallyDrop<dyn Iterator<Item: Copy>> }
    |               +
 help: the `Box` type always has a statically known size and allocates its contents in the heap
    |
-LL | union U1 { f: Box<dyn Iterator<Item: Copy>> }
-   |               ++++                        +
+LL | union U1 { f: Box<ManuallyDrop<dyn Iterator<Item: Copy>>> }
+   |               ++++                                      +
 
 error[E0277]: the size for values of type `(dyn Iterator<Item = impl Sized> + 'static)` cannot be known at compilation time
-  --> $DIR/inside-adt.rs:25:15
+  --> $DIR/inside-adt.rs:26:15
    |
-LL | union U3 { f: dyn Iterator<Item: 'static> }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+LL | union U3 { f: ManuallyDrop<dyn Iterator<Item: 'static>> }
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
-   = help: the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)`
+   = help: within `ManuallyDrop<(dyn Iterator<Item = impl Sized> + 'static)>`, the trait `Sized` is not implemented for `(dyn Iterator<Item = impl Sized> + 'static)`
+   = note: required because it appears within the type `ManuallyDrop<(dyn Iterator<Item = impl Sized> + 'static)>`
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: borrowed types always have a statically known size
    |
-LL | union U3 { f: &dyn Iterator<Item: 'static> }
+LL | union U3 { f: &ManuallyDrop<dyn Iterator<Item: 'static>> }
    |               +
 help: the `Box` type always has a statically known size and allocates its contents in the heap
    |
-LL | union U3 { f: Box<dyn Iterator<Item: 'static>> }
-   |               ++++                           +
+LL | union U3 { f: Box<ManuallyDrop<dyn Iterator<Item: 'static>>> }
+   |               ++++                                         +
 
 error: aborting due to 13 previous errors
 
diff --git a/src/test/ui/associated-type-bounds/union-bounds.rs b/src/test/ui/associated-type-bounds/union-bounds.rs
index 97c5acf1f72ca..46e5aef04031a 100644
--- a/src/test/ui/associated-type-bounds/union-bounds.rs
+++ b/src/test/ui/associated-type-bounds/union-bounds.rs
@@ -1,7 +1,6 @@
 // run-pass
 
 #![feature(associated_type_bounds)]
-#![feature(untagged_unions)]
 
 #![allow(unused_assignments)]
 
diff --git a/src/test/ui/binding/issue-53114-safety-checks.rs b/src/test/ui/binding/issue-53114-safety-checks.rs
index 5042ad024afff..d0eb28c571411 100644
--- a/src/test/ui/binding/issue-53114-safety-checks.rs
+++ b/src/test/ui/binding/issue-53114-safety-checks.rs
@@ -3,9 +3,9 @@
 // captures the behavior of how `_` bindings are handled with respect to how we
 // flag expressions that are meant to request unsafe blocks.
 
-#![feature(untagged_unions)]
-
+#[derive(Copy, Clone)]
 struct I(i64);
+#[derive(Copy, Clone)]
 struct F(f64);
 
 union U { a: I, b: F }
diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.rs b/src/test/ui/borrowck/borrowck-union-move-assign.rs
index a24f42d2ddf87..4c96ccdb25aaa 100644
--- a/src/test/ui/borrowck/borrowck-union-move-assign.rs
+++ b/src/test/ui/borrowck/borrowck-union-move-assign.rs
@@ -1,31 +1,31 @@
-#![feature(untagged_unions)]
+use std::mem::ManuallyDrop;
 
 // Non-copy
 struct A;
 struct B;
 
 union U {
-    a: A,
-    b: B,
+    a: ManuallyDrop<A>,
+    b: ManuallyDrop<B>,
 }
 
 fn main() {
     unsafe {
         {
-            let mut u = U { a: A };
+            let mut u = U { a: ManuallyDrop::new(A) };
             let a = u.a;
             let a = u.a; //~ ERROR use of moved value: `u`
         }
         {
-            let mut u = U { a: A };
+            let mut u = U { a: ManuallyDrop::new(A) };
             let a = u.a;
-            u.a = A;
+            u.a = ManuallyDrop::new(A);
             let a = u.a; // OK
         }
         {
-            let mut u = U { a: A };
+            let mut u = U { a: ManuallyDrop::new(A) };
             let a = u.a;
-            u.b = B;
+            u.b = ManuallyDrop::new(B);
             let a = u.a; // OK
         }
     }
diff --git a/src/test/ui/borrowck/borrowck-union-move-assign.stderr b/src/test/ui/borrowck/borrowck-union-move-assign.stderr
index 0b1714fd75dc0..af6f6fac40870 100644
--- a/src/test/ui/borrowck/borrowck-union-move-assign.stderr
+++ b/src/test/ui/borrowck/borrowck-union-move-assign.stderr
@@ -1,7 +1,7 @@
 error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move-assign.rs:17:21
    |
-LL |             let mut u = U { a: A };
+LL |             let mut u = U { a: ManuallyDrop::new(A) };
    |                 ----- move occurs because `u` has type `U`, which does not implement the `Copy` trait
 LL |             let a = u.a;
    |                     --- value moved here
diff --git a/src/test/ui/borrowck/borrowck-union-move.rs b/src/test/ui/borrowck/borrowck-union-move.rs
index d0aa6dff74410..510547ad5bb74 100644
--- a/src/test/ui/borrowck/borrowck-union-move.rs
+++ b/src/test/ui/borrowck/borrowck-union-move.rs
@@ -1,12 +1,12 @@
-#![feature(untagged_unions)]
+use std::mem::ManuallyDrop;
 
 #[derive(Clone, Copy)]
 struct Copy;
 struct NonCopy;
 
 union Unn {
-    n1: NonCopy,
-    n2: NonCopy,
+    n1: ManuallyDrop<NonCopy>,
+    n2: ManuallyDrop<NonCopy>,
 }
 union Ucc {
     c1: Copy,
@@ -14,24 +14,24 @@ union Ucc {
 }
 union Ucn {
     c: Copy,
-    n: NonCopy,
+    n: ManuallyDrop<NonCopy>,
 }
 
 fn main() {
     unsafe {
         // 2 NonCopy
         {
-            let mut u = Unn { n1: NonCopy };
+            let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
             let a = u.n1;
             let a = u.n1; //~ ERROR use of moved value: `u`
         }
         {
-            let mut u = Unn { n1: NonCopy };
+            let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
             let a = u.n1;
             let a = u; //~ ERROR use of moved value: `u`
         }
         {
-            let mut u = Unn { n1: NonCopy };
+            let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
             let a = u.n1;
             let a = u.n2; //~ ERROR use of moved value: `u`
         }
diff --git a/src/test/ui/borrowck/borrowck-union-move.stderr b/src/test/ui/borrowck/borrowck-union-move.stderr
index abbb0142a9c30..731607fbdd1f7 100644
--- a/src/test/ui/borrowck/borrowck-union-move.stderr
+++ b/src/test/ui/borrowck/borrowck-union-move.stderr
@@ -1,7 +1,7 @@
 error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move.rs:26:21
    |
-LL |             let mut u = Unn { n1: NonCopy };
+LL |             let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
    |                 ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
 LL |             let a = u.n1;
    |                     ---- value moved here
@@ -11,7 +11,7 @@ LL |             let a = u.n1;
 error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move.rs:31:21
    |
-LL |             let mut u = Unn { n1: NonCopy };
+LL |             let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
    |                 ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
 LL |             let a = u.n1;
    |                     ---- value moved here
@@ -21,7 +21,7 @@ LL |             let a = u;
 error[E0382]: use of moved value: `u`
   --> $DIR/borrowck-union-move.rs:36:21
    |
-LL |             let mut u = Unn { n1: NonCopy };
+LL |             let mut u = Unn { n1: ManuallyDrop::new(NonCopy) };
    |                 ----- move occurs because `u` has type `Unn`, which does not implement the `Copy` trait
 LL |             let a = u.n1;
    |                     ---- value moved here
diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs
index 8fbf120fc1c78..0bd2147f46331 100644
--- a/src/test/ui/borrowck/move-from-union-field-issue-66500.rs
+++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.rs
@@ -1,8 +1,6 @@
 // Moving from a reference/raw pointer should be an error, even when they're
 // the field of a union.
 
-#![feature(untagged_unions)]
-
 union Pointers {
     a: &'static String,
     b: &'static mut String,
diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr
index 82c3fe3b12d1c..70078582713c6 100644
--- a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr
+++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr
@@ -1,23 +1,23 @@
 error[E0507]: cannot move out of `*u.a` which is behind a shared reference
-  --> $DIR/move-from-union-field-issue-66500.rs:14:5
+  --> $DIR/move-from-union-field-issue-66500.rs:12:5
    |
 LL |     *u.a
    |     ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `*u.b` which is behind a mutable reference
-  --> $DIR/move-from-union-field-issue-66500.rs:18:5
+  --> $DIR/move-from-union-field-issue-66500.rs:16:5
    |
 LL |     *u.b
    |     ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `*u.c` which is behind a raw pointer
-  --> $DIR/move-from-union-field-issue-66500.rs:22:5
+  --> $DIR/move-from-union-field-issue-66500.rs:20:5
    |
 LL |     *u.c
    |     ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait
 
 error[E0507]: cannot move out of `*u.d` which is behind a raw pointer
-  --> $DIR/move-from-union-field-issue-66500.rs:26:5
+  --> $DIR/move-from-union-field-issue-66500.rs:24:5
    |
 LL |     *u.d
    |     ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait
diff --git a/src/test/ui/consts/invalid-union.32bit.stderr b/src/test/ui/consts/invalid-union.32bit.stderr
index 7e9abc3ffa7e1..ae5f6b2baee40 100644
--- a/src/test/ui/consts/invalid-union.32bit.stderr
+++ b/src/test/ui/consts/invalid-union.32bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-union.rs:40:1
+  --> $DIR/invalid-union.rs:41:1
    |
 LL | fn main() {
    | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
@@ -10,7 +10,7 @@ LL | fn main() {
            }
 
 error: erroneous constant used
-  --> $DIR/invalid-union.rs:41:25
+  --> $DIR/invalid-union.rs:42:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^ referenced constant has errors
@@ -24,7 +24,7 @@ error: aborting due to 2 previous errors
 For more information about this error, try `rustc --explain E0080`.
 Future incompatibility report: Future breakage diagnostic:
 error: erroneous constant used
-  --> $DIR/invalid-union.rs:41:25
+  --> $DIR/invalid-union.rs:42:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^ referenced constant has errors
diff --git a/src/test/ui/consts/invalid-union.64bit.stderr b/src/test/ui/consts/invalid-union.64bit.stderr
index 81c1024424972..d50e74a16ec36 100644
--- a/src/test/ui/consts/invalid-union.64bit.stderr
+++ b/src/test/ui/consts/invalid-union.64bit.stderr
@@ -1,5 +1,5 @@
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/invalid-union.rs:40:1
+  --> $DIR/invalid-union.rs:41:1
    |
 LL | fn main() {
    | ^^^^^^^^^ constructing invalid value at .<deref>.y.<enum-variant(B)>.0: encountered `UnsafeCell` in a `const`
@@ -10,7 +10,7 @@ LL | fn main() {
            }
 
 error: erroneous constant used
-  --> $DIR/invalid-union.rs:41:25
+  --> $DIR/invalid-union.rs:42:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^ referenced constant has errors
@@ -24,7 +24,7 @@ error: aborting due to 2 previous errors
 For more information about this error, try `rustc --explain E0080`.
 Future incompatibility report: Future breakage diagnostic:
 error: erroneous constant used
-  --> $DIR/invalid-union.rs:41:25
+  --> $DIR/invalid-union.rs:42:25
    |
 LL |     let _: &'static _ = &C;
    |                         ^^ referenced constant has errors
diff --git a/src/test/ui/consts/invalid-union.rs b/src/test/ui/consts/invalid-union.rs
index f3f1af89b2c41..efeddf75cb557 100644
--- a/src/test/ui/consts/invalid-union.rs
+++ b/src/test/ui/consts/invalid-union.rs
@@ -9,8 +9,9 @@
 // build-fail
 // stderr-per-bitwidth
 #![feature(const_mut_refs)]
-#![feature(untagged_unions)]
+
 use std::cell::Cell;
+use std::mem::ManuallyDrop;
 
 #[repr(C)]
 struct S {
@@ -25,7 +26,7 @@ enum E {
 }
 
 union U {
-    cell: Cell<u32>,
+    cell: ManuallyDrop<Cell<u32>>,
 }
 
 const C: S = {
diff --git a/src/test/ui/consts/qualif-union.rs b/src/test/ui/consts/qualif-union.rs
index 2054b5b89ed6e..11c019be96432 100644
--- a/src/test/ui/consts/qualif-union.rs
+++ b/src/test/ui/consts/qualif-union.rs
@@ -1,18 +1,19 @@
 // Checks that unions use type based qualification. Regression test for issue #90268.
-#![feature(untagged_unions)]
+
 use std::cell::Cell;
+use std::mem::ManuallyDrop;
 
-union U { i: u32, c: Cell<u32> }
+union U { i: u32, c: ManuallyDrop<Cell<u32>> }
 
-const C1: Cell<u32> = {
-    unsafe { U { c: Cell::new(0) }.c }
+const C1: ManuallyDrop<Cell<u32>> = {
+    unsafe { U { c: ManuallyDrop::new(Cell::new(0)) }.c }
 };
 
-const C2: Cell<u32> = {
+const C2: ManuallyDrop<Cell<u32>> = {
     unsafe { U { i : 0 }.c }
 };
 
-const C3: Cell<u32> = {
+const C3: ManuallyDrop<Cell<u32>> = {
     let mut u = U { i: 0 };
     u.i = 1;
     unsafe { u.c }
diff --git a/src/test/ui/consts/qualif-union.stderr b/src/test/ui/consts/qualif-union.stderr
index fda8ad4a3bc81..8ec68ada048a5 100644
--- a/src/test/ui/consts/qualif-union.stderr
+++ b/src/test/ui/consts/qualif-union.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/qualif-union.rs:27:26
+  --> $DIR/qualif-union.rs:28:26
    |
 LL |     let _: &'static _ = &C1;
    |            ----------    ^^ creates a temporary which is freed while still in use
@@ -10,7 +10,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/qualif-union.rs:28:26
+  --> $DIR/qualif-union.rs:29:26
    |
 LL |     let _: &'static _ = &C2;
    |            ----------    ^^ creates a temporary which is freed while still in use
@@ -21,7 +21,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/qualif-union.rs:29:26
+  --> $DIR/qualif-union.rs:30:26
    |
 LL |     let _: &'static _ = &C3;
    |            ----------    ^^ creates a temporary which is freed while still in use
@@ -32,7 +32,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/qualif-union.rs:30:26
+  --> $DIR/qualif-union.rs:31:26
    |
 LL |     let _: &'static _ = &C4;
    |            ----------    ^^ creates a temporary which is freed while still in use
@@ -43,7 +43,7 @@ LL | }
    | - temporary value is freed at the end of this statement
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/qualif-union.rs:31:26
+  --> $DIR/qualif-union.rs:32:26
    |
 LL |     let _: &'static _ = &C5;
    |            ----------    ^^ creates a temporary which is freed while still in use
diff --git a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
index a93fb7977131d..4e020327447ff 100644
--- a/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
+++ b/src/test/ui/feature-gates/feature-gate-associated_type_bounds.rs
@@ -1,7 +1,7 @@
 // compile-flags: -Zsave-analysis
 // This is also a regression test for #69415 and the above flag is needed.
 
-#![feature(untagged_unions)]
+use std::mem::ManuallyDrop;
 
 trait Tr1 { type As1: Copy; }
 trait Tr2 { type As2: Copy; }
@@ -36,9 +36,9 @@ enum _En1<T: Tr1<As1: Tr2>> {
 
 union _Un1<T: Tr1<As1: Tr2>> {
 //~^ ERROR associated type bounds are unstable
-    outest: std::mem::ManuallyDrop<T>,
-    outer: T::As1,
-    inner: <T::As1 as Tr2>::As2,
+    outest: ManuallyDrop<T>,
+    outer: ManuallyDrop<T::As1>,
+    inner: ManuallyDrop<<T::As1 as Tr2>::As2>,
 }
 
 type _TaWhere1<T> where T: Iterator<Item: Copy> = T;
diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
deleted file mode 100644
index af8d8e92b20bd..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// ignore-tidy-linelength
-
-union U1 { // OK
-    a: u8,
-}
-
-union U2<T: Copy> { // OK
-    a: T,
-}
-
-union U22<T> { // OK
-    a: std::mem::ManuallyDrop<T>,
-}
-
-union U3 {
-    a: String, //~ ERROR unions cannot contain fields that may need dropping
-}
-
-union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test!
-    a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
-}
-
-union U4<T> {
-    a: T, //~ ERROR unions cannot contain fields that may need dropping
-}
-
-union U5 { // Having a drop impl is OK
-    a: u8,
-}
-
-impl Drop for U5 {
-    fn drop(&mut self) {}
-}
-
-fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
deleted file mode 100644
index 9e4a89f80c852..0000000000000
--- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr
+++ /dev/null
@@ -1,37 +0,0 @@
-error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable
-  --> $DIR/feature-gate-untagged_unions.rs:20:5
-   |
-LL |     a: std::cell::RefCell<i32>,
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information
-   = help: add `#![feature(untagged_unions)]` to the crate attributes to enable
-
-error[E0740]: unions cannot contain fields that may need dropping
-  --> $DIR/feature-gate-untagged_unions.rs:16:5
-   |
-LL |     a: String,
-   |     ^^^^^^^^^
-   |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
-   |
-LL |     a: std::mem::ManuallyDrop<String>,
-   |        +++++++++++++++++++++++      +
-
-error[E0740]: unions cannot contain fields that may need dropping
-  --> $DIR/feature-gate-untagged_unions.rs:24:5
-   |
-LL |     a: T,
-   |     ^^^^
-   |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
-   |
-LL |     a: std::mem::ManuallyDrop<T>,
-   |        +++++++++++++++++++++++ +
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0658, E0740.
-For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/layout/unsafe-cell-hides-niche.rs b/src/test/ui/layout/unsafe-cell-hides-niche.rs
index 4ca3f7a1aad94..fce101d7bb173 100644
--- a/src/test/ui/layout/unsafe-cell-hides-niche.rs
+++ b/src/test/ui/layout/unsafe-cell-hides-niche.rs
@@ -3,30 +3,79 @@
 // test checks that an `Option<UnsafeCell<NonZeroU32>>` has the same
 // size in memory as an `Option<UnsafeCell<u32>>` (namely, 8 bytes).
 
-// run-pass
+// check-pass
+// compile-flags: --crate-type=lib
 
-#![feature(no_niche)]
+#![feature(repr_simd)]
 
-use std::cell::UnsafeCell;
+use std::cell::{UnsafeCell, RefCell, Cell};
 use std::mem::size_of;
 use std::num::NonZeroU32 as N32;
+use std::sync::{Mutex, RwLock};
 
 struct Wrapper<T>(T);
 
 #[repr(transparent)]
 struct Transparent<T>(T);
 
-#[repr(no_niche)]
-struct NoNiche<T>(T);
+struct NoNiche<T>(UnsafeCell<T>);
 
-fn main() {
-    assert_eq!(size_of::<Option<Wrapper<u32>>>(),     8);
-    assert_eq!(size_of::<Option<Wrapper<N32>>>(),     4);
-    assert_eq!(size_of::<Option<Transparent<u32>>>(), 8);
-    assert_eq!(size_of::<Option<Transparent<N32>>>(), 4);
-    assert_eq!(size_of::<Option<NoNiche<u32>>>(),     8);
-    assert_eq!(size_of::<Option<NoNiche<N32>>>(),     8);
+struct Size<const S: usize>;
 
-    assert_eq!(size_of::<Option<UnsafeCell<u32>>>(),  8);
-    assert_eq!(size_of::<Option<UnsafeCell<N32>>>(),  8);
+macro_rules! check_sizes {
+    (check_one_specific_size: $ty:ty, $size:expr) => {
+        const _: Size::<{$size}> = Size::<{size_of::<$ty>()}>;
+    };
+    // Any tests run on `UnsafeCell` must be the same for `Cell`
+    (UnsafeCell<$ty:ty>: $size:expr => $optioned_size:expr) => {
+        check_sizes!(Cell<$ty>: $size => $optioned_size);
+        check_sizes!(@actual_check: UnsafeCell<$ty>: $size => $optioned_size);
+    };
+    ($ty:ty: $size:expr => $optioned_size:expr) => {
+        check_sizes!(@actual_check: $ty: $size => $optioned_size);
+    };
+    // This branch does the actual checking logic, the `@actual_check` prefix is here to distinguish
+    // it from other branches and not accidentally match any.
+    (@actual_check: $ty:ty: $size:expr => $optioned_size:expr) => {
+        check_sizes!(check_one_specific_size: $ty, $size);
+        check_sizes!(check_one_specific_size: Option<$ty>, $optioned_size);
+        check_sizes!(check_no_niche_opt: $size != $optioned_size, $ty);
+    };
+    // only check that there is no niche (size goes up when wrapped in an option),
+    // don't check actual sizes
+    ($ty:ty) => {
+        check_sizes!(check_no_niche_opt: true, $ty);
+    };
+    (check_no_niche_opt: $no_niche_opt:expr, $ty:ty) => {
+        const _: () = if $no_niche_opt { assert!(size_of::<$ty>() < size_of::<Option<$ty>>()); };
+    };
 }
+
+const PTR_SIZE: usize = std::mem::size_of::<*const ()>();
+
+check_sizes!(Wrapper<u32>:     4 => 8);
+check_sizes!(Wrapper<N32>:     4 => 4); // (✓ niche opt)
+check_sizes!(Transparent<u32>: 4 => 8);
+check_sizes!(Transparent<N32>: 4 => 4); // (✓ niche opt)
+check_sizes!(NoNiche<u32>:     4 => 8);
+check_sizes!(NoNiche<N32>:     4 => 8);
+
+check_sizes!(UnsafeCell<u32>:  4 => 8);
+check_sizes!(UnsafeCell<N32>:  4 => 8);
+
+check_sizes!(UnsafeCell<&()>: PTR_SIZE => PTR_SIZE * 2);
+check_sizes!(   RefCell<&()>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+check_sizes!(RwLock<&()>);
+check_sizes!(Mutex<&()>);
+
+check_sizes!(UnsafeCell<&[i32]>: PTR_SIZE * 2 => PTR_SIZE * 3);
+check_sizes!(UnsafeCell<(&(), &())>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+trait Trait {}
+check_sizes!(UnsafeCell<&dyn Trait>: PTR_SIZE * 2 => PTR_SIZE * 3);
+
+#[repr(simd)]
+pub struct Vec4<T>([T; 4]);
+
+check_sizes!(UnsafeCell<Vec4<N32>>: 16 => 32);
diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs
index 2ce4dd56eab0d..809e0602671fe 100644
--- a/src/test/ui/lint/clashing-extern-fn.rs
+++ b/src/test/ui/lint/clashing-extern-fn.rs
@@ -1,7 +1,6 @@
 // check-pass
 // aux-build:external_extern_fn.rs
 #![crate_type = "lib"]
-#![feature(no_niche)]
 #![warn(clashing_extern_declarations)]
 
 mod redeclared_different_signature {
@@ -400,9 +399,8 @@ mod hidden_niche {
         #[repr(transparent)]
         struct Transparent { x: NonZeroUsize }
 
-        #[repr(no_niche)]
         #[repr(transparent)]
-        struct TransparentNoNiche { y: NonZeroUsize }
+        struct TransparentNoNiche { y: UnsafeCell<NonZeroUsize> }
 
         extern "C" {
             fn hidden_niche_transparent() -> Option<Transparent>;
diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr
index a856de322c8ca..4607f68499322 100644
--- a/src/test/ui/lint/clashing-extern-fn.stderr
+++ b/src/test/ui/lint/clashing-extern-fn.stderr
@@ -1,5 +1,5 @@
 warning: `clash` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:15:13
+  --> $DIR/clashing-extern-fn.rs:14:13
    |
 LL |             fn clash(x: u8);
    |             ---------------- `clash` previously declared here
@@ -8,7 +8,7 @@ LL |             fn clash(x: u64);
    |             ^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration
    |
 note: the lint level is defined here
-  --> $DIR/clashing-extern-fn.rs:5:9
+  --> $DIR/clashing-extern-fn.rs:4:9
    |
 LL | #![warn(clashing_extern_declarations)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | #![warn(clashing_extern_declarations)]
               found `unsafe extern "C" fn(u64)`
 
 warning: `extern_link_name` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:53:9
+  --> $DIR/clashing-extern-fn.rs:52:9
    |
 LL | /     #[link_name = "extern_link_name"]
 LL | |     fn some_new_name(x: i16);
@@ -29,7 +29,7 @@ LL |           fn extern_link_name(x: u32);
               found `unsafe extern "C" fn(u32)`
 
 warning: `some_other_extern_link_name` redeclares `some_other_new_name` with a different signature
-  --> $DIR/clashing-extern-fn.rs:56:9
+  --> $DIR/clashing-extern-fn.rs:55:9
    |
 LL |       fn some_other_new_name(x: i16);
    |       ------------------------------- `some_other_new_name` previously declared here
@@ -43,7 +43,7 @@ LL | |         fn some_other_extern_link_name(x: u32);
               found `unsafe extern "C" fn(u32)`
 
 warning: `other_both_names_different` redeclares `link_name_same` with a different signature
-  --> $DIR/clashing-extern-fn.rs:60:9
+  --> $DIR/clashing-extern-fn.rs:59:9
    |
 LL | /     #[link_name = "link_name_same"]
 LL | |     fn both_names_different(x: i16);
@@ -58,7 +58,7 @@ LL | |         fn other_both_names_different(x: u32);
               found `unsafe extern "C" fn(u32)`
 
 warning: `different_mod` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:73:9
+  --> $DIR/clashing-extern-fn.rs:72:9
    |
 LL |         fn different_mod(x: u8);
    |         ------------------------ `different_mod` previously declared here
@@ -70,7 +70,7 @@ LL |         fn different_mod(x: u64);
               found `unsafe extern "C" fn(u64)`
 
 warning: `variadic_decl` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:83:9
+  --> $DIR/clashing-extern-fn.rs:82:9
    |
 LL |     fn variadic_decl(x: u8, ...);
    |     ----------------------------- `variadic_decl` previously declared here
@@ -82,7 +82,7 @@ LL |         fn variadic_decl(x: u8);
               found `unsafe extern "C" fn(u8)`
 
 warning: `weigh_banana` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:143:13
+  --> $DIR/clashing-extern-fn.rs:142:13
    |
 LL |             fn weigh_banana(count: *const Banana) -> u64;
    |             --------------------------------------------- `weigh_banana` previously declared here
@@ -94,7 +94,7 @@ LL |             fn weigh_banana(count: *const Banana) -> u64;
               found `unsafe extern "C" fn(*const three::Banana) -> u64`
 
 warning: `draw_point` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:172:13
+  --> $DIR/clashing-extern-fn.rs:171:13
    |
 LL |             fn draw_point(p: Point);
    |             ------------------------ `draw_point` previously declared here
@@ -106,7 +106,7 @@ LL |             fn draw_point(p: Point);
               found `unsafe extern "C" fn(sameish_members::b::Point)`
 
 warning: `origin` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:198:13
+  --> $DIR/clashing-extern-fn.rs:197:13
    |
 LL |             fn origin() -> Point3;
    |             ---------------------- `origin` previously declared here
@@ -118,7 +118,7 @@ LL |             fn origin() -> Point3;
               found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3`
 
 warning: `transparent_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:221:13
+  --> $DIR/clashing-extern-fn.rs:220:13
    |
 LL |             fn transparent_incorrect() -> T;
    |             -------------------------------- `transparent_incorrect` previously declared here
@@ -130,7 +130,7 @@ LL |             fn transparent_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `missing_return_type` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:239:13
+  --> $DIR/clashing-extern-fn.rs:238:13
    |
 LL |             fn missing_return_type() -> usize;
    |             ---------------------------------- `missing_return_type` previously declared here
@@ -142,7 +142,7 @@ LL |             fn missing_return_type();
               found `unsafe extern "C" fn()`
 
 warning: `non_zero_usize` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:257:13
+  --> $DIR/clashing-extern-fn.rs:256:13
    |
 LL |             fn non_zero_usize() -> core::num::NonZeroUsize;
    |             ----------------------------------------------- `non_zero_usize` previously declared here
@@ -154,7 +154,7 @@ LL |             fn non_zero_usize() -> usize;
               found `unsafe extern "C" fn() -> usize`
 
 warning: `non_null_ptr` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:259:13
+  --> $DIR/clashing-extern-fn.rs:258:13
    |
 LL |             fn non_null_ptr() -> core::ptr::NonNull<usize>;
    |             ----------------------------------------------- `non_null_ptr` previously declared here
@@ -166,7 +166,7 @@ LL |             fn non_null_ptr() -> *const usize;
               found `unsafe extern "C" fn() -> *const usize`
 
 warning: `option_non_zero_usize_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:357:13
+  --> $DIR/clashing-extern-fn.rs:356:13
    |
 LL |             fn option_non_zero_usize_incorrect() -> usize;
    |             ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here
@@ -178,7 +178,7 @@ LL |             fn option_non_zero_usize_incorrect() -> isize;
               found `unsafe extern "C" fn() -> isize`
 
 warning: `option_non_null_ptr_incorrect` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:359:13
+  --> $DIR/clashing-extern-fn.rs:358:13
    |
 LL |             fn option_non_null_ptr_incorrect() -> *const usize;
    |             --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here
@@ -190,7 +190,7 @@ LL |             fn option_non_null_ptr_incorrect() -> *const isize;
               found `unsafe extern "C" fn() -> *const isize`
 
 warning: `hidden_niche_transparent_no_niche` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:410:13
+  --> $DIR/clashing-extern-fn.rs:408:13
    |
 LL |             fn hidden_niche_transparent_no_niche() -> usize;
    |             ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here
@@ -202,7 +202,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
               found `unsafe extern "C" fn() -> Option<TransparentNoNiche>`
 
 warning: `hidden_niche_unsafe_cell` redeclared with a different signature
-  --> $DIR/clashing-extern-fn.rs:414:13
+  --> $DIR/clashing-extern-fn.rs:412:13
    |
 LL |             fn hidden_niche_unsafe_cell() -> usize;
    |             --------------------------------------- `hidden_niche_unsafe_cell` previously declared here
@@ -214,7 +214,7 @@ LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize
               found `unsafe extern "C" fn() -> Option<UnsafeCell<NonZeroUsize>>`
 
 warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:410:55
+  --> $DIR/clashing-extern-fn.rs:408:55
    |
 LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>;
    |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
@@ -224,7 +224,7 @@ LL |             fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN
    = note: enum has no representation hint
 
 warning: `extern` block uses type `Option<UnsafeCell<NonZeroUsize>>`, which is not FFI-safe
-  --> $DIR/clashing-extern-fn.rs:414:46
+  --> $DIR/clashing-extern-fn.rs:412:46
    |
 LL |             fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZeroUsize>>;
    |                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe
diff --git a/src/test/ui/nll/issue-55651.rs b/src/test/ui/nll/issue-55651.rs
index 46255bf74a138..75ba482717460 100644
--- a/src/test/ui/nll/issue-55651.rs
+++ b/src/test/ui/nll/issue-55651.rs
@@ -1,27 +1,27 @@
 // check-pass
 
-#![feature(untagged_unions)]
+use std::mem::ManuallyDrop;
 
 struct A;
 struct B;
 
 union U {
-    a: A,
-    b: B,
+    a: ManuallyDrop<A>,
+    b: ManuallyDrop<B>,
 }
 
 fn main() {
     unsafe {
         {
-            let mut u = U { a: A };
+            let mut u = U { a: ManuallyDrop::new(A) };
             let a = u.a;
-            u.a = A;
+            u.a = ManuallyDrop::new(A);
             let a = u.a; // OK
         }
         {
-            let mut u = U { a: A };
+            let mut u = U { a: ManuallyDrop::new(A) };
             let a = u.a;
-            u.b = B;
+            u.b = ManuallyDrop::new(B);
             let a = u.a; // OK
         }
     }
diff --git a/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs
new file mode 100644
index 0000000000000..4bf6b54fe0787
--- /dev/null
+++ b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+
+pub struct Private { _priv: () }
+
+#[non_exhaustive]
+pub struct NonExhaustive {}
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {}
+
+pub enum NonExhaustiveVariant {
+    #[non_exhaustive]
+    A,
+}
+
+pub struct ExternalIndirection<T> {
+    pub x: T,
+}
diff --git a/src/test/ui/repr/feature-gate-no-niche.rs b/src/test/ui/repr/feature-gate-no-niche.rs
deleted file mode 100644
index 8872ee7119e4a..0000000000000
--- a/src/test/ui/repr/feature-gate-no-niche.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-use std::num::NonZeroU8 as N8;
-use std::num::NonZeroU16 as N16;
-
-#[repr(no_niche)]
-pub struct Cloaked(N16);
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-#[repr(transparent, no_niche)]
-pub struct Shadowy(N16);
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-#[repr(no_niche)]
-pub enum Cloaked1 { _A(N16), }
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-#[repr(no_niche)]
-pub enum Cloaked2 { _A(N16), _B(u8, N8) }
-//~^^ ERROR the attribute `repr(no_niche)` is currently unstable [E0658]
-
-fn main() { }
diff --git a/src/test/ui/repr/feature-gate-no-niche.stderr b/src/test/ui/repr/feature-gate-no-niche.stderr
deleted file mode 100644
index 34fd417cc99a2..0000000000000
--- a/src/test/ui/repr/feature-gate-no-niche.stderr
+++ /dev/null
@@ -1,35 +0,0 @@
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:4:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:8:21
-   |
-LL | #[repr(transparent, no_niche)]
-   |                     ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:12:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error[E0658]: the attribute `repr(no_niche)` is currently unstable
-  --> $DIR/feature-gate-no-niche.rs:16:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-   |
-   = help: add `#![feature(no_niche)]` to the crate attributes to enable
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs
deleted file mode 100644
index 870eda89c20d7..0000000000000
--- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.rs
+++ /dev/null
@@ -1,14 +0,0 @@
-#![feature(no_niche)]
-
-use std::num::NonZeroU8 as N8;
-use std::num::NonZeroU16 as N16;
-
-#[repr(no_niche)]
-pub union Cloaked1 { _A: N16 }
-//~^^ ERROR attribute should be applied to a struct or enum [E0517]
-
-#[repr(no_niche)]
-pub union Cloaked2 { _A: N16, _B: (u8, N8) }
-//~^^ ERROR attribute should be applied to a struct or enum [E0517]
-
-fn main() { }
diff --git a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr b/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr
deleted file mode 100644
index 9af929d409473..0000000000000
--- a/src/test/ui/repr/repr-no-niche-inapplicable-to-unions.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0517]: attribute should be applied to a struct or enum
-  --> $DIR/repr-no-niche-inapplicable-to-unions.rs:6:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-LL | pub union Cloaked1 { _A: N16 }
-   | ------------------------------ not a struct or enum
-
-error[E0517]: attribute should be applied to a struct or enum
-  --> $DIR/repr-no-niche-inapplicable-to-unions.rs:10:8
-   |
-LL | #[repr(no_niche)]
-   |        ^^^^^^^^
-LL | pub union Cloaked2 { _A: N16, _B: (u8, N8) }
-   | -------------------------------------------- not a struct or enum
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0517`.
diff --git a/src/test/ui/repr/repr-no-niche.rs b/src/test/ui/repr/repr-no-niche.rs
deleted file mode 100644
index 2e6064aeb0074..0000000000000
--- a/src/test/ui/repr/repr-no-niche.rs
+++ /dev/null
@@ -1,327 +0,0 @@
-// run-pass
-
-// This file tests repr(no_niche), which causes an struct/enum to hide
-// any niche space that may exist in its internal state from the
-// context it appears in.
-
-// Here are the axes this test is seeking to cover:
-//
-// repr annotation:
-// visible: (); cloaked: (no_niche); transparent: (transparent); shadowy: (transparent, no_niche)
-//
-// enum vs struct
-//
-// niche-type via type-parameter vs inline declaration
-
-#![feature(decl_macro)]
-#![feature(no_niche)]
-
-use std::mem::size_of;
-use std::num::{NonZeroU8, NonZeroU16};
-
-mod struct_inline {
-    use std::num::NonZeroU16 as N16;
-
-    #[derive(Debug)] pub struct Visible(N16);
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub struct Cloaked(N16);
-
-    #[repr(transparent)]
-    #[derive(Debug)] pub struct Transparent(N16);
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub struct Shadowy(N16);
-}
-
-mod struct_param {
-    #[derive(Debug)] pub struct Visible<T>(T);
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub struct Cloaked<T>(T);
-
-    #[repr(transparent)]
-    #[derive(Debug)] pub struct Transparent<T>(T);
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub struct Shadowy<T>(T);
-}
-
-mod enum_inline {
-    use crate::two_fifty_six_variant_enum;
-    use std::num::{NonZeroU8 as N8, NonZeroU16 as N16};
-
-    #[derive(Debug)] pub enum Visible1 { _A(N16), }
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub enum Cloaked1 { _A(N16), }
-
-    // (N.B.: transparent enums must be univariant)
-    #[repr(transparent)]
-    #[derive(Debug)] pub enum Transparent { _A(N16), }
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub enum Shadowy { _A(N16), }
-
-    // including multivariant enums for completeness. Payload and
-    // number of variants (i.e. discriminant size) have been chosen so
-    // that layout including discriminant is 4 bytes, with no space in
-    // padding to hide another discrimnant from the surrounding
-    // context.
-    //
-    // (Note that multivariant enums cannot usefully expose a niche in
-    // general; this test is relying on that.)
-    two_fifty_six_variant_enum!(Visible2, N8);
-
-    two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2, N8);
-}
-
-mod enum_param {
-    use super::two_fifty_six_variant_enum;
-
-    #[derive(Debug)] pub enum Visible1<T> { _A(T), }
-
-    #[repr(no_niche)]
-    #[derive(Debug)] pub enum Cloaked1<T> { _A(T), }
-
-    // (N.B.: transparent enums must be univariant)
-    #[repr(transparent)]
-    #[derive(Debug)] pub enum Transparent<T> { _A(T), }
-
-    #[repr(transparent, no_niche)]
-    #[derive(Debug)] pub enum Shadowy<T> { _A(T), }
-
-    // including multivariant enums for completeness. Same notes apply
-    // here as above (assuming `T` is instantiated with `NonZeroU8`).
-    two_fifty_six_variant_enum!(Visible2<T>);
-
-    two_fifty_six_variant_enum!(#[repr(no_niche)] Cloaked2<T>);
-}
-
-fn main() {
-    // sanity-checks
-    assert_eq!(size_of::<struct_inline::Visible>(),               2);
-    assert_eq!(size_of::<struct_inline::Cloaked>(),               2);
-    assert_eq!(size_of::<struct_inline::Transparent>(),           2);
-    assert_eq!(size_of::<struct_inline::Shadowy>(),               2);
-
-    assert_eq!(size_of::<struct_param::Visible<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<struct_param::Cloaked<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<struct_param::Transparent<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<struct_param::Shadowy<NonZeroU16>>(), 2);
-
-    assert_eq!(size_of::<enum_inline::Visible1>(),    2);
-    assert_eq!(size_of::<enum_inline::Cloaked1>(),    2);
-    assert_eq!(size_of::<enum_inline::Transparent>(), 2); // transparent enums are univariant
-    assert_eq!(size_of::<enum_inline::Shadowy>(),     2);
-    assert_eq!(size_of::<enum_inline::Visible2>(),    4);
-    assert_eq!(size_of::<enum_inline::Cloaked2>(),    4);
-
-    assert_eq!(size_of::<enum_param::Visible1<NonZeroU16>>(),    2);
-    assert_eq!(size_of::<enum_param::Cloaked1<NonZeroU16>>(),    2);
-    assert_eq!(size_of::<enum_param::Transparent<NonZeroU16>>(), 2);
-    assert_eq!(size_of::<enum_param::Shadowy<NonZeroU16>>(),     2);
-    assert_eq!(size_of::<enum_param::Visible2<NonZeroU8>>(),     4);
-    assert_eq!(size_of::<enum_param::Cloaked2<NonZeroU8>>(),     4);
-
-    // now the actual tests of no_niche: how do inputs above compose
-    // with `Option` type constructor. The cases with a `_+2` are the
-    // ones where no_niche fires.
-    assert_eq!(size_of::<Option<struct_inline::Visible>>(),       2);
-    assert_eq!(size_of::<Option<struct_inline::Cloaked>>(),       2+2);
-    assert_eq!(size_of::<Option<struct_inline::Transparent>>(),   2);
-    assert_eq!(size_of::<Option<struct_inline::Shadowy>>(),       2+2);
-
-    assert_eq!(size_of::<Option<struct_param::Visible<NonZeroU16>>>(),     2);
-    assert_eq!(size_of::<Option<struct_param::Cloaked<NonZeroU16>>>(),     2+2);
-    assert_eq!(size_of::<Option<struct_param::Transparent<NonZeroU16>>>(), 2);
-    assert_eq!(size_of::<Option<struct_param::Shadowy<NonZeroU16>>>(),     2+2);
-
-    assert_eq!(size_of::<Option<enum_inline::Visible1>>(),    2);
-    assert_eq!(size_of::<Option<enum_inline::Cloaked1>>(),    2+2);
-    assert_eq!(size_of::<Option<enum_inline::Transparent>>(), 2);
-    assert_eq!(size_of::<Option<enum_inline::Shadowy>>(),     2+2);
-    // cannot use niche of multivariant payload
-    assert_eq!(size_of::<Option<enum_inline::Visible2>>(),    4+2);
-    assert_eq!(size_of::<Option<enum_inline::Cloaked2>>(),    4+2);
-
-    assert_eq!(size_of::<Option<enum_param::Visible1<NonZeroU16>>>(),    2);
-    assert_eq!(size_of::<Option<enum_param::Cloaked1<NonZeroU16>>>(),    2+2);
-    assert_eq!(size_of::<Option<enum_param::Transparent<NonZeroU16>>>(), 2);
-    assert_eq!(size_of::<Option<enum_param::Shadowy<NonZeroU16>>>(),     2+2);
-    // cannot use niche of multivariant payload
-    assert_eq!(size_of::<Option<enum_param::Visible2<NonZeroU8>>>(),    4+2);
-    assert_eq!(size_of::<Option<enum_param::Cloaked2<NonZeroU8>>>(),    4+2);
-}
-
-macro two_fifty_six_variant_enum {
-    ($(#[$attr:meta])* $name:ident<$param:ident>) => {
-        #[derive(Debug)] $(#[$attr])*
-        pub enum $name<$param> {
-            _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
-            _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
-            _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param),
-            _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param),
-
-            _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param),
-            _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param),
-            _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param),
-            _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param),
-
-            _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param),
-            _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param),
-            _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param),
-            _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param),
-
-            _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param),
-            _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param),
-            _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param),
-            _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param),
-
-            _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param),
-            _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param),
-            _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param),
-            _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param),
-
-            _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param),
-            _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param),
-            _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param),
-            _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param),
-
-            _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param),
-            _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param),
-            _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param),
-            _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param),
-
-            _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param),
-            _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param),
-            _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param),
-            _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param),
-
-            _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param),
-            _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param),
-            _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param),
-            _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param),
-
-            _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param),
-            _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param),
-            _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param),
-            _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param),
-
-            _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param),
-            _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param),
-            _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param),
-            _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param),
-
-            _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param),
-            _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param),
-            _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param),
-            _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param),
-
-            _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param),
-            _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param),
-            _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param),
-            _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param),
-
-            _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param),
-            _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param),
-            _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param),
-            _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param),
-
-            _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param),
-            _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param),
-            _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param),
-            _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param),
-
-            _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param),
-            _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param),
-            _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param),
-            _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param),
-        }
-    },
-
-    ($(#[$attr:meta])* $name:ident, $param:ty) => {
-        #[derive(Debug)] $(#[$attr])*
-        pub enum $name {
-            _V00($param, u16), _V01(u16, $param), _V02($param, u16), _V03(u16, $param),
-            _V04($param, u16), _V05(u16, $param), _V06($param, u16), _V07(u16, $param),
-            _V08($param, u16), _V09(u16, $param), _V0a($param, u16), _V0b(u16, $param),
-            _V0c($param, u16), _V0d(u16, $param), _V0e($param, u16), _V0f(u16, $param),
-
-            _V10($param, u16), _V11(u16, $param), _V12($param, u16), _V13(u16, $param),
-            _V14($param, u16), _V15(u16, $param), _V16($param, u16), _V17(u16, $param),
-            _V18($param, u16), _V19(u16, $param), _V1a($param, u16), _V1b(u16, $param),
-            _V1c($param, u16), _V1d(u16, $param), _V1e($param, u16), _V1f(u16, $param),
-
-            _V20($param, u16), _V21(u16, $param), _V22($param, u16), _V23(u16, $param),
-            _V24($param, u16), _V25(u16, $param), _V26($param, u16), _V27(u16, $param),
-            _V28($param, u16), _V29(u16, $param), _V2a($param, u16), _V2b(u16, $param),
-            _V2c($param, u16), _V2d(u16, $param), _V2e($param, u16), _V2f(u16, $param),
-
-            _V30($param, u16), _V31(u16, $param), _V32($param, u16), _V33(u16, $param),
-            _V34($param, u16), _V35(u16, $param), _V36($param, u16), _V37(u16, $param),
-            _V38($param, u16), _V39(u16, $param), _V3a($param, u16), _V3b(u16, $param),
-            _V3c($param, u16), _V3d(u16, $param), _V3e($param, u16), _V3f(u16, $param),
-
-            _V40($param, u16), _V41(u16, $param), _V42($param, u16), _V43(u16, $param),
-            _V44($param, u16), _V45(u16, $param), _V46($param, u16), _V47(u16, $param),
-            _V48($param, u16), _V49(u16, $param), _V4a($param, u16), _V4b(u16, $param),
-            _V4c($param, u16), _V4d(u16, $param), _V4e($param, u16), _V4f(u16, $param),
-
-            _V50($param, u16), _V51(u16, $param), _V52($param, u16), _V53(u16, $param),
-            _V54($param, u16), _V55(u16, $param), _V56($param, u16), _V57(u16, $param),
-            _V58($param, u16), _V59(u16, $param), _V5a($param, u16), _V5b(u16, $param),
-            _V5c($param, u16), _V5d(u16, $param), _V5e($param, u16), _V5f(u16, $param),
-
-            _V60($param, u16), _V61(u16, $param), _V62($param, u16), _V63(u16, $param),
-            _V64($param, u16), _V65(u16, $param), _V66($param, u16), _V67(u16, $param),
-            _V68($param, u16), _V69(u16, $param), _V6a($param, u16), _V6b(u16, $param),
-            _V6c($param, u16), _V6d(u16, $param), _V6e($param, u16), _V6f(u16, $param),
-
-            _V70($param, u16), _V71(u16, $param), _V72($param, u16), _V73(u16, $param),
-            _V74($param, u16), _V75(u16, $param), _V76($param, u16), _V77(u16, $param),
-            _V78($param, u16), _V79(u16, $param), _V7a($param, u16), _V7b(u16, $param),
-            _V7c($param, u16), _V7d(u16, $param), _V7e($param, u16), _V7f(u16, $param),
-
-            _V80($param, u16), _V81(u16, $param), _V82($param, u16), _V83(u16, $param),
-            _V84($param, u16), _V85(u16, $param), _V86($param, u16), _V87(u16, $param),
-            _V88($param, u16), _V89(u16, $param), _V8a($param, u16), _V8b(u16, $param),
-            _V8c($param, u16), _V8d(u16, $param), _V8e($param, u16), _V8f(u16, $param),
-
-            _V90($param, u16), _V91(u16, $param), _V92($param, u16), _V93(u16, $param),
-            _V94($param, u16), _V95(u16, $param), _V96($param, u16), _V97(u16, $param),
-            _V98($param, u16), _V99(u16, $param), _V9a($param, u16), _V9b(u16, $param),
-            _V9c($param, u16), _V9d(u16, $param), _V9e($param, u16), _V9f(u16, $param),
-
-            _Va0($param, u16), _Va1(u16, $param), _Va2($param, u16), _Va3(u16, $param),
-            _Va4($param, u16), _Va5(u16, $param), _Va6($param, u16), _Va7(u16, $param),
-            _Va8($param, u16), _Va9(u16, $param), _Vaa($param, u16), _Vab(u16, $param),
-            _Vac($param, u16), _Vad(u16, $param), _Vae($param, u16), _Vaf(u16, $param),
-
-            _Vb0($param, u16), _Vb1(u16, $param), _Vb2($param, u16), _Vb3(u16, $param),
-            _Vb4($param, u16), _Vb5(u16, $param), _Vb6($param, u16), _Vb7(u16, $param),
-            _Vb8($param, u16), _Vb9(u16, $param), _Vba($param, u16), _Vbb(u16, $param),
-            _Vbc($param, u16), _Vbd(u16, $param), _Vbe($param, u16), _Vbf(u16, $param),
-
-            _Vc0($param, u16), _Vc1(u16, $param), _Vc2($param, u16), _Vc3(u16, $param),
-            _Vc4($param, u16), _Vc5(u16, $param), _Vc6($param, u16), _Vc7(u16, $param),
-            _Vc8($param, u16), _Vc9(u16, $param), _Vca($param, u16), _Vcb(u16, $param),
-            _Vcc($param, u16), _Vcd(u16, $param), _Vce($param, u16), _Vcf(u16, $param),
-
-            _Vd0($param, u16), _Vd1(u16, $param), _Vd2($param, u16), _Vd3(u16, $param),
-            _Vd4($param, u16), _Vd5(u16, $param), _Vd6($param, u16), _Vd7(u16, $param),
-            _Vd8($param, u16), _Vd9(u16, $param), _Vda($param, u16), _Vdb(u16, $param),
-            _Vdc($param, u16), _Vdd(u16, $param), _Vde($param, u16), _Vdf(u16, $param),
-
-            _Ve0($param, u16), _Ve1(u16, $param), _Ve2($param, u16), _Ve3(u16, $param),
-            _Ve4($param, u16), _Ve5(u16, $param), _Ve6($param, u16), _Ve7(u16, $param),
-            _Ve8($param, u16), _Ve9(u16, $param), _Vea($param, u16), _Veb(u16, $param),
-            _Vec($param, u16), _Ved(u16, $param), _Vee($param, u16), _Vef(u16, $param),
-
-            _Vf0($param, u16), _Vf1(u16, $param), _Vf2($param, u16), _Vf3(u16, $param),
-            _Vf4($param, u16), _Vf5(u16, $param), _Vf6($param, u16), _Vf7(u16, $param),
-            _Vf8($param, u16), _Vf9(u16, $param), _Vfa($param, u16), _Vfb(u16, $param),
-            _Vfc($param, u16), _Vfd(u16, $param), _Vfe($param, u16), _Vff(u16, $param),
-        }
-    }
-}
diff --git a/src/test/ui/repr/repr-packed-contains-align.rs b/src/test/ui/repr/repr-packed-contains-align.rs
index 67d87eb5cd520..bef5c7d8c62fc 100644
--- a/src/test/ui/repr/repr-packed-contains-align.rs
+++ b/src/test/ui/repr/repr-packed-contains-align.rs
@@ -1,16 +1,19 @@
-#![feature(untagged_unions)]
 #![allow(dead_code)]
 
 #[repr(align(16))]
+#[derive(Clone, Copy)]
 struct SA(i32);
 
+#[derive(Clone, Copy)]
 struct SB(SA);
 
 #[repr(align(16))]
+#[derive(Clone, Copy)]
 union UA {
     i: i32
 }
 
+#[derive(Clone, Copy)]
 union UB {
     a: UA
 }
diff --git a/src/test/ui/repr/repr-packed-contains-align.stderr b/src/test/ui/repr/repr-packed-contains-align.stderr
index 531004e8e202b..4c3a960cad2a6 100644
--- a/src/test/ui/repr/repr-packed-contains-align.stderr
+++ b/src/test/ui/repr/repr-packed-contains-align.stderr
@@ -1,5 +1,5 @@
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:19:1
+  --> $DIR/repr-packed-contains-align.rs:22:1
    |
 LL | struct SC(SA);
    | ^^^^^^^^^
@@ -11,7 +11,7 @@ LL | struct SA(i32);
    | ^^^^^^^^^
 
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:22:1
+  --> $DIR/repr-packed-contains-align.rs:25:1
    |
 LL | struct SD(SB);
    | ^^^^^^^^^
@@ -22,86 +22,86 @@ note: `SA` has a `#[repr(align)]` attribute
 LL | struct SA(i32);
    | ^^^^^^^^^
 note: `SD` contains a field of type `SB`
-  --> $DIR/repr-packed-contains-align.rs:22:11
+  --> $DIR/repr-packed-contains-align.rs:25:11
    |
 LL | struct SD(SB);
    |           ^^
 note: ...which contains a field of type `SA`
-  --> $DIR/repr-packed-contains-align.rs:7:11
+  --> $DIR/repr-packed-contains-align.rs:8:11
    |
 LL | struct SB(SA);
    |           ^^
 
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:25:1
+  --> $DIR/repr-packed-contains-align.rs:28:1
    |
 LL | struct SE(UA);
    | ^^^^^^^^^
    |
 note: `UA` has a `#[repr(align)]` attribute
-  --> $DIR/repr-packed-contains-align.rs:10:1
+  --> $DIR/repr-packed-contains-align.rs:12:1
    |
 LL | union UA {
    | ^^^^^^^^
 
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:28:1
+  --> $DIR/repr-packed-contains-align.rs:31:1
    |
 LL | struct SF(UB);
    | ^^^^^^^^^
    |
 note: `UA` has a `#[repr(align)]` attribute
-  --> $DIR/repr-packed-contains-align.rs:10:1
+  --> $DIR/repr-packed-contains-align.rs:12:1
    |
 LL | union UA {
    | ^^^^^^^^
 note: `SF` contains a field of type `UB`
-  --> $DIR/repr-packed-contains-align.rs:28:11
+  --> $DIR/repr-packed-contains-align.rs:31:11
    |
 LL | struct SF(UB);
    |           ^^
 note: ...which contains a field of type `UA`
-  --> $DIR/repr-packed-contains-align.rs:15:5
+  --> $DIR/repr-packed-contains-align.rs:18:5
    |
 LL |     a: UA
    |     ^
 
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:31:1
+  --> $DIR/repr-packed-contains-align.rs:34:1
    |
 LL | union UC {
    | ^^^^^^^^
    |
 note: `UA` has a `#[repr(align)]` attribute
-  --> $DIR/repr-packed-contains-align.rs:10:1
+  --> $DIR/repr-packed-contains-align.rs:12:1
    |
 LL | union UA {
    | ^^^^^^^^
 
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:36:1
+  --> $DIR/repr-packed-contains-align.rs:39:1
    |
 LL | union UD {
    | ^^^^^^^^
    |
 note: `UA` has a `#[repr(align)]` attribute
-  --> $DIR/repr-packed-contains-align.rs:10:1
+  --> $DIR/repr-packed-contains-align.rs:12:1
    |
 LL | union UA {
    | ^^^^^^^^
 note: `UD` contains a field of type `UB`
-  --> $DIR/repr-packed-contains-align.rs:37:5
+  --> $DIR/repr-packed-contains-align.rs:40:5
    |
 LL |     n: UB
    |     ^
 note: ...which contains a field of type `UA`
-  --> $DIR/repr-packed-contains-align.rs:15:5
+  --> $DIR/repr-packed-contains-align.rs:18:5
    |
 LL |     a: UA
    |     ^
 
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:41:1
+  --> $DIR/repr-packed-contains-align.rs:44:1
    |
 LL | union UE {
    | ^^^^^^^^
@@ -113,7 +113,7 @@ LL | struct SA(i32);
    | ^^^^^^^^^
 
 error[E0588]: packed type cannot transitively contain a `#[repr(align)]` type
-  --> $DIR/repr-packed-contains-align.rs:46:1
+  --> $DIR/repr-packed-contains-align.rs:49:1
    |
 LL | union UF {
    | ^^^^^^^^
@@ -124,12 +124,12 @@ note: `SA` has a `#[repr(align)]` attribute
 LL | struct SA(i32);
    | ^^^^^^^^^
 note: `UF` contains a field of type `SB`
-  --> $DIR/repr-packed-contains-align.rs:47:5
+  --> $DIR/repr-packed-contains-align.rs:50:5
    |
 LL |     n: SB
    |     ^
 note: ...which contains a field of type `SA`
-  --> $DIR/repr-packed-contains-align.rs:7:11
+  --> $DIR/repr-packed-contains-align.rs:8:11
    |
 LL | struct SB(SA);
    |           ^^
diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/repr-transparent-non-exhaustive.rs
new file mode 100644
index 0000000000000..9ccd8610dad47
--- /dev/null
+++ b/src/test/ui/repr/repr-transparent-non-exhaustive.rs
@@ -0,0 +1,96 @@
+#![deny(repr_transparent_external_private_fields)]
+
+// aux-build: repr-transparent-non-exhaustive.rs
+extern crate repr_transparent_non_exhaustive;
+
+use repr_transparent_non_exhaustive::{
+    Private,
+    NonExhaustive,
+    NonExhaustiveEnum,
+    NonExhaustiveVariant,
+    ExternalIndirection,
+};
+
+pub struct InternalPrivate {
+    _priv: (),
+}
+
+#[non_exhaustive]
+pub struct InternalNonExhaustive;
+
+pub struct InternalIndirection<T> {
+    x: T,
+}
+
+pub type Sized = i32;
+
+#[repr(transparent)]
+pub struct T1(Sized, InternalPrivate);
+#[repr(transparent)]
+pub struct T2(Sized, InternalNonExhaustive);
+#[repr(transparent)]
+pub struct T3(Sized, InternalIndirection<(InternalPrivate, InternalNonExhaustive)>);
+#[repr(transparent)]
+pub struct T4(Sized, ExternalIndirection<(InternalPrivate, InternalNonExhaustive)>);
+
+#[repr(transparent)]
+pub struct T5(Sized, Private);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T6(Sized, NonExhaustive);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T7(Sized, NonExhaustiveEnum);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T8(Sized, NonExhaustiveVariant);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T9(Sized, InternalIndirection<Private>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T10(Sized, InternalIndirection<NonExhaustive>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T13(Sized, ExternalIndirection<Private>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.stderr b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr
new file mode 100644
index 0000000000000..3b1e334a0cbe2
--- /dev/null
+++ b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr
@@ -0,0 +1,127 @@
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:37:22
+   |
+LL | pub struct T5(Sized, Private);
+   |                      ^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_external_private_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:42:22
+   |
+LL | pub struct T6(Sized, NonExhaustive);
+   |                      ^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:47:22
+   |
+LL | pub struct T7(Sized, NonExhaustiveEnum);
+   |                      ^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:52:22
+   |
+LL | pub struct T8(Sized, NonExhaustiveVariant);
+   |                      ^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:57:22
+   |
+LL | pub struct T9(Sized, InternalIndirection<Private>);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:62:23
+   |
+LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:67:23
+   |
+LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:72:23
+   |
+LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:77:23
+   |
+LL | pub struct T13(Sized, ExternalIndirection<Private>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:82:23
+   |
+LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:87:23
+   |
+LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:92:23
+   |
+LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: aborting due to 12 previous errors
+
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
index ea8a3c177e9d7..871208b5ba785 100644
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.rs
@@ -1,11 +1,11 @@
 #![feature(rustc_attrs)]
-#![feature(untagged_unions)]
 
 #[rustc_outlives]
 union Foo<'b, U: Copy> { //~ ERROR rustc_outlives
     bar: Bar<'b, U>
 }
 
+#[derive(Clone, Copy)]
 union Bar<'a, T: Copy> where T: 'a {
     x: &'a (),
     y: T,
diff --git a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
index 2c6d06aa8c7f5..16b64bdc29dd3 100644
--- a/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/explicit-union.stderr
@@ -1,5 +1,5 @@
 error: rustc_outlives
-  --> $DIR/explicit-union.rs:5:1
+  --> $DIR/explicit-union.rs:4:1
    |
 LL | union Foo<'b, U: Copy> {
    | ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
index 0da3cc2ba1b04..27ebd0b54db5d 100644
--- a/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.rs
@@ -1,5 +1,4 @@
 #![feature(rustc_attrs)]
-#![feature(untagged_unions)]
 
 #[rustc_outlives]
 union Foo<'a, T: Copy> { //~ ERROR rustc_outlives
@@ -7,6 +6,7 @@ union Foo<'a, T: Copy> { //~ ERROR rustc_outlives
 }
 
 // Type U needs to outlive lifetime 'b
+#[derive(Clone, Copy)]
 union Bar<'b, U: Copy> {
     field2: &'b U
 }
diff --git a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
index 0116a2a68ceb2..a785c63ce3d99 100644
--- a/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
+++ b/src/test/ui/rfc-2093-infer-outlives/nested-union.stderr
@@ -1,5 +1,5 @@
 error: rustc_outlives
-  --> $DIR/nested-union.rs:5:1
+  --> $DIR/nested-union.rs:4:1
    |
 LL | union Foo<'a, T: Copy> {
    | ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/ui/union/field_checks.rs b/src/test/ui/union/field_checks.rs
new file mode 100644
index 0000000000000..d5d1e44ac855c
--- /dev/null
+++ b/src/test/ui/union/field_checks.rs
@@ -0,0 +1,65 @@
+use std::mem::ManuallyDrop;
+
+union U1 { // OK
+    a: u8,
+}
+
+union U2<T: Copy> { // OK
+    a: T,
+}
+
+union U22<T> { // OK
+    a: ManuallyDrop<T>,
+}
+
+union U23<T> { // OK
+    a: (ManuallyDrop<T>, i32),
+}
+
+union U24<T> { // OK
+    a: [ManuallyDrop<T>; 2],
+}
+
+union U3 {
+    a: String, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U32 { // field that does not drop but is not `Copy`, either
+    a: std::cell::RefCell<i32>, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U4<T> {
+    a: T, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U5 { // Having a drop impl is OK
+    a: u8,
+}
+
+impl Drop for U5 {
+    fn drop(&mut self) {}
+}
+
+union U5Nested { // a nested union that drops is NOT OK
+    nest: U5, //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U5Nested2 { // for now we don't special-case empty arrays
+    nest: [U5; 0], //~ ERROR unions cannot contain fields that may need dropping
+}
+
+union U6 { // OK
+    s: &'static i32,
+    m: &'static mut i32,
+}
+
+union U7<T> { // OK
+    f: (&'static mut i32, ManuallyDrop<T>, i32),
+}
+
+union U8<T> { // OK
+    f1: [(&'static mut i32, i32); 8],
+    f2: [ManuallyDrop<T>; 2],
+}
+
+fn main() {}
diff --git a/src/test/ui/union/field_checks.stderr b/src/test/ui/union/field_checks.stderr
new file mode 100644
index 0000000000000..1f97e97ac6ede
--- /dev/null
+++ b/src/test/ui/union/field_checks.stderr
@@ -0,0 +1,63 @@
+error[E0740]: unions cannot contain fields that may need dropping
+  --> $DIR/field_checks.rs:24:5
+   |
+LL |     a: String,
+   |     ^^^^^^^^^
+   |
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   |
+LL |     a: std::mem::ManuallyDrop<String>,
+   |        +++++++++++++++++++++++      +
+
+error[E0740]: unions cannot contain fields that may need dropping
+  --> $DIR/field_checks.rs:28:5
+   |
+LL |     a: std::cell::RefCell<i32>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   |
+LL |     a: std::mem::ManuallyDrop<std::cell::RefCell<i32>>,
+   |        +++++++++++++++++++++++                       +
+
+error[E0740]: unions cannot contain fields that may need dropping
+  --> $DIR/field_checks.rs:32:5
+   |
+LL |     a: T,
+   |     ^^^^
+   |
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   |
+LL |     a: std::mem::ManuallyDrop<T>,
+   |        +++++++++++++++++++++++ +
+
+error[E0740]: unions cannot contain fields that may need dropping
+  --> $DIR/field_checks.rs:44:5
+   |
+LL |     nest: U5,
+   |     ^^^^^^^^
+   |
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   |
+LL |     nest: std::mem::ManuallyDrop<U5>,
+   |           +++++++++++++++++++++++  +
+
+error[E0740]: unions cannot contain fields that may need dropping
+  --> $DIR/field_checks.rs:48:5
+   |
+LL |     nest: [U5; 0],
+   |     ^^^^^^^^^^^^^
+   |
+   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
+help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
+   |
+LL |     nest: std::mem::ManuallyDrop<[U5; 0]>,
+   |           +++++++++++++++++++++++       +
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/union/issue-41073.rs b/src/test/ui/union/issue-41073.rs
index 80474b807e7f3..4dfdc606bb409 100644
--- a/src/test/ui/union/issue-41073.rs
+++ b/src/test/ui/union/issue-41073.rs
@@ -1,5 +1,3 @@
-#![feature(untagged_unions)]
-
 union Test {
     a: A, //~ ERROR unions cannot contain fields that may need dropping
     b: B
diff --git a/src/test/ui/union/issue-41073.stderr b/src/test/ui/union/issue-41073.stderr
index 7d4208b10da80..b3887fa0f90be 100644
--- a/src/test/ui/union/issue-41073.stderr
+++ b/src/test/ui/union/issue-41073.stderr
@@ -1,5 +1,5 @@
 error[E0740]: unions cannot contain fields that may need dropping
-  --> $DIR/issue-41073.rs:4:5
+  --> $DIR/issue-41073.rs:2:5
    |
 LL |     a: A,
    |     ^^^^
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr
index e785a2ee7335d..ca02de4c61bb8 100644
--- a/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.mirunsafeck.stderr
@@ -1,49 +1,69 @@
-error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
   --> $DIR/union-borrow-move-parent-sibling.rs:56:13
    |
-LL |     let a = &mut u.x.0;
-   |             ---------- mutable borrow occurs here (via `u.x.0`)
+LL |     let a = &mut (*u.x).0;
+   |                    --- mutable borrow occurs here (via `u.x`)
 LL |     let b = &u.y;
-   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here
+   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
 LL |     use_borrow(a);
    |                - mutable borrow later used here
    |
-   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
+   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
+
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
+  --> $DIR/union-borrow-move-parent-sibling.rs:62:13
+   |
+LL |     let a = u.x.0;
+   |             ^^^^^
+   |             |
+   |             move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
+   |             help: consider borrowing here: `&u.x.0`
 
 error[E0382]: use of moved value: `u`
-  --> $DIR/union-borrow-move-parent-sibling.rs:63:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:64:13
    |
-LL |     let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+LL |     let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
    |         - move occurs because `u` has type `U`, which does not implement the `Copy` trait
 LL |     let a = u.x.0;
-   |             ----- value moved here
+LL |     let a = u.x;
+   |             --- value moved here
 LL |     let b = u.y;
    |             ^^^ value used here after move
 
-error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
-  --> $DIR/union-borrow-move-parent-sibling.rs:69:13
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
+  --> $DIR/union-borrow-move-parent-sibling.rs:70:13
    |
-LL |     let a = &mut (u.x.0).0;
-   |             -------------- mutable borrow occurs here (via `u.x.0.0`)
+LL |     let a = &mut ((*u.x).0).0;
+   |                     --- mutable borrow occurs here (via `u.x`)
 LL |     let b = &u.y;
-   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here
+   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
 LL |     use_borrow(a);
    |                - mutable borrow later used here
    |
-   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
+   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
 
-error[E0382]: use of moved value: `u`
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
   --> $DIR/union-borrow-move-parent-sibling.rs:76:13
    |
-LL |     let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+LL |     let a = (u.x.0).0;
+   |             ^^^^^^^^^
+   |             |
+   |             move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
+   |             help: consider borrowing here: `&(u.x.0).0`
+
+error[E0382]: use of moved value: `u`
+  --> $DIR/union-borrow-move-parent-sibling.rs:78:13
+   |
+LL |     let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
    |         - move occurs because `u` has type `U`, which does not implement the `Copy` trait
 LL |     let a = (u.x.0).0;
-   |             --------- value moved here
+LL |     let a = u.x;
+   |             --- value moved here
 LL |     let b = u.y;
    |             ^^^ value used here after move
 
 error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
-  --> $DIR/union-borrow-move-parent-sibling.rs:82:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:84:13
    |
 LL |     let a = &mut *u.y;
    |                   --- mutable borrow occurs here (via `u.y`)
@@ -54,7 +74,7 @@ LL |     use_borrow(a);
    |
    = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0382, E0502.
+Some errors have detailed explanations: E0382, E0502, E0507.
 For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.rs b/src/test/ui/union/union-borrow-move-parent-sibling.rs
index e56d87255dbaf..83781c5e55092 100644
--- a/src/test/ui/union/union-borrow-move-parent-sibling.rs
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.rs
@@ -1,10 +1,10 @@
 // revisions: mirunsafeck thirunsafeck
 // [thirunsafeck]compile-flags: -Z thir-unsafeck
 
-#![feature(untagged_unions)]
 #![allow(unused)]
 
 use std::ops::{Deref, DerefMut};
+use std::mem::ManuallyDrop;
 
 #[derive(Default)]
 struct MockBox<T> {
@@ -44,47 +44,49 @@ impl<T> DerefMut for MockVec<T> {
 
 
 union U {
-    x: ((MockVec<u8>, MockVec<u8>), MockVec<u8>),
-    y: MockBox<MockVec<u8>>,
+    x: ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>,
+    y: ManuallyDrop<MockBox<MockVec<u8>>>,
 }
 
 fn use_borrow<T>(_: &T) {}
 
 unsafe fn parent_sibling_borrow() {
-    let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
-    let a = &mut u.x.0;
+    let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+    let a = &mut (*u.x).0;
     let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`)
     use_borrow(a);
 }
 
 unsafe fn parent_sibling_move() {
-    let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
-    let a = u.x.0;
+    let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+    let a = u.x.0; //~ERROR cannot move out of dereference
+    let a = u.x;
     let b = u.y; //~ ERROR use of moved value: `u`
 }
 
 unsafe fn grandparent_sibling_borrow() {
-    let mut u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
-    let a = &mut (u.x.0).0;
+    let mut u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+    let a = &mut ((*u.x).0).0;
     let b = &u.y; //~ ERROR cannot borrow `u` (via `u.y`)
     use_borrow(a);
 }
 
 unsafe fn grandparent_sibling_move() {
-    let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
-    let a = (u.x.0).0;
+    let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
+    let a = (u.x.0).0; //~ERROR cannot move out of dereference
+    let a = u.x;
     let b = u.y; //~ ERROR use of moved value: `u`
 }
 
 unsafe fn deref_sibling_borrow() {
-    let mut u = U { y: MockBox::default() };
+    let mut u = U { y: ManuallyDrop::new(MockBox::default()) };
     let a = &mut *u.y;
     let b = &u.x; //~ ERROR cannot borrow `u` (via `u.x`)
     use_borrow(a);
 }
 
 unsafe fn deref_sibling_move() {
-    let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+    let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
     // No way to test deref-move without Box in union
     // let a = *u.y;
     // let b = u.x; ERROR use of moved value: `u`
diff --git a/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr
index e785a2ee7335d..ca02de4c61bb8 100644
--- a/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr
+++ b/src/test/ui/union/union-borrow-move-parent-sibling.thirunsafeck.stderr
@@ -1,49 +1,69 @@
-error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0`)
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
   --> $DIR/union-borrow-move-parent-sibling.rs:56:13
    |
-LL |     let a = &mut u.x.0;
-   |             ---------- mutable borrow occurs here (via `u.x.0`)
+LL |     let a = &mut (*u.x).0;
+   |                    --- mutable borrow occurs here (via `u.x`)
 LL |     let b = &u.y;
-   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0` -- occurs here
+   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
 LL |     use_borrow(a);
    |                - mutable borrow later used here
    |
-   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0`
+   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
+
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
+  --> $DIR/union-borrow-move-parent-sibling.rs:62:13
+   |
+LL |     let a = u.x.0;
+   |             ^^^^^
+   |             |
+   |             move occurs because value has type `(MockVec<u8>, MockVec<u8>)`, which does not implement the `Copy` trait
+   |             help: consider borrowing here: `&u.x.0`
 
 error[E0382]: use of moved value: `u`
-  --> $DIR/union-borrow-move-parent-sibling.rs:63:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:64:13
    |
-LL |     let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+LL |     let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
    |         - move occurs because `u` has type `U`, which does not implement the `Copy` trait
 LL |     let a = u.x.0;
-   |             ----- value moved here
+LL |     let a = u.x;
+   |             --- value moved here
 LL |     let b = u.y;
    |             ^^^ value used here after move
 
-error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x.0.0`)
-  --> $DIR/union-borrow-move-parent-sibling.rs:69:13
+error[E0502]: cannot borrow `u` (via `u.y`) as immutable because it is also borrowed as mutable (via `u.x`)
+  --> $DIR/union-borrow-move-parent-sibling.rs:70:13
    |
-LL |     let a = &mut (u.x.0).0;
-   |             -------------- mutable borrow occurs here (via `u.x.0.0`)
+LL |     let a = &mut ((*u.x).0).0;
+   |                     --- mutable borrow occurs here (via `u.x`)
 LL |     let b = &u.y;
-   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x.0.0` -- occurs here
+   |             ^^^^ immutable borrow of `u.y` -- which overlaps with `u.x` -- occurs here
 LL |     use_borrow(a);
    |                - mutable borrow later used here
    |
-   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x.0.0`
+   = note: `u.y` is a field of the union `U`, so it overlaps the field `u.x`
 
-error[E0382]: use of moved value: `u`
+error[E0507]: cannot move out of dereference of `ManuallyDrop<((MockVec<u8>, MockVec<u8>), MockVec<u8>)>`
   --> $DIR/union-borrow-move-parent-sibling.rs:76:13
    |
-LL |     let u = U { x: ((MockVec::new(), MockVec::new()), MockVec::new()) };
+LL |     let a = (u.x.0).0;
+   |             ^^^^^^^^^
+   |             |
+   |             move occurs because value has type `MockVec<u8>`, which does not implement the `Copy` trait
+   |             help: consider borrowing here: `&(u.x.0).0`
+
+error[E0382]: use of moved value: `u`
+  --> $DIR/union-borrow-move-parent-sibling.rs:78:13
+   |
+LL |     let u = U { x: ManuallyDrop::new(((MockVec::new(), MockVec::new()), MockVec::new())) };
    |         - move occurs because `u` has type `U`, which does not implement the `Copy` trait
 LL |     let a = (u.x.0).0;
-   |             --------- value moved here
+LL |     let a = u.x;
+   |             --- value moved here
 LL |     let b = u.y;
    |             ^^^ value used here after move
 
 error[E0502]: cannot borrow `u` (via `u.x`) as immutable because it is also borrowed as mutable (via `u.y`)
-  --> $DIR/union-borrow-move-parent-sibling.rs:82:13
+  --> $DIR/union-borrow-move-parent-sibling.rs:84:13
    |
 LL |     let a = &mut *u.y;
    |                   --- mutable borrow occurs here (via `u.y`)
@@ -54,7 +74,7 @@ LL |     use_borrow(a);
    |
    = note: `u.x` is a field of the union `U`, so it overlaps the field `u.y`
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0382, E0502.
+Some errors have detailed explanations: E0382, E0502, E0507.
 For more information about an error, try `rustc --explain E0382`.
diff --git a/src/test/ui/union/union-custom-drop.rs b/src/test/ui/union/union-custom-drop.rs
deleted file mode 100644
index 4b333631ec0f7..0000000000000
--- a/src/test/ui/union/union-custom-drop.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// test for a union with a field that's a union with a manual impl Drop
-// Ensures we do not treat all unions as not having any drop glue.
-
-#![feature(untagged_unions)]
-
-union Foo {
-    bar: Bar, //~ ERROR unions cannot contain fields that may need dropping
-}
-
-union Bar {
-    a: i32,
-    b: u32,
-}
-
-impl Drop for Bar {
-    fn drop(&mut self) {}
-}
-
-fn main() {}
diff --git a/src/test/ui/union/union-custom-drop.stderr b/src/test/ui/union/union-custom-drop.stderr
deleted file mode 100644
index b5579eeef0977..0000000000000
--- a/src/test/ui/union/union-custom-drop.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0740]: unions cannot contain fields that may need dropping
-  --> $DIR/union-custom-drop.rs:7:5
-   |
-LL |     bar: Bar,
-   |     ^^^^^^^^
-   |
-   = note: a type is guaranteed not to need dropping when it implements `Copy`, or when it is the special `ManuallyDrop<_>` type
-help: when the type does not implement `Copy`, wrap it inside a `ManuallyDrop<_>` and ensure it is manually dropped
-   |
-LL |     bar: std::mem::ManuallyDrop<Bar>,
-   |          +++++++++++++++++++++++   +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0740`.
diff --git a/src/test/ui/union/union-deref.mirunsafeck.stderr b/src/test/ui/union/union-deref.mirunsafeck.stderr
index ff37e6fd9177a..be5e60ab88a59 100644
--- a/src/test/ui/union/union-deref.mirunsafeck.stderr
+++ b/src/test/ui/union/union-deref.mirunsafeck.stderr
@@ -1,5 +1,5 @@
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:17:14
+  --> $DIR/union-deref.rs:16:14
    |
 LL |     unsafe { u.f.0 = Vec::new() };
    |              ^^^
@@ -8,7 +8,7 @@ LL |     unsafe { u.f.0 = Vec::new() };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:19:19
+  --> $DIR/union-deref.rs:18:19
    |
 LL |     unsafe { &mut u.f.0 };
    |                   ^^^
@@ -17,7 +17,7 @@ LL |     unsafe { &mut u.f.0 };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:21:14
+  --> $DIR/union-deref.rs:20:14
    |
 LL |     unsafe { u.f.0.push(0) };
    |              ^^^
@@ -26,7 +26,7 @@ LL |     unsafe { u.f.0.push(0) };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:25:14
+  --> $DIR/union-deref.rs:24:14
    |
 LL |     unsafe { u.f.0.0 = Vec::new() };
    |              ^^^^^
@@ -35,7 +35,7 @@ LL |     unsafe { u.f.0.0 = Vec::new() };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:27:19
+  --> $DIR/union-deref.rs:26:19
    |
 LL |     unsafe { &mut u.f.0.0 };
    |                   ^^^^^
@@ -44,7 +44,7 @@ LL |     unsafe { &mut u.f.0.0 };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:29:14
+  --> $DIR/union-deref.rs:28:14
    |
 LL |     unsafe { u.f.0.0.push(0) };
    |              ^^^^^
diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs
index 4bf2ba2f1bfce..5aa28d93f96ed 100644
--- a/src/test/ui/union/union-deref.rs
+++ b/src/test/ui/union/union-deref.rs
@@ -3,7 +3,6 @@
 
 //! Test the part of RFC 2514 that is about not applying `DerefMut` coercions
 //! of union fields.
-#![feature(untagged_unions)]
 
 use std::mem::ManuallyDrop;
 
diff --git a/src/test/ui/union/union-deref.thirunsafeck.stderr b/src/test/ui/union/union-deref.thirunsafeck.stderr
index ff37e6fd9177a..be5e60ab88a59 100644
--- a/src/test/ui/union/union-deref.thirunsafeck.stderr
+++ b/src/test/ui/union/union-deref.thirunsafeck.stderr
@@ -1,5 +1,5 @@
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:17:14
+  --> $DIR/union-deref.rs:16:14
    |
 LL |     unsafe { u.f.0 = Vec::new() };
    |              ^^^
@@ -8,7 +8,7 @@ LL |     unsafe { u.f.0 = Vec::new() };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:19:19
+  --> $DIR/union-deref.rs:18:19
    |
 LL |     unsafe { &mut u.f.0 };
    |                   ^^^
@@ -17,7 +17,7 @@ LL |     unsafe { &mut u.f.0 };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:21:14
+  --> $DIR/union-deref.rs:20:14
    |
 LL |     unsafe { u.f.0.push(0) };
    |              ^^^
@@ -26,7 +26,7 @@ LL |     unsafe { u.f.0.push(0) };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:25:14
+  --> $DIR/union-deref.rs:24:14
    |
 LL |     unsafe { u.f.0.0 = Vec::new() };
    |              ^^^^^
@@ -35,7 +35,7 @@ LL |     unsafe { u.f.0.0 = Vec::new() };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:27:19
+  --> $DIR/union-deref.rs:26:19
    |
 LL |     unsafe { &mut u.f.0.0 };
    |                   ^^^^^
@@ -44,7 +44,7 @@ LL |     unsafe { &mut u.f.0.0 };
    = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
 
 error: not automatically applying `DerefMut` on `ManuallyDrop` union field
-  --> $DIR/union-deref.rs:29:14
+  --> $DIR/union-deref.rs:28:14
    |
 LL |     unsafe { u.f.0.0.push(0) };
    |              ^^^^^
diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr
index f55fbea6336e3..53050cf539eaf 100644
--- a/src/test/ui/union/union-move.mirunsafeck.stderr
+++ b/src/test/ui/union/union-move.mirunsafeck.stderr
@@ -27,7 +27,7 @@ LL |         move_out(x.f1_nocopy);
    |                  ^^^^^^^^^^^
    |                  |
    |                  cannot move out of here
-   |                  move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait
+   |                  move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs
index 8f78c30d67a55..b8b1ac8046a03 100644
--- a/src/test/ui/union/union-move.rs
+++ b/src/test/ui/union/union-move.rs
@@ -3,20 +3,20 @@
 
 //! Test the behavior of moving out of non-`Copy` union fields.
 //! Avoid types that `Drop`, we want to focus on moving.
-#![feature(untagged_unions)]
 
 use std::cell::RefCell;
+use std::mem::ManuallyDrop;
 
 fn move_out<T>(x: T) {}
 
 union U1 {
-    f1_nocopy: RefCell<i32>,
-    f2_nocopy: RefCell<i32>,
+    f1_nocopy: ManuallyDrop<RefCell<i32>>,
+    f2_nocopy: ManuallyDrop<RefCell<i32>>,
     f3_copy: i32,
 }
 
 union U2 {
-    f1_nocopy: RefCell<i32>,
+    f1_nocopy: ManuallyDrop<RefCell<i32>>,
 }
 impl Drop for U2 {
     fn drop(&mut self) {}
diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr
index f55fbea6336e3..53050cf539eaf 100644
--- a/src/test/ui/union/union-move.thirunsafeck.stderr
+++ b/src/test/ui/union/union-move.thirunsafeck.stderr
@@ -27,7 +27,7 @@ LL |         move_out(x.f1_nocopy);
    |                  ^^^^^^^^^^^
    |                  |
    |                  cannot move out of here
-   |                  move occurs because `x.f1_nocopy` has type `RefCell<i32>`, which does not implement the `Copy` trait
+   |                  move occurs because `x.f1_nocopy` has type `ManuallyDrop<RefCell<i32>>`, which does not implement the `Copy` trait
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/union/union-nonrepresentable.rs b/src/test/ui/union/union-nonrepresentable.rs
index 4dbd97ea957ba..4bdf7c6872fa5 100644
--- a/src/test/ui/union/union-nonrepresentable.rs
+++ b/src/test/ui/union/union-nonrepresentable.rs
@@ -1,8 +1,6 @@
-#![feature(untagged_unions)]
-
 union U { //~ ERROR recursive type `U` has infinite size
     a: u8,
-    b: U,
+    b: std::mem::ManuallyDrop<U>,
 }
 
 fn main() {}
diff --git a/src/test/ui/union/union-nonrepresentable.stderr b/src/test/ui/union/union-nonrepresentable.stderr
index 7da7c870e704b..9804b1418b208 100644
--- a/src/test/ui/union/union-nonrepresentable.stderr
+++ b/src/test/ui/union/union-nonrepresentable.stderr
@@ -1,16 +1,16 @@
 error[E0072]: recursive type `U` has infinite size
-  --> $DIR/union-nonrepresentable.rs:3:1
+  --> $DIR/union-nonrepresentable.rs:1:1
    |
 LL | union U {
    | ^^^^^^^ recursive type has infinite size
 LL |     a: u8,
-LL |     b: U,
-   |        - recursive without indirection
+LL |     b: std::mem::ManuallyDrop<U>,
+   |        ------------------------- recursive without indirection
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `U` representable
    |
-LL |     b: Box<U>,
-   |        ++++ +
+LL |     b: Box<std::mem::ManuallyDrop<U>>,
+   |        ++++                         +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/union/union-sized-field.rs b/src/test/ui/union/union-sized-field.rs
index b84cb3eff56f6..cb852eff0c60a 100644
--- a/src/test/ui/union/union-sized-field.rs
+++ b/src/test/ui/union/union-sized-field.rs
@@ -1,18 +1,18 @@
-#![feature(untagged_unions)]
+use std::mem::ManuallyDrop;
 
 union Foo<T: ?Sized> {
-    value: T,
+    value: ManuallyDrop<T>,
     //~^ ERROR the size for values of type
 }
 
 struct Foo2<T: ?Sized> {
-    value: T,
+    value: ManuallyDrop<T>,
     //~^ ERROR the size for values of type
     t: u32,
 }
 
 enum Foo3<T: ?Sized> {
-    Value(T),
+    Value(ManuallyDrop<T>),
     //~^ ERROR the size for values of type
 }
 
diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr
index 3fe6e71f3b863..771e8f2619995 100644
--- a/src/test/ui/union/union-sized-field.stderr
+++ b/src/test/ui/union/union-sized-field.stderr
@@ -3,9 +3,10 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim
    |
 LL | union Foo<T: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
-LL |     value: T,
-   |            ^ doesn't have a size known at compile-time
+LL |     value: ManuallyDrop<T>,
+   |            ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
+   = note: required because it appears within the type `ManuallyDrop<T>`
    = note: no field of a union may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
@@ -15,21 +16,22 @@ LL + union Foo<T> {
    |
 help: borrowed types always have a statically known size
    |
-LL |     value: &T,
+LL |     value: &ManuallyDrop<T>,
    |            +
 help: the `Box` type always has a statically known size and allocates its contents in the heap
    |
-LL |     value: Box<T>,
-   |            ++++ +
+LL |     value: Box<ManuallyDrop<T>>,
+   |            ++++               +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/union-sized-field.rs:9:12
    |
 LL | struct Foo2<T: ?Sized> {
    |             - this type parameter needs to be `std::marker::Sized`
-LL |     value: T,
-   |            ^ doesn't have a size known at compile-time
+LL |     value: ManuallyDrop<T>,
+   |            ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
+   = note: required because it appears within the type `ManuallyDrop<T>`
    = note: only the last field of a struct may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
@@ -39,21 +41,22 @@ LL + struct Foo2<T> {
    |
 help: borrowed types always have a statically known size
    |
-LL |     value: &T,
+LL |     value: &ManuallyDrop<T>,
    |            +
 help: the `Box` type always has a statically known size and allocates its contents in the heap
    |
-LL |     value: Box<T>,
-   |            ++++ +
+LL |     value: Box<ManuallyDrop<T>>,
+   |            ++++               +
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> $DIR/union-sized-field.rs:15:11
    |
 LL | enum Foo3<T: ?Sized> {
    |           - this type parameter needs to be `std::marker::Sized`
-LL |     Value(T),
-   |           ^ doesn't have a size known at compile-time
+LL |     Value(ManuallyDrop<T>),
+   |           ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
+   = note: required because it appears within the type `ManuallyDrop<T>`
    = note: no field of an enum variant may have a dynamically sized type
    = help: change the field's type to have a statically known size
 help: consider removing the `?Sized` bound to make the type parameter `Sized`
@@ -63,12 +66,12 @@ LL + enum Foo3<T> {
    |
 help: borrowed types always have a statically known size
    |
-LL |     Value(&T),
+LL |     Value(&ManuallyDrop<T>),
    |           +
 help: the `Box` type always has a statically known size and allocates its contents in the heap
    |
-LL |     Value(Box<T>),
-   |           ++++ +
+LL |     Value(Box<ManuallyDrop<T>>),
+   |           ++++               +
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/union/union-unsafe.mir.stderr b/src/test/ui/union/union-unsafe.mir.stderr
index 318b00ddea94e..544213dbc5543 100644
--- a/src/test/ui/union/union-unsafe.mir.stderr
+++ b/src/test/ui/union/union-unsafe.mir.stderr
@@ -1,29 +1,13 @@
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:34:5
+  --> $DIR/union-unsafe.rs:33:5
    |
 LL |     *(u.p) = 13;
    |     ^^^^^^^^^^^ access to union field
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:39:5
-   |
-LL |     u.a = (RefCell::new(0), 1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
-   |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:40:5
-   |
-LL |     u.a.0 = RefCell::new(0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
-   |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:47:6
+  --> $DIR/union-unsafe.rs:46:6
    |
 LL |     *u3.a = T::default();
    |      ^^^^ access to union field
@@ -31,7 +15,7 @@ LL |     *u3.a = T::default();
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:53:6
+  --> $DIR/union-unsafe.rs:52:6
    |
 LL |     *u3.a = T::default();
    |      ^^^^ access to union field
@@ -39,7 +23,7 @@ LL |     *u3.a = T::default();
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:61:13
+  --> $DIR/union-unsafe.rs:60:13
    |
 LL |     let a = u1.a;
    |             ^^^^ access to union field
@@ -47,7 +31,7 @@ LL |     let a = u1.a;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:64:14
+  --> $DIR/union-unsafe.rs:63:14
    |
 LL |     let U1 { a } = u1;
    |              ^ access to union field
@@ -55,7 +39,7 @@ LL |     let U1 { a } = u1;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:65:12
+  --> $DIR/union-unsafe.rs:64:12
    |
 LL |     if let U1 { a: 12 } = u1 {}
    |            ^^^^^^^^^^^^ access to union field
@@ -63,7 +47,7 @@ LL |     if let U1 { a: 12 } = u1 {}
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:70:6
+  --> $DIR/union-unsafe.rs:69:6
    |
 LL |     *u2.a = String::from("new");
    |      ^^^^ access to union field
@@ -71,7 +55,7 @@ LL |     *u2.a = String::from("new");
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:74:6
+  --> $DIR/union-unsafe.rs:73:6
    |
 LL |     *u3.a = 1;
    |      ^^^^ access to union field
@@ -79,13 +63,13 @@ LL |     *u3.a = 1;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:78:6
+  --> $DIR/union-unsafe.rs:77:6
    |
 LL |     *u3.a = String::from("new");
    |      ^^^^ access to union field
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error: aborting due to 11 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs
index 3cb3a18cb7544..5e1837a901d46 100644
--- a/src/test/ui/union/union-unsafe.rs
+++ b/src/test/ui/union/union-unsafe.rs
@@ -1,7 +1,6 @@
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
 
-#![feature(untagged_unions)]
 use std::mem::ManuallyDrop;
 use std::cell::RefCell;
 
@@ -26,7 +25,7 @@ union URef {
 }
 
 union URefCell { // field that does not drop but is not `Copy`, either
-    a: (RefCell<i32>, i32),
+    a: (ManuallyDrop<RefCell<i32>>, i32),
 }
 
 fn deref_union_field(mut u: URef) {
@@ -36,8 +35,8 @@ fn deref_union_field(mut u: URef) {
 
 fn assign_noncopy_union_field(mut u: URefCell) {
     // FIXME(thir-unsafeck)
-    u.a = (RefCell::new(0), 1); //~ ERROR assignment to union field that might need dropping
-    u.a.0 = RefCell::new(0); //~ ERROR assignment to union field that might need dropping
+    u.a = (ManuallyDrop::new(RefCell::new(0)), 1); // OK (assignment does not drop)
+    u.a.0 = ManuallyDrop::new(RefCell::new(0)); // OK (assignment does not drop)
     u.a.1 = 1; // OK
 }
 
diff --git a/src/test/ui/union/union-unsafe.thir.stderr b/src/test/ui/union/union-unsafe.thir.stderr
index a8c3886657f43..f959fe5bdb5c5 100644
--- a/src/test/ui/union/union-unsafe.thir.stderr
+++ b/src/test/ui/union/union-unsafe.thir.stderr
@@ -1,29 +1,13 @@
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:34:6
+  --> $DIR/union-unsafe.rs:33:6
    |
 LL |     *(u.p) = 13;
    |      ^^^^^ access to union field
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:39:5
-   |
-LL |     u.a = (RefCell::new(0), 1);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
-   |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:40:5
-   |
-LL |     u.a.0 = RefCell::new(0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
-   |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:47:6
+  --> $DIR/union-unsafe.rs:46:6
    |
 LL |     *u3.a = T::default();
    |      ^^^^ access to union field
@@ -31,7 +15,7 @@ LL |     *u3.a = T::default();
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:53:6
+  --> $DIR/union-unsafe.rs:52:6
    |
 LL |     *u3.a = T::default();
    |      ^^^^ access to union field
@@ -39,7 +23,7 @@ LL |     *u3.a = T::default();
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:61:13
+  --> $DIR/union-unsafe.rs:60:13
    |
 LL |     let a = u1.a;
    |             ^^^^ access to union field
@@ -47,7 +31,7 @@ LL |     let a = u1.a;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:64:14
+  --> $DIR/union-unsafe.rs:63:14
    |
 LL |     let U1 { a } = u1;
    |              ^ access to union field
@@ -55,7 +39,7 @@ LL |     let U1 { a } = u1;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:65:8
+  --> $DIR/union-unsafe.rs:64:8
    |
 LL |     if let U1 { a: 12 } = u1 {}
    |        ^^^^^^^^^^^^^^^^^^^^^ access to union field
@@ -63,7 +47,7 @@ LL |     if let U1 { a: 12 } = u1 {}
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:70:6
+  --> $DIR/union-unsafe.rs:69:6
    |
 LL |     *u2.a = String::from("new");
    |      ^^^^ access to union field
@@ -71,7 +55,7 @@ LL |     *u2.a = String::from("new");
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:74:6
+  --> $DIR/union-unsafe.rs:73:6
    |
 LL |     *u3.a = 1;
    |      ^^^^ access to union field
@@ -79,13 +63,13 @@ LL |     *u3.a = 1;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-unsafe.rs:78:6
+  --> $DIR/union-unsafe.rs:77:6
    |
 LL |     *u3.a = String::from("new");
    |      ^^^^ access to union field
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error: aborting due to 11 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/union/union-unsized.mirunsafeck.stderr b/src/test/ui/union/union-unsized.mirunsafeck.stderr
index 36e782ac0424d..59ab835fba22d 100644
--- a/src/test/ui/union/union-unsized.mirunsafeck.stderr
+++ b/src/test/ui/union/union-unsized.mirunsafeck.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:7:8
+  --> $DIR/union-unsized.rs:5:8
    |
 LL |     a: str,
    |        ^^^ doesn't have a size known at compile-time
@@ -17,7 +17,7 @@ LL |     a: Box<str>,
    |        ++++   +
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:15:8
+  --> $DIR/union-unsized.rs:13:8
    |
 LL |     b: str,
    |        ^^^ doesn't have a size known at compile-time
diff --git a/src/test/ui/union/union-unsized.rs b/src/test/ui/union/union-unsized.rs
index e9792f527dc71..8e897d7d3c6d6 100644
--- a/src/test/ui/union/union-unsized.rs
+++ b/src/test/ui/union/union-unsized.rs
@@ -1,8 +1,6 @@
 // revisions: mirunsafeck thirunsafeck
 // [thirunsafeck]compile-flags: -Z thir-unsafeck
 
-#![feature(untagged_unions)]
-
 union U {
     a: str,
     //~^ ERROR the size for values of type
diff --git a/src/test/ui/union/union-unsized.thirunsafeck.stderr b/src/test/ui/union/union-unsized.thirunsafeck.stderr
index 36e782ac0424d..59ab835fba22d 100644
--- a/src/test/ui/union/union-unsized.thirunsafeck.stderr
+++ b/src/test/ui/union/union-unsized.thirunsafeck.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:7:8
+  --> $DIR/union-unsized.rs:5:8
    |
 LL |     a: str,
    |        ^^^ doesn't have a size known at compile-time
@@ -17,7 +17,7 @@ LL |     a: Box<str>,
    |        ++++   +
 
 error[E0277]: the size for values of type `str` cannot be known at compilation time
-  --> $DIR/union-unsized.rs:15:8
+  --> $DIR/union-unsized.rs:13:8
    |
 LL |     b: str,
    |        ^^^ doesn't have a size known at compile-time
diff --git a/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr
index cd338ac9e3a27..0ecd5203dd9d9 100644
--- a/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr
+++ b/src/test/ui/unsafe/union-assignop.mirunsafeck.stderr
@@ -1,5 +1,5 @@
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:20:5
+  --> $DIR/union-assignop.rs:19:5
    |
 LL |     foo.a += 5;
    |     ^^^^^^^^^^ access to union field
@@ -7,20 +7,20 @@ LL |     foo.a += 5;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:21:5
+  --> $DIR/union-assignop.rs:20:6
    |
-LL |     foo.b += Dropping;
-   |     ^^^^^ access to union field
+LL |     *foo.b += NonCopy;
+   |      ^^^^^ access to union field
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:22:5
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:21:6
    |
-LL |     foo.b = Dropping;
-   |     ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+LL |     *foo.b = NonCopy;
+   |      ^^^^^ access to union field
    |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
   --> $DIR/union-assignop.rs:23:5
@@ -46,14 +46,6 @@ LL |     foo.b = foo.b;
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:27:5
-   |
-LL |     foo.b = foo.b;
-   |     ^^^^^^^^^^^^^ assignment to union field that might need dropping
-   |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/union-assignop.rs b/src/test/ui/unsafe/union-assignop.rs
index c4be20aa567b7..5e667cd10d59f 100644
--- a/src/test/ui/unsafe/union-assignop.rs
+++ b/src/test/ui/unsafe/union-assignop.rs
@@ -1,30 +1,29 @@
 // revisions: mirunsafeck thirunsafeck
 // [thirunsafeck]compile-flags: -Z thir-unsafeck
 
-#![feature(untagged_unions)]
-
 use std::ops::AddAssign;
+use std::mem::ManuallyDrop;
 
-struct Dropping;
-impl AddAssign for Dropping {
+struct NonCopy;
+impl AddAssign for NonCopy {
     fn add_assign(&mut self, _: Self) {}
 }
 
 union Foo {
     a: u8, // non-dropping
-    b: Dropping, // treated as dropping
+    b: ManuallyDrop<NonCopy>,
 }
 
 fn main() {
     let mut foo = Foo { a: 42 };
     foo.a += 5; //~ ERROR access to union field is unsafe
-    foo.b += Dropping; //~ ERROR access to union field is unsafe
-    foo.b = Dropping; //~ ERROR assignment to union field that might need dropping is unsafe
+    *foo.b += NonCopy; //~ ERROR access to union field is unsafe
+    *foo.b = NonCopy; //~ ERROR access to union field is unsafe
+    foo.b = ManuallyDrop::new(NonCopy);
     foo.a; //~ ERROR access to union field is unsafe
     let foo = Foo { a: 42 };
     foo.b; //~ ERROR access to union field is unsafe
     let mut foo = Foo { a: 42 };
     foo.b = foo.b;
     //~^ ERROR access to union field is unsafe
-    //~| ERROR assignment to union field that might need dropping
 }
diff --git a/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr b/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr
index 71de421a2553e..24b357e762bba 100644
--- a/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr
+++ b/src/test/ui/unsafe/union-assignop.thirunsafeck.stderr
@@ -1,5 +1,5 @@
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:20:5
+  --> $DIR/union-assignop.rs:19:5
    |
 LL |     foo.a += 5;
    |     ^^^^^ access to union field
@@ -7,20 +7,20 @@ LL |     foo.a += 5;
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:21:5
+  --> $DIR/union-assignop.rs:20:6
    |
-LL |     foo.b += Dropping;
-   |     ^^^^^ access to union field
+LL |     *foo.b += NonCopy;
+   |      ^^^^^ access to union field
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:22:5
+error[E0133]: access to union field is unsafe and requires unsafe function or block
+  --> $DIR/union-assignop.rs:21:6
    |
-LL |     foo.b = Dropping;
-   |     ^^^^^^^^^^^^^^^^ assignment to union field that might need dropping
+LL |     *foo.b = NonCopy;
+   |      ^^^^^ access to union field
    |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
+   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
   --> $DIR/union-assignop.rs:23:5
@@ -38,14 +38,6 @@ LL |     foo.b;
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error[E0133]: assignment to union field that might need dropping is unsafe and requires unsafe function or block
-  --> $DIR/union-assignop.rs:27:5
-   |
-LL |     foo.b = foo.b;
-   |     ^^^^^^^^^^^^^ assignment to union field that might need dropping
-   |
-   = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized
-
 error[E0133]: access to union field is unsafe and requires unsafe function or block
   --> $DIR/union-assignop.rs:27:13
    |
@@ -54,6 +46,6 @@ LL |     foo.b = foo.b;
    |
    = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior
 
-error: aborting due to 7 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0133`.
diff --git a/src/test/ui/unsafe/union-modification.rs b/src/test/ui/unsafe/union-modification.rs
index 5c70b78df7c12..9a53ef9085200 100644
--- a/src/test/ui/unsafe/union-modification.rs
+++ b/src/test/ui/unsafe/union-modification.rs
@@ -2,8 +2,6 @@
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
 
-#![feature(untagged_unions)]
-
 union Foo {
     bar: i8,
     _blah: isize,
diff --git a/src/test/ui/unsafe/union.rs b/src/test/ui/unsafe/union.rs
index 5fe09933cfc48..4338d78eabb9d 100644
--- a/src/test/ui/unsafe/union.rs
+++ b/src/test/ui/unsafe/union.rs
@@ -1,19 +1,19 @@
 // revisions: mir thir
 // [thir]compile-flags: -Z thir-unsafeck
 
-#![feature(untagged_unions)]
-
 union Foo {
     bar: i8,
     zst: (),
     pizza: Pizza,
 }
 
+#[derive(Clone, Copy)]
 struct Pizza {
     topping: Option<PizzaTopping>
 }
 
 #[allow(dead_code)]
+#[derive(Clone, Copy)]
 enum PizzaTopping {
     Cheese,
     Pineapple,
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index a1ef32ae60805..6bce5fbd4c1fe 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -148,7 +148,7 @@ fn is_value_unfrozen_raw<'tcx>(
         match val.ty().kind() {
             // the fact that we have to dig into every structs to search enums
             // leads us to the point checking `UnsafeCell` directly is the only option.
-            ty::Adt(ty_def, ..) if Some(ty_def.did()) == cx.tcx.lang_items().unsafe_cell_type() => true,
+            ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
             ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => {
                 let val = cx.tcx.destructure_mir_constant(cx.param_env, val);
                 val.fields.iter().any(|field| inner(cx, *field))
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
index 75b22326dad19..5342f47f42766 160000
--- a/src/tools/rust-analyzer
+++ b/src/tools/rust-analyzer
@@ -1 +1 @@
-Subproject commit 75b22326dad1914c22484ab6672de5cae94f7457
+Subproject commit 5342f47f4276641ddb5f0a5e08fb307742d6cdc4
diff --git a/triagebot.toml b/triagebot.toml
index ba9ed20cc64a2..8d9fab84ca13e 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -165,6 +165,19 @@ exclude_labels = [
     "T-*",
 ]
 
+[autolabel."A-bootstrap"]
+trigger_files = [
+    "x.py",
+    "src/bootstrap",
+    "src/tools/rust-installer",
+]
+
+[autolabel."T-infra"]
+trigger_files = [
+    "src/ci",
+    "src/tools/bump-stage0",
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"