about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-30 07:02:01 +0000
committerbors <bors@rust-lang.org>2023-01-30 07:02:01 +0000
commit3f25e56496a07d1848f7c4d0d98f91ec05e0be86 (patch)
treeabd6633f6263629649a7f325b5e3b1d9554e88c9
parentf55b0022db8dccc6aa6bf3f650b562eaec0fdc54 (diff)
parent2e93f2c92f1f1125d51f104f611a235466154aa1 (diff)
downloadrust-3f25e56496a07d1848f7c4d0d98f91ec05e0be86.tar.gz
rust-3f25e56496a07d1848f7c4d0d98f91ec05e0be86.zip
Auto merge of #104429 - nnethercote:more-deriving-on-packed-structs, r=RalfJung
More deriving on packed structs

See [here](https://github.com/rust-lang/rust/pull/104429#issuecomment-1320909245) for the t-lang nomination summary, and [here](https://github.com/rust-lang/rust/pull/104429#issuecomment-1360077895) for the approval.

r? `@RalfJung`
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/debug.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/decodable.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/default.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/encodable.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs135
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/hash.rs1
-rw-r--r--compiler/rustc_lint/src/context.rs3
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs33
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs9
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs45
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs1
-rw-r--r--tests/ui/derives/deriving-with-repr-packed-2.rs22
-rw-r--r--tests/ui/derives/deriving-with-repr-packed-2.stderr33
-rw-r--r--tests/ui/derives/deriving-with-repr-packed.rs41
-rw-r--r--tests/ui/derives/deriving-with-repr-packed.stderr126
-rw-r--r--tests/ui/deriving/deriving-all-codegen.rs85
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stderr63
-rw-r--r--tests/ui/deriving/deriving-all-codegen.stdout513
25 files changed, 823 insertions, 298 deletions
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 240167146e1..0481a118906 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -17,6 +17,7 @@ pub fn expand_deriving_copy(
         span,
         path: path_std!(marker::Copy),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: false,
         additional_bounds: Vec::new(),
         supports_unions: true,
         methods: Vec::new(),
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index ef5a75f428d..42f50d8ade2 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -73,6 +73,7 @@ pub fn expand_deriving_clone(
         span,
         path: path_std!(clone::Clone),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: bounds,
         supports_unions: true,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 3e994f037ad..424719f9795 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -27,6 +27,7 @@ pub fn expand_deriving_eq(
         span,
         path: path_std!(cmp::Eq),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: true,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index a926fca4e65..671f32550d2 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -20,6 +20,7 @@ pub fn expand_deriving_ord(
         span,
         path: path_std!(cmp::Ord),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index 9051fe0b28a..88d454fbc11 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -84,6 +84,7 @@ pub fn expand_deriving_partial_eq(
         span,
         path: path_std!(cmp::PartialEq),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods,
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 2fc30d8e05f..bcc90442eb7 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -59,6 +59,7 @@ pub fn expand_deriving_partial_ord(
         span,
         path: path_std!(cmp::PartialOrd),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: vec![],
         supports_unions: false,
         methods: vec![partial_cmp_def],
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index e0f487e8648..897048f6421 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -23,6 +23,7 @@ pub fn expand_deriving_debug(
         span,
         path: path_std!(fmt::Debug),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index 5f9519dad1b..c783e46eda9 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -25,6 +25,7 @@ pub fn expand_deriving_rustc_decodable(
         span,
         path: Path::new_(vec![krate, sym::Decodable], vec![], PathKind::Global),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 18270747296..a6c8b111527 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -25,6 +25,7 @@ pub fn expand_deriving_default(
         span,
         path: Path::new(vec![kw::Default, sym::Default]),
         skip_path_as_bound: has_a_default_variant(item),
+        needs_copy_as_bound_if_packed: false,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 2afeed927ac..a5e2b599df4 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -109,6 +109,7 @@ pub fn expand_deriving_rustc_encodable(
         span,
         path: Path::new_(vec![krate, sym::Encodable], vec![], PathKind::Global),
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 17b7ac0eba1..97de40bac34 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -165,11 +165,12 @@ pub use SubstructureFields::*;
 use crate::deriving;
 use rustc_ast::ptr::P;
 use rustc_ast::{
-    self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
+    self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
+    Mutability, PatKind, TyKind, VariantData,
 };
-use rustc_ast::{GenericArg, GenericParamKind, VariantData};
 use rustc_attr as attr;
 use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use std::cell::RefCell;
@@ -191,6 +192,9 @@ pub struct TraitDef<'a> {
     /// Whether to skip adding the current trait as a bound to the type parameters of the type.
     pub skip_path_as_bound: bool,
 
+    /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct.
+    pub needs_copy_as_bound_if_packed: bool,
+
     /// Additional bounds required of any type parameters of the type,
     /// other than the current trait
     pub additional_bounds: Vec<Ty>,
@@ -455,18 +459,6 @@ impl<'a> TraitDef<'a> {
                     }
                     false
                 });
-                let has_no_type_params = match &item.kind {
-                    ast::ItemKind::Struct(_, generics)
-                    | ast::ItemKind::Enum(_, generics)
-                    | ast::ItemKind::Union(_, generics) => !generics
-                        .params
-                        .iter()
-                        .any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
-                    _ => unreachable!(),
-                };
-                let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
-                let copy_fields =
-                    is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id);
 
                 let newitem = match &item.kind {
                     ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
@@ -475,7 +467,7 @@ impl<'a> TraitDef<'a> {
                         item.ident,
                         generics,
                         from_scratch,
-                        copy_fields,
+                        is_packed,
                     ),
                     ast::ItemKind::Enum(enum_def, generics) => {
                         // We ignore `is_packed` here, because `repr(packed)`
@@ -493,7 +485,7 @@ impl<'a> TraitDef<'a> {
                                 item.ident,
                                 generics,
                                 from_scratch,
-                                copy_fields,
+                                is_packed,
                             )
                         } else {
                             cx.span_err(mitem.span, "this trait cannot be derived for unions");
@@ -565,6 +557,7 @@ impl<'a> TraitDef<'a> {
         generics: &Generics,
         field_tys: Vec<P<ast::Ty>>,
         methods: Vec<P<ast::AssocItem>>,
+        is_packed: bool,
     ) -> P<ast::Item> {
         let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
 
@@ -607,20 +600,32 @@ impl<'a> TraitDef<'a> {
             .map(|param| match &param.kind {
                 GenericParamKind::Lifetime { .. } => param.clone(),
                 GenericParamKind::Type { .. } => {
-                    // I don't think this can be moved out of the loop, since
-                    // a GenericBound requires an ast id
-                    let bounds: Vec<_> =
-                    // extra restrictions on the generics parameters to the
-                    // type being derived upon
-                    self.additional_bounds.iter().map(|p| {
-                        cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
-                    }).chain(
-                        // require the current trait
-                        self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
-                    ).chain(
-                        // also add in any bounds from the declaration
-                        param.bounds.iter().cloned()
-                    ).collect();
+                    // Extra restrictions on the generics parameters to the
+                    // type being derived upon.
+                    let bounds: Vec<_> = self
+                        .additional_bounds
+                        .iter()
+                        .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+                        .chain(
+                            // Add a bound for the current trait.
+                            self.skip_path_as_bound
+                                .not()
+                                .then(|| cx.trait_bound(trait_path.clone())),
+                        )
+                        .chain({
+                            // Add a `Copy` bound if required.
+                            if is_packed && self.needs_copy_as_bound_if_packed {
+                                let p = deriving::path_std!(marker::Copy);
+                                Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
+                            } else {
+                                None
+                            }
+                        })
+                        .chain(
+                            // Also add in any bounds from the declaration.
+                            param.bounds.iter().cloned(),
+                        )
+                        .collect();
 
                     cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
                 }
@@ -692,9 +697,17 @@ impl<'a> TraitDef<'a> {
                             .map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
                             .collect();
 
-                        // require the current trait
+                        // Require the current trait.
                         bounds.push(cx.trait_bound(trait_path.clone()));
 
+                        // Add a `Copy` bound if required.
+                        if is_packed && self.needs_copy_as_bound_if_packed {
+                            let p = deriving::path_std!(marker::Copy);
+                            bounds.push(
+                                cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)),
+                            );
+                        }
+
                         let predicate = ast::WhereBoundPredicate {
                             span: self.span,
                             bound_generic_params: field_ty_param.bound_generic_params,
@@ -762,7 +775,7 @@ impl<'a> TraitDef<'a> {
         type_ident: Ident,
         generics: &Generics,
         from_scratch: bool,
-        copy_fields: bool,
+        is_packed: bool,
     ) -> P<ast::Item> {
         let field_tys: Vec<P<ast::Ty>> =
             struct_def.fields().iter().map(|field| field.ty.clone()).collect();
@@ -790,7 +803,7 @@ impl<'a> TraitDef<'a> {
                         type_ident,
                         &selflike_args,
                         &nonselflike_args,
-                        copy_fields,
+                        is_packed,
                     )
                 };
 
@@ -806,7 +819,7 @@ impl<'a> TraitDef<'a> {
             })
             .collect();
 
-        self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
+        self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
     }
 
     fn expand_enum_def(
@@ -861,7 +874,8 @@ impl<'a> TraitDef<'a> {
             })
             .collect();
 
-        self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
+        let is_packed = false; // enums are never packed
+        self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
     }
 }
 
@@ -1011,8 +1025,8 @@ impl<'a> MethodDef<'a> {
     /// ```
     /// But if the struct is `repr(packed)`, we can't use something like
     /// `&self.x` because that might cause an unaligned ref. So for any trait
-    /// method that takes a reference, if the struct impls `Copy` then we use a
-    /// local block to force a copy:
+    /// method that takes a reference, we use a local block to force a copy.
+    /// This requires that the field impl `Copy`.
     /// ```
     /// # struct A { x: u8, y: u8 }
     /// impl PartialEq for A {
@@ -1027,10 +1041,6 @@ impl<'a> MethodDef<'a> {
     ///         ::core::hash::Hash::hash(&{ self.y }, state)
     ///     }
     /// }
-    /// ```
-    /// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This
-    /// only works if the fields match the alignment required by the
-    /// `packed(N)` attribute. (We'll get errors later on if not.)
     fn expand_struct_method_body<'b>(
         &self,
         cx: &mut ExtCtxt<'_>,
@@ -1039,12 +1049,12 @@ impl<'a> MethodDef<'a> {
         type_ident: Ident,
         selflike_args: &[P<Expr>],
         nonselflike_args: &[P<Expr>],
-        copy_fields: bool,
+        is_packed: bool,
     ) -> BlockOrExpr {
         assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
 
         let selflike_fields =
-            trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields);
+            trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed);
         self.call_substructure_method(
             cx,
             trait_,
@@ -1514,7 +1524,7 @@ impl<'a> TraitDef<'a> {
         cx: &mut ExtCtxt<'_>,
         selflike_args: &[P<Expr>],
         struct_def: &'a VariantData,
-        copy_fields: bool,
+        is_packed: bool,
     ) -> Vec<FieldInfo> {
         self.create_fields(struct_def, |i, struct_field, sp| {
             selflike_args
@@ -1533,10 +1543,39 @@ impl<'a> TraitDef<'a> {
                             }),
                         ),
                     );
-                    if copy_fields {
-                        field_expr = cx.expr_block(
-                            cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
-                        );
+                    // In general, fields in packed structs are copied via a
+                    // block, e.g. `&{self.0}`. The one exception is `[u8]`
+                    // fields, which cannot be copied and also never cause
+                    // unaligned references. This exception is allowed to
+                    // handle the `FlexZeroSlice` type in the `zerovec` crate
+                    // within `icu4x-0.9.0`.
+                    //
+                    // Once use of `icu4x-0.9.0` has dropped sufficiently, this
+                    // exception should be removed.
+                    let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
+                        let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind &&
+                        let [seg] = segments.as_slice() &&
+                        seg.ident.name == sym::u8 && seg.args.is_none()
+                    {
+                        true
+                    } else {
+                        false
+                    };
+                    if is_packed {
+                        if is_u8_slice {
+                            cx.sess.parse_sess.buffer_lint_with_diagnostic(
+                                BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
+                                sp,
+                                ast::CRATE_NODE_ID,
+                                "byte slice in a packed struct that derives a built-in trait",
+                                rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
+                            );
+                        } else {
+                            // Wrap the expression in `{...}`, causing a copy.
+                            field_expr = cx.expr_block(
+                                cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
+                            );
+                        }
                     }
                     cx.expr_addr_of(sp, field_expr)
                 })
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index f8570d8f86a..5c2e89c5697 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -24,6 +24,7 @@ pub fn expand_deriving_hash(
         span,
         path,
         skip_path_as_bound: false,
+        needs_copy_as_bound_if_packed: true,
         additional_bounds: Vec::new(),
         supports_unions: false,
         methods: vec![MethodDef {
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 8046cc21cea..d1d4bb37528 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -882,6 +882,9 @@ pub trait LintContext: Sized {
                         );
                     }
                 }
+                BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => {
+                    db.help("consider implementing the trait by hand, or remove the `packed` attribute");
+                }
             }
             // Rewrap `db`, and pass control to the user.
             decorate(db)
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 4a38ab2159f..d731c10f46e 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3381,6 +3381,7 @@ declare_lint_pass! {
         REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
         NAMED_ARGUMENTS_USED_POSITIONALLY,
         IMPLIED_BOUNDS_ENTAILMENT,
+        BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
     ]
 }
 
@@ -4115,3 +4116,35 @@ declare_lint! {
         reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
     };
 }
+
+declare_lint! {
+    /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field
+    /// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #[repr(packed)]
+    /// #[derive(Hash)]
+    /// struct FlexZeroSlice {
+    ///     width: u8,
+    ///     data: [u8],
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This was previously accepted but is being phased out, because fields in packed structs are
+    /// now required to implement `Copy` for `derive` to work. Byte slices are a temporary
+    /// exception because certain crates depended on them.
+    pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
+    Warn,
+    "`[u8]` slice used in a packed struct with `derive`",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
+        reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
+    };
+    report_in_external_macro
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7054d1e9f10..6efbf5ce9ee 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -521,6 +521,7 @@ pub enum BuiltinLintDiagnostics {
         /// Indicates if the named argument is used as a width/precision for formatting
         is_formatting_arg: bool,
     },
+    ByteSliceInPackedStructWithDerive,
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 1f1f4fc95b5..1eff796e91b 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -814,15 +814,6 @@ rustc_queries! {
         }
     }
 
-    /// HACK: when evaluated, this reports an "unsafe derive on repr(packed)" error.
-    ///
-    /// Unsafety checking is executed for each method separately, but we only want
-    /// to emit this error once per derive. As there are some impls with multiple
-    /// methods, we use a query for deduplication.
-    query unsafe_derive_on_repr_packed(key: LocalDefId) -> () {
-        desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
-    }
-
     /// Returns the types assumed to be well formed while "inside" of the given item.
     ///
     /// Note that we've liberated the late bound regions of function signatures, so
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 51abcf51189..3e7571aa7a2 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -1,17 +1,11 @@
-use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::*;
-use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
 
 use crate::util;
 use crate::MirLint;
 
-pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
-}
-
 pub struct CheckPackedRef;
 
 impl<'tcx> MirLint<'tcx> for CheckPackedRef {
@@ -30,32 +24,6 @@ struct PackedRefChecker<'a, 'tcx> {
     source_info: SourceInfo,
 }
 
-fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
-    // FIXME: when we make this a hard error, this should have its
-    // own error code.
-
-    let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
-        "with type or const parameters"
-    } else {
-        "that does not derive `Copy`"
-    };
-    let message = format!(
-        "`{}` can't be derived on this `#[repr(packed)]` struct {}",
-        tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
-        extra
-    );
-
-    tcx.struct_span_lint_hir(
-        UNALIGNED_REFERENCES,
-        lint_hir_id,
-        tcx.def_span(def_id),
-        message,
-        |lint| lint,
-    );
-}
-
 impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
     fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
         // Make sure we know where in the MIR we are.
@@ -73,14 +41,13 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
         if context.is_borrow() {
             if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
                 let def_id = self.body.source.instance.def_id();
-                if let Some(impl_def_id) = self
-                    .tcx
-                    .impl_of_method(def_id)
-                    .filter(|&def_id| self.tcx.is_builtin_derive(def_id))
+                if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
+                    && self.tcx.is_builtin_derive(impl_def_id)
                 {
-                    // If a method is defined in the local crate,
-                    // the impl containing that method should also be.
-                    self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local());
+                    // If we ever reach here it means that the generated derive
+                    // code is somehow doing an unaligned reference, which it
+                    // shouldn't do.
+                    unreachable!();
                 } else {
                     let source_info = self.source_info;
                     let lint_root = self.body.source_scopes[source_info.scope]
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index abf89e550b1..3d9137fa102 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -104,7 +104,6 @@ use rustc_mir_dataflow::rustc_peek;
 
 pub fn provide(providers: &mut Providers) {
     check_unsafety::provide(providers);
-    check_packed_ref::provide(providers);
     coverage::query::provide(providers);
     ffi_unwind_calls::provide(providers);
     shim::provide(providers);
diff --git a/tests/ui/derives/deriving-with-repr-packed-2.rs b/tests/ui/derives/deriving-with-repr-packed-2.rs
new file mode 100644
index 00000000000..cbd7432fce4
--- /dev/null
+++ b/tests/ui/derives/deriving-with-repr-packed-2.rs
@@ -0,0 +1,22 @@
+#![deny(unaligned_references)]
+
+// Check that deriving certain builtin traits on certain packed structs cause
+// errors. To avoid potentially misaligned references, field copies must be
+// used, which involves adding `T: Copy` bounds.
+
+#[derive(Copy, Clone, Default, PartialEq, Eq)]
+#[repr(packed)]
+pub struct Foo<T>(T, T, T);
+
+struct NonCopy;
+
+fn main() {
+    // This one is fine because `u32` impls `Copy`.
+    let x: Foo<u32> = Foo(1, 2, 3);
+    _ = x.clone();
+
+    // This one is an error because `NonCopy` doesn't impl `Copy`.
+    let x: Foo<NonCopy> = Foo(NonCopy, NonCopy, NonCopy);
+    _ = x.clone();
+    //~^ ERROR the method `clone` exists for struct `Foo<NonCopy>`, but its trait bounds were not satisfied
+}
diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr
new file mode 100644
index 00000000000..83540739ee3
--- /dev/null
+++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr
@@ -0,0 +1,33 @@
+error[E0599]: the method `clone` exists for struct `Foo<NonCopy>`, but its trait bounds were not satisfied
+  --> $DIR/deriving-with-repr-packed-2.rs:20:11
+   |
+LL | pub struct Foo<T>(T, T, T);
+   | -----------------
+   | |
+   | method `clone` not found for this struct
+   | doesn't satisfy `Foo<NonCopy>: Clone`
+LL |
+LL | struct NonCopy;
+   | --------------
+   | |
+   | doesn't satisfy `NonCopy: Clone`
+   | doesn't satisfy `NonCopy: Copy`
+...
+LL |     _ = x.clone();
+   |           ^^^^^ method cannot be called on `Foo<NonCopy>` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `NonCopy: Clone`
+      `NonCopy: Copy`
+  --> $DIR/deriving-with-repr-packed-2.rs:7:16
+   |
+LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
+   |                ^^^^^ unsatisfied trait bound introduced in this `derive` macro
+help: consider annotating `NonCopy` with `#[derive(Clone, Copy)]`
+   |
+LL | #[derive(Clone, Copy)]
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/derives/deriving-with-repr-packed.rs b/tests/ui/derives/deriving-with-repr-packed.rs
index 3884e397764..eddf41f5553 100644
--- a/tests/ui/derives/deriving-with-repr-packed.rs
+++ b/tests/ui/derives/deriving-with-repr-packed.rs
@@ -1,45 +1,38 @@
 #![deny(unaligned_references)]
 
 // Check that deriving certain builtin traits on certain packed structs cause
-// errors. This happens when the derived trait would need to use a potentially
-// misaligned reference. But there are two cases that are allowed:
-// - If all the fields within the struct meet the required alignment: 1 for
-//   `repr(packed)`, or `N` for `repr(packed(N))`.
-// - If `Default` is the only trait derived, because it doesn't involve any
-//   references.
+// errors. To avoid potentially misaligned references, field copies must be
+// used, which involves adding `T: Copy` bounds.
 
 #[derive(Copy, Clone, Default, PartialEq, Eq)]
-//~^ ERROR `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
-//~| hard error
-//~^^^ ERROR `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
-//~| hard error
 #[repr(packed)]
 pub struct Foo<T>(T, T, T);
 
+// This one is fine because the fields all impl `Copy`.
 #[derive(Default, Hash)]
-//~^ ERROR `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
-//~| hard error
 #[repr(packed)]
 pub struct Bar(u32, u32, u32);
 
-// This one is fine because the field alignment is 1.
-#[derive(Default, Hash)]
-#[repr(packed)]
-pub struct Bar2(u8, i8, bool);
-
-// This one is fine because the field alignment is 2, matching `packed(2)`.
-#[derive(Default, Hash)]
-#[repr(packed(2))]
-pub struct Bar3(u16, i16, bool);
-
 // This one is fine because it's not packed.
 #[derive(Debug, Default)]
 struct Y(usize);
 
+// This one has an error because `Y` doesn't impl `Copy`.
+// Note: there is room for improvement in the error message.
 #[derive(Debug, Default)]
-//~^ ERROR `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
-//~| hard error
 #[repr(packed)]
 struct X(Y);
+//~^ ERROR cannot move out of `self` which is behind a shared reference
+
+// This is currently allowed, but will be phased out at some point. From
+// `zerovec` within icu4x-0.9.0.
+#[derive(Debug)]
+#[repr(packed)]
+struct FlexZeroSlice {
+    width: u8,
+    data: [u8],
+    //~^ WARNING byte slice in a packed struct that derives a built-in trait
+    //~^^ this was previously accepted
+}
 
 fn main() {}
diff --git a/tests/ui/derives/deriving-with-repr-packed.stderr b/tests/ui/derives/deriving-with-repr-packed.stderr
index 0ad800c3981..2cb2a696d97 100644
--- a/tests/ui/derives/deriving-with-repr-packed.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed.stderr
@@ -1,111 +1,45 @@
-error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
-  --> $DIR/deriving-with-repr-packed.rs:11:16
+warning: byte slice in a packed struct that derives a built-in trait
+  --> $DIR/deriving-with-repr-packed.rs:33:5
    |
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
-   |                ^^^^^
+LL | #[derive(Debug)]
+   |          ----- in this derive macro expansion
+...
+LL |     data: [u8],
+   |     ^^^^^^^^^^
    |
    = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
-  --> $DIR/deriving-with-repr-packed.rs:1:9
-   |
-LL | #![deny(unaligned_references)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
-  --> $DIR/deriving-with-repr-packed.rs:11:32
-   |
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
-   |                                ^^^^^^^^^
-   |
-   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
-  --> $DIR/deriving-with-repr-packed.rs:19:19
-   |
-LL | #[derive(Default, Hash)]
-   |                   ^^^^
-   |
-   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
+   = help: consider implementing the trait by hand, or remove the `packed` attribute
+   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
-  --> $DIR/deriving-with-repr-packed.rs:39:10
+error[E0507]: cannot move out of `self` which is behind a shared reference
+  --> $DIR/deriving-with-repr-packed.rs:24:10
    |
 LL | #[derive(Debug, Default)]
-   |          ^^^^^
+   |          ----- in this derive macro expansion
+LL | #[repr(packed)]
+LL | struct X(Y);
+   |          ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait
    |
-   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 4 previous errors
+error: aborting due to previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0507`.
 Future incompatibility report: Future breakage diagnostic:
-error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
-  --> $DIR/deriving-with-repr-packed.rs:11:16
-   |
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
-   |                ^^^^^
-   |
-   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
-  --> $DIR/deriving-with-repr-packed.rs:1:9
-   |
-LL | #![deny(unaligned_references)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
-  --> $DIR/deriving-with-repr-packed.rs:11:32
-   |
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
-   |                                ^^^^^^^^^
-   |
-   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
-  --> $DIR/deriving-with-repr-packed.rs:1:9
-   |
-LL | #![deny(unaligned_references)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
-  --> $DIR/deriving-with-repr-packed.rs:19:19
-   |
-LL | #[derive(Default, Hash)]
-   |                   ^^^^
+warning: byte slice in a packed struct that derives a built-in trait
+  --> $DIR/deriving-with-repr-packed.rs:33:5
    |
-   = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
-  --> $DIR/deriving-with-repr-packed.rs:1:9
-   |
-LL | #![deny(unaligned_references)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
-  --> $DIR/deriving-with-repr-packed.rs:39:10
-   |
-LL | #[derive(Debug, Default)]
-   |          ^^^^^
+LL | #[derive(Debug)]
+   |          ----- in this derive macro expansion
+...
+LL |     data: [u8],
+   |     ^^^^^^^^^^
    |
    = 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
-  --> $DIR/deriving-with-repr-packed.rs:1:9
-   |
-LL | #![deny(unaligned_references)]
-   |         ^^^^^^^^^^^^^^^^^^^^
-   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
+   = help: consider implementing the trait by hand, or remove the `packed` attribute
+   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs
index ba7809413bd..51f9708d3cd 100644
--- a/tests/ui/deriving/deriving-all-codegen.rs
+++ b/tests/ui/deriving/deriving-all-codegen.rs
@@ -21,36 +21,88 @@
 #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Empty;
 
-// A basic struct.
+// A basic struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
 #[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Point {
     x: u32,
     y: u32,
 }
 
-// A large struct.
-#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+// A basic packed struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(packed)]
+struct PackedPoint {
+    x: u32,
+    y: u32,
+}
+
+// A large struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Big {
     b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32,
 }
 
+// A struct that doesn't impl `Copy`, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+struct NonCopy(u32);
+
+// A packed struct that doesn't impl `Copy`, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+#[repr(packed)]
+struct PackedNonCopy(u32);
+
+// A struct that impls `Copy` manually, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+struct ManualCopy(u32);
+impl Copy for ManualCopy {}
+
+// A packed struct that impls `Copy` manually, which means it gets the
+// non-simple `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+#[repr(packed)]
+struct PackedManualCopy(u32);
+impl Copy for PackedManualCopy {}
+
 // A struct with an unsized field. Some derives are not usable in this case.
 #[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
 struct Unsized([u32]);
 
-// A packed tuple struct that impls `Copy`.
-#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+// A packed struct with an unsized `[u8]` field. This is currently allowed, but
+// causes a warning and will be phased out at some point.
+#[derive(Debug, Hash)]
 #[repr(packed)]
-struct PackedCopy(u32);
+struct PackedUnsizedU8([u8]);
+//~^ WARNING byte slice in a packed struct that derives a built-in trait
+//~^^ WARNING byte slice in a packed struct that derives a built-in trait
+//~^^^ this was previously accepted
+//~^^^^ this was previously accepted
 
-// A packed tuple struct that does not impl `Copy`. Note that the alignment of
-// the field must be 1 for this code to be valid. Otherwise it triggers an
-// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not
-// derive Copy (error E0133)" at MIR building time. This is a weird case and
-// it's possible that this struct is not supposed to work, but for now it does.
-#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+trait Trait {
+    type A;
+}
+
+// A generic struct involving an associated type.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+struct Generic<T: Trait, U> {
+    t: T,
+    ta: T::A,
+    u: U,
+}
+
+// A packed, generic tuple struct involving an associated type. Because it is
+// packed, a `T: Copy` bound is added to all impls (and where clauses within
+// them) except for `Default`. This is because we must access fields using
+// copies (e.g. `&{self.0}`), instead of using direct references (e.g.
+// `&self.0`) which may be misaligned in a packed struct.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
 #[repr(packed)]
-struct PackedNonCopy(u8);
+struct PackedGeneric<T: Trait, U>(T, T::A, U);
 
 // An empty enum.
 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
@@ -97,6 +149,13 @@ enum Fielded {
     Z(Option<i32>),
 }
 
+// A generic enum. Note that `Default` cannot be derived for this enum.
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
+enum EnumGeneric<T, U> {
+    One(T),
+    Two(U),
+}
+
 // A union. Most builtin traits are not derivable for unions.
 #[derive(Clone, Copy)]
 pub union Union {
diff --git a/tests/ui/deriving/deriving-all-codegen.stderr b/tests/ui/deriving/deriving-all-codegen.stderr
new file mode 100644
index 00000000000..503f0cae73b
--- /dev/null
+++ b/tests/ui/deriving/deriving-all-codegen.stderr
@@ -0,0 +1,63 @@
+warning: byte slice in a packed struct that derives a built-in trait
+  --> $DIR/deriving-all-codegen.rs:80:24
+   |
+LL | #[derive(Debug, Hash)]
+   |          ----- in this derive macro expansion
+LL | #[repr(packed)]
+LL | struct PackedUnsizedU8([u8]);
+   |                        ^^^^
+   |
+   = 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 #107457 <https://github.com/rust-lang/rust/issues/107457>
+   = help: consider implementing the trait by hand, or remove the `packed` attribute
+   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: byte slice in a packed struct that derives a built-in trait
+  --> $DIR/deriving-all-codegen.rs:80:24
+   |
+LL | #[derive(Debug, Hash)]
+   |                 ---- in this derive macro expansion
+LL | #[repr(packed)]
+LL | struct PackedUnsizedU8([u8]);
+   |                        ^^^^
+   |
+   = 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 #107457 <https://github.com/rust-lang/rust/issues/107457>
+   = help: consider implementing the trait by hand, or remove the `packed` attribute
+   = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 2 warnings emitted
+
+Future incompatibility report: Future breakage diagnostic:
+warning: byte slice in a packed struct that derives a built-in trait
+  --> $DIR/deriving-all-codegen.rs:80:24
+   |
+LL | #[derive(Debug, Hash)]
+   |          ----- in this derive macro expansion
+LL | #[repr(packed)]
+LL | struct PackedUnsizedU8([u8]);
+   |                        ^^^^
+   |
+   = 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 #107457 <https://github.com/rust-lang/rust/issues/107457>
+   = help: consider implementing the trait by hand, or remove the `packed` attribute
+   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+   = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+Future breakage diagnostic:
+warning: byte slice in a packed struct that derives a built-in trait
+  --> $DIR/deriving-all-codegen.rs:80:24
+   |
+LL | #[derive(Debug, Hash)]
+   |                 ---- in this derive macro expansion
+LL | #[repr(packed)]
+LL | struct PackedUnsizedU8([u8]);
+   |                        ^^^^
+   |
+   = 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 #107457 <https://github.com/rust-lang/rust/issues/107457>
+   = help: consider implementing the trait by hand, or remove the `packed` attribute
+   = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+   = note: this warning originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index 2a93a05c627..b4874cef134 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -78,7 +78,8 @@ impl ::core::cmp::Ord for Empty {
     }
 }
 
-// A basic struct.
+// A basic struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
 struct Point {
     x: u32,
     y: u32,
@@ -161,7 +162,95 @@ impl ::core::cmp::Ord for Point {
     }
 }
 
-// A large struct.
+// A basic packed struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
+#[repr(packed)]
+struct PackedPoint {
+    x: u32,
+    y: u32,
+}
+#[automatically_derived]
+impl ::core::clone::Clone for PackedPoint {
+    #[inline]
+    fn clone(&self) -> PackedPoint {
+        let _: ::core::clone::AssertParamIsClone<u32>;
+        *self
+    }
+}
+#[automatically_derived]
+impl ::core::marker::Copy for PackedPoint { }
+#[automatically_derived]
+impl ::core::fmt::Debug for PackedPoint {
+    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+        ::core::fmt::Formatter::debug_struct_field2_finish(f, "PackedPoint",
+            "x", &&{ self.x }, "y", &&{ self.y })
+    }
+}
+#[automatically_derived]
+impl ::core::default::Default for PackedPoint {
+    #[inline]
+    fn default() -> PackedPoint {
+        PackedPoint {
+            x: ::core::default::Default::default(),
+            y: ::core::default::Default::default(),
+        }
+    }
+}
+#[automatically_derived]
+impl ::core::hash::Hash for PackedPoint {
+    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
+        ::core::hash::Hash::hash(&{ self.x }, state);
+        ::core::hash::Hash::hash(&{ self.y }, state)
+    }
+}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for PackedPoint { }
+#[automatically_derived]
+impl ::core::cmp::PartialEq for PackedPoint {
+    #[inline]
+    fn eq(&self, other: &PackedPoint) -> bool {
+        { self.x } == { other.x } && { self.y } == { other.y }
+    }
+}
+#[automatically_derived]
+impl ::core::marker::StructuralEq for PackedPoint { }
+#[automatically_derived]
+impl ::core::cmp::Eq for PackedPoint {
+    #[inline]
+    #[doc(hidden)]
+    #[no_coverage]
+    fn assert_receiver_is_total_eq(&self) -> () {
+        let _: ::core::cmp::AssertParamIsEq<u32>;
+    }
+}
+#[automatically_derived]
+impl ::core::cmp::PartialOrd for PackedPoint {
+    #[inline]
+    fn partial_cmp(&self, other: &PackedPoint)
+        -> ::core::option::Option<::core::cmp::Ordering> {
+        match ::core::cmp::PartialOrd::partial_cmp(&{ self.x }, &{ other.x })
+            {
+            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+                ::core::cmp::PartialOrd::partial_cmp(&{ self.y },
+                    &{ other.y }),
+            cmp => cmp,
+        }
+    }
+}
+#[automatically_derived]
+impl ::core::cmp::Ord for PackedPoint {
+    #[inline]
+    fn cmp(&self, other: &PackedPoint) -> ::core::cmp::Ordering {
+        match ::core::cmp::Ord::cmp(&{ self.x }, &{ other.x }) {
+            ::core::cmp::Ordering::Equal =>
+                ::core::cmp::Ord::cmp(&{ self.y }, &{ other.y }),
+            cmp => cmp,
+        }
+    }
+}
+
+// A large struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
 struct Big {
     b1: u32,
     b2: u32,
@@ -176,19 +265,13 @@ struct Big {
 impl ::core::clone::Clone for Big {
     #[inline]
     fn clone(&self) -> Big {
-        Big {
-            b1: ::core::clone::Clone::clone(&self.b1),
-            b2: ::core::clone::Clone::clone(&self.b2),
-            b3: ::core::clone::Clone::clone(&self.b3),
-            b4: ::core::clone::Clone::clone(&self.b4),
-            b5: ::core::clone::Clone::clone(&self.b5),
-            b6: ::core::clone::Clone::clone(&self.b6),
-            b7: ::core::clone::Clone::clone(&self.b7),
-            b8: ::core::clone::Clone::clone(&self.b8),
-        }
+        let _: ::core::clone::AssertParamIsClone<u32>;
+        *self
     }
 }
 #[automatically_derived]
+impl ::core::marker::Copy for Big { }
+#[automatically_derived]
 impl ::core::fmt::Debug for Big {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
         let names: &'static _ =
@@ -336,6 +419,54 @@ impl ::core::cmp::Ord for Big {
     }
 }
 
+// A struct that doesn't impl `Copy`, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+struct NonCopy(u32);
+#[automatically_derived]
+impl ::core::clone::Clone for NonCopy {
+    #[inline]
+    fn clone(&self) -> NonCopy {
+        NonCopy(::core::clone::Clone::clone(&self.0))
+    }
+}
+
+// A packed struct that doesn't impl `Copy`, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+#[repr(packed)]
+struct PackedNonCopy(u32);
+#[automatically_derived]
+impl ::core::clone::Clone for PackedNonCopy {
+    #[inline]
+    fn clone(&self) -> PackedNonCopy {
+        PackedNonCopy(::core::clone::Clone::clone(&{ self.0 }))
+    }
+}
+
+// A struct that impls `Copy` manually, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+struct ManualCopy(u32);
+#[automatically_derived]
+impl ::core::clone::Clone for ManualCopy {
+    #[inline]
+    fn clone(&self) -> ManualCopy {
+        ManualCopy(::core::clone::Clone::clone(&self.0))
+    }
+}
+impl Copy for ManualCopy {}
+
+// A packed struct that impls `Copy` manually, which means it gets the
+// non-simple `clone` implemention that clones the fields individually.
+#[repr(packed)]
+struct PackedManualCopy(u32);
+#[automatically_derived]
+impl ::core::clone::Clone for PackedManualCopy {
+    #[inline]
+    fn clone(&self) -> PackedManualCopy {
+        PackedManualCopy(::core::clone::Clone::clone(&{ self.0 }))
+    }
+}
+impl Copy for PackedManualCopy {}
+
 // A struct with an unsized field. Some derives are not usable in this case.
 struct Unsized([u32]);
 #[automatically_derived]
@@ -385,138 +516,265 @@ impl ::core::cmp::Ord for Unsized {
     }
 }
 
-// A packed tuple struct that impls `Copy`.
+// A packed struct with an unsized `[u8]` field. This is currently allowed, but
+// causes a warning and will be phased out at some point.
 #[repr(packed)]
-struct PackedCopy(u32);
+struct PackedUnsizedU8([u8]);
+#[automatically_derived]
+impl ::core::fmt::Debug for PackedUnsizedU8 {
+    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
+            "PackedUnsizedU8", &&self.0)
+    }
+}
 #[automatically_derived]
-impl ::core::clone::Clone for PackedCopy {
+impl ::core::hash::Hash for PackedUnsizedU8 {
+    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
+        ::core::hash::Hash::hash(&self.0, state)
+    }
+}
+
+trait Trait {
+    type A;
+}
+
+// A generic struct involving an associated type.
+struct Generic<T: Trait, U> {
+    t: T,
+    ta: T::A,
+    u: U,
+}
+#[automatically_derived]
+impl<T: ::core::clone::Clone + Trait, U: ::core::clone::Clone>
+    ::core::clone::Clone for Generic<T, U> where T::A: ::core::clone::Clone {
     #[inline]
-    fn clone(&self) -> PackedCopy {
-        let _: ::core::clone::AssertParamIsClone<u32>;
-        *self
+    fn clone(&self) -> Generic<T, U> {
+        Generic {
+            t: ::core::clone::Clone::clone(&self.t),
+            ta: ::core::clone::Clone::clone(&self.ta),
+            u: ::core::clone::Clone::clone(&self.u),
+        }
     }
 }
 #[automatically_derived]
-impl ::core::marker::Copy for PackedCopy { }
+impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy>
+    ::core::marker::Copy for Generic<T, U> where T::A: ::core::marker::Copy {
+}
 #[automatically_derived]
-impl ::core::fmt::Debug for PackedCopy {
+impl<T: ::core::fmt::Debug + Trait, U: ::core::fmt::Debug> ::core::fmt::Debug
+    for Generic<T, U> where T::A: ::core::fmt::Debug {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy",
-            &&{ self.0 })
+        ::core::fmt::Formatter::debug_struct_field3_finish(f, "Generic", "t",
+            &&self.t, "ta", &&self.ta, "u", &&self.u)
     }
 }
 #[automatically_derived]
-impl ::core::default::Default for PackedCopy {
+impl<T: ::core::default::Default + Trait, U: ::core::default::Default>
+    ::core::default::Default for Generic<T, U> where
+    T::A: ::core::default::Default {
     #[inline]
-    fn default() -> PackedCopy {
-        PackedCopy(::core::default::Default::default())
+    fn default() -> Generic<T, U> {
+        Generic {
+            t: ::core::default::Default::default(),
+            ta: ::core::default::Default::default(),
+            u: ::core::default::Default::default(),
+        }
     }
 }
 #[automatically_derived]
-impl ::core::hash::Hash for PackedCopy {
+impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash
+    for Generic<T, U> where T::A: ::core::hash::Hash {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        ::core::hash::Hash::hash(&{ self.0 }, state)
+        ::core::hash::Hash::hash(&self.t, state);
+        ::core::hash::Hash::hash(&self.ta, state);
+        ::core::hash::Hash::hash(&self.u, state)
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralPartialEq for PackedCopy { }
+impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { }
 #[automatically_derived]
-impl ::core::cmp::PartialEq for PackedCopy {
+impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
+    ::core::cmp::PartialEq for Generic<T, U> where
+    T::A: ::core::cmp::PartialEq {
     #[inline]
-    fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
+    fn eq(&self, other: &Generic<T, U>) -> bool {
+        self.t == other.t && self.ta == other.ta && self.u == other.u
+    }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for PackedCopy { }
+impl<T: Trait, U> ::core::marker::StructuralEq for Generic<T, U> { }
 #[automatically_derived]
-impl ::core::cmp::Eq for PackedCopy {
+impl<T: ::core::cmp::Eq + Trait, U: ::core::cmp::Eq> ::core::cmp::Eq for
+    Generic<T, U> where T::A: ::core::cmp::Eq {
     #[inline]
     #[doc(hidden)]
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
-        let _: ::core::cmp::AssertParamIsEq<u32>;
+        let _: ::core::cmp::AssertParamIsEq<T>;
+        let _: ::core::cmp::AssertParamIsEq<T::A>;
+        let _: ::core::cmp::AssertParamIsEq<U>;
     }
 }
 #[automatically_derived]
-impl ::core::cmp::PartialOrd for PackedCopy {
+impl<T: ::core::cmp::PartialOrd + Trait, U: ::core::cmp::PartialOrd>
+    ::core::cmp::PartialOrd for Generic<T, U> where
+    T::A: ::core::cmp::PartialOrd {
     #[inline]
-    fn partial_cmp(&self, other: &PackedCopy)
+    fn partial_cmp(&self, other: &Generic<T, U>)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
+        match ::core::cmp::PartialOrd::partial_cmp(&self.t, &other.t) {
+            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+                match ::core::cmp::PartialOrd::partial_cmp(&self.ta,
+                        &other.ta) {
+                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+                        => ::core::cmp::PartialOrd::partial_cmp(&self.u, &other.u),
+                    cmp => cmp,
+                },
+            cmp => cmp,
+        }
     }
 }
 #[automatically_derived]
-impl ::core::cmp::Ord for PackedCopy {
+impl<T: ::core::cmp::Ord + Trait, U: ::core::cmp::Ord> ::core::cmp::Ord for
+    Generic<T, U> where T::A: ::core::cmp::Ord {
     #[inline]
-    fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
-        ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 })
+    fn cmp(&self, other: &Generic<T, U>) -> ::core::cmp::Ordering {
+        match ::core::cmp::Ord::cmp(&self.t, &other.t) {
+            ::core::cmp::Ordering::Equal =>
+                match ::core::cmp::Ord::cmp(&self.ta, &other.ta) {
+                    ::core::cmp::Ordering::Equal =>
+                        ::core::cmp::Ord::cmp(&self.u, &other.u),
+                    cmp => cmp,
+                },
+            cmp => cmp,
+        }
     }
 }
 
-// A packed tuple struct that does not impl `Copy`. Note that the alignment of
-// the field must be 1 for this code to be valid. Otherwise it triggers an
-// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not
-// derive Copy (error E0133)" at MIR building time. This is a weird case and
-// it's possible that this struct is not supposed to work, but for now it does.
+// A packed, generic tuple struct involving an associated type. Because it is
+// packed, a `T: Copy` bound is added to all impls (and where clauses within
+// them) except for `Default`. This is because we must access fields using
+// copies (e.g. `&{self.0}`), instead of using direct references (e.g.
+// `&self.0`) which may be misaligned in a packed struct.
 #[repr(packed)]
-struct PackedNonCopy(u8);
+struct PackedGeneric<T: Trait, U>(T, T::A, U);
 #[automatically_derived]
-impl ::core::clone::Clone for PackedNonCopy {
+impl<T: ::core::clone::Clone + ::core::marker::Copy + Trait,
+    U: ::core::clone::Clone + ::core::marker::Copy> ::core::clone::Clone for
+    PackedGeneric<T, U> where T::A: ::core::clone::Clone +
+    ::core::marker::Copy {
     #[inline]
-    fn clone(&self) -> PackedNonCopy {
-        PackedNonCopy(::core::clone::Clone::clone(&self.0))
+    fn clone(&self) -> PackedGeneric<T, U> {
+        PackedGeneric(::core::clone::Clone::clone(&{ self.0 }),
+            ::core::clone::Clone::clone(&{ self.1 }),
+            ::core::clone::Clone::clone(&{ self.2 }))
     }
 }
 #[automatically_derived]
-impl ::core::fmt::Debug for PackedNonCopy {
+impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy>
+    ::core::marker::Copy for PackedGeneric<T, U> where
+    T::A: ::core::marker::Copy {
+}
+#[automatically_derived]
+impl<T: ::core::fmt::Debug + ::core::marker::Copy + Trait,
+    U: ::core::fmt::Debug + ::core::marker::Copy> ::core::fmt::Debug for
+    PackedGeneric<T, U> where T::A: ::core::fmt::Debug + ::core::marker::Copy
+    {
     fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
-        ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy",
-            &&self.0)
+        ::core::fmt::Formatter::debug_tuple_field3_finish(f, "PackedGeneric",
+            &&{ self.0 }, &&{ self.1 }, &&{ self.2 })
     }
 }
 #[automatically_derived]
-impl ::core::default::Default for PackedNonCopy {
+impl<T: ::core::default::Default + Trait, U: ::core::default::Default>
+    ::core::default::Default for PackedGeneric<T, U> where
+    T::A: ::core::default::Default {
     #[inline]
-    fn default() -> PackedNonCopy {
-        PackedNonCopy(::core::default::Default::default())
+    fn default() -> PackedGeneric<T, U> {
+        PackedGeneric(::core::default::Default::default(),
+            ::core::default::Default::default(),
+            ::core::default::Default::default())
     }
 }
 #[automatically_derived]
-impl ::core::hash::Hash for PackedNonCopy {
+impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait,
+    U: ::core::hash::Hash + ::core::marker::Copy> ::core::hash::Hash for
+    PackedGeneric<T, U> where T::A: ::core::hash::Hash + ::core::marker::Copy
+    {
     fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
-        ::core::hash::Hash::hash(&self.0, state)
+        ::core::hash::Hash::hash(&{ self.0 }, state);
+        ::core::hash::Hash::hash(&{ self.1 }, state);
+        ::core::hash::Hash::hash(&{ self.2 }, state)
     }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralPartialEq for PackedNonCopy { }
+impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U>
+    {
+}
 #[automatically_derived]
-impl ::core::cmp::PartialEq for PackedNonCopy {
+impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
+    U: ::core::cmp::PartialEq + ::core::marker::Copy> ::core::cmp::PartialEq
+    for PackedGeneric<T, U> where T::A: ::core::cmp::PartialEq +
+    ::core::marker::Copy {
     #[inline]
-    fn eq(&self, other: &PackedNonCopy) -> bool { self.0 == other.0 }
+    fn eq(&self, other: &PackedGeneric<T, U>) -> bool {
+        { self.0 } == { other.0 } && { self.1 } == { other.1 } &&
+            { self.2 } == { other.2 }
+    }
 }
 #[automatically_derived]
-impl ::core::marker::StructuralEq for PackedNonCopy { }
+impl<T: Trait, U> ::core::marker::StructuralEq for PackedGeneric<T, U> { }
 #[automatically_derived]
-impl ::core::cmp::Eq for PackedNonCopy {
+impl<T: ::core::cmp::Eq + ::core::marker::Copy + Trait, U: ::core::cmp::Eq +
+    ::core::marker::Copy> ::core::cmp::Eq for PackedGeneric<T, U> where
+    T::A: ::core::cmp::Eq + ::core::marker::Copy {
     #[inline]
     #[doc(hidden)]
     #[no_coverage]
     fn assert_receiver_is_total_eq(&self) -> () {
-        let _: ::core::cmp::AssertParamIsEq<u8>;
+        let _: ::core::cmp::AssertParamIsEq<T>;
+        let _: ::core::cmp::AssertParamIsEq<T::A>;
+        let _: ::core::cmp::AssertParamIsEq<U>;
     }
 }
 #[automatically_derived]
-impl ::core::cmp::PartialOrd for PackedNonCopy {
+impl<T: ::core::cmp::PartialOrd + ::core::marker::Copy + Trait,
+    U: ::core::cmp::PartialOrd + ::core::marker::Copy> ::core::cmp::PartialOrd
+    for PackedGeneric<T, U> where T::A: ::core::cmp::PartialOrd +
+    ::core::marker::Copy {
     #[inline]
-    fn partial_cmp(&self, other: &PackedNonCopy)
+    fn partial_cmp(&self, other: &PackedGeneric<T, U>)
         -> ::core::option::Option<::core::cmp::Ordering> {
-        ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
+        match ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
+            {
+            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+                match ::core::cmp::PartialOrd::partial_cmp(&{ self.1 },
+                        &{ other.1 }) {
+                    ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+                        =>
+                        ::core::cmp::PartialOrd::partial_cmp(&{ self.2 },
+                            &{ other.2 }),
+                    cmp => cmp,
+                },
+            cmp => cmp,
+        }
     }
 }
 #[automatically_derived]
-impl ::core::cmp::Ord for PackedNonCopy {
+impl<T: ::core::cmp::Ord + ::core::marker::Copy + Trait, U: ::core::cmp::Ord +
+    ::core::marker::Copy> ::core::cmp::Ord for PackedGeneric<T, U> where
+    T::A: ::core::cmp::Ord + ::core::marker::Copy {
     #[inline]
-    fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering {
-        ::core::cmp::Ord::cmp(&self.0, &other.0)
+    fn cmp(&self, other: &PackedGeneric<T, U>) -> ::core::cmp::Ordering {
+        match ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) {
+            ::core::cmp::Ordering::Equal =>
+                match ::core::cmp::Ord::cmp(&{ self.1 }, &{ other.1 }) {
+                    ::core::cmp::Ordering::Equal =>
+                        ::core::cmp::Ord::cmp(&{ self.2 }, &{ other.2 }),
+                    cmp => cmp,
+                },
+            cmp => cmp,
+        }
     }
 }
 
@@ -1051,6 +1309,125 @@ impl ::core::cmp::Ord for Fielded {
     }
 }
 
+// A generic enum. Note that `Default` cannot be derived for this enum.
+enum EnumGeneric<T, U> { One(T), Two(U), }
+#[automatically_derived]
+impl<T: ::core::clone::Clone, U: ::core::clone::Clone> ::core::clone::Clone
+    for EnumGeneric<T, U> {
+    #[inline]
+    fn clone(&self) -> EnumGeneric<T, U> {
+        match self {
+            EnumGeneric::One(__self_0) =>
+                EnumGeneric::One(::core::clone::Clone::clone(__self_0)),
+            EnumGeneric::Two(__self_0) =>
+                EnumGeneric::Two(::core::clone::Clone::clone(__self_0)),
+        }
+    }
+}
+#[automatically_derived]
+impl<T: ::core::marker::Copy, U: ::core::marker::Copy> ::core::marker::Copy
+    for EnumGeneric<T, U> {
+}
+#[automatically_derived]
+impl<T: ::core::fmt::Debug, U: ::core::fmt::Debug> ::core::fmt::Debug for
+    EnumGeneric<T, U> {
+    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+        match self {
+            EnumGeneric::One(__self_0) =>
+                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "One",
+                    &__self_0),
+            EnumGeneric::Two(__self_0) =>
+                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Two",
+                    &__self_0),
+        }
+    }
+}
+#[automatically_derived]
+impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for
+    EnumGeneric<T, U> {
+    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
+        let __self_tag = ::core::intrinsics::discriminant_value(self);
+        ::core::hash::Hash::hash(&__self_tag, state);
+        match self {
+            EnumGeneric::One(__self_0) =>
+                ::core::hash::Hash::hash(__self_0, state),
+            EnumGeneric::Two(__self_0) =>
+                ::core::hash::Hash::hash(__self_0, state),
+        }
+    }
+}
+#[automatically_derived]
+impl<T, U> ::core::marker::StructuralPartialEq for EnumGeneric<T, U> { }
+#[automatically_derived]
+impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
+    ::core::cmp::PartialEq for EnumGeneric<T, U> {
+    #[inline]
+    fn eq(&self, other: &EnumGeneric<T, U>) -> bool {
+        let __self_tag = ::core::intrinsics::discriminant_value(self);
+        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        __self_tag == __arg1_tag &&
+            match (self, other) {
+                (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
+                    *__self_0 == *__arg1_0,
+                (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) =>
+                    *__self_0 == *__arg1_0,
+                _ => unsafe { ::core::intrinsics::unreachable() }
+            }
+    }
+}
+#[automatically_derived]
+impl<T, U> ::core::marker::StructuralEq for EnumGeneric<T, U> { }
+#[automatically_derived]
+impl<T: ::core::cmp::Eq, U: ::core::cmp::Eq> ::core::cmp::Eq for
+    EnumGeneric<T, U> {
+    #[inline]
+    #[doc(hidden)]
+    #[no_coverage]
+    fn assert_receiver_is_total_eq(&self) -> () {
+        let _: ::core::cmp::AssertParamIsEq<T>;
+        let _: ::core::cmp::AssertParamIsEq<U>;
+    }
+}
+#[automatically_derived]
+impl<T: ::core::cmp::PartialOrd, U: ::core::cmp::PartialOrd>
+    ::core::cmp::PartialOrd for EnumGeneric<T, U> {
+    #[inline]
+    fn partial_cmp(&self, other: &EnumGeneric<T, U>)
+        -> ::core::option::Option<::core::cmp::Ordering> {
+        let __self_tag = ::core::intrinsics::discriminant_value(self);
+        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        match (self, other) {
+            (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) =>
+                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
+            _ =>
+                ::core::cmp::PartialOrd::partial_cmp(&__self_tag,
+                    &__arg1_tag),
+        }
+    }
+}
+#[automatically_derived]
+impl<T: ::core::cmp::Ord, U: ::core::cmp::Ord> ::core::cmp::Ord for
+    EnumGeneric<T, U> {
+    #[inline]
+    fn cmp(&self, other: &EnumGeneric<T, U>) -> ::core::cmp::Ordering {
+        let __self_tag = ::core::intrinsics::discriminant_value(self);
+        let __arg1_tag = ::core::intrinsics::discriminant_value(other);
+        match ::core::cmp::Ord::cmp(&__self_tag, &__arg1_tag) {
+            ::core::cmp::Ordering::Equal =>
+                match (self, other) {
+                    (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
+                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
+                    (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) =>
+                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
+                    _ => unsafe { ::core::intrinsics::unreachable() }
+                },
+            cmp => cmp,
+        }
+    }
+}
+
 // A union. Most builtin traits are not derivable for unions.
 pub union Union {
     pub b: bool,