]> git.lizzy.rs Git - rust.git/commitdiff
Allow more deriving on packed structs.
authorNicholas Nethercote <n.nethercote@gmail.com>
Mon, 21 Nov 2022 03:40:32 +0000 (14:40 +1100)
committerNicholas Nethercote <n.nethercote@gmail.com>
Mon, 30 Jan 2023 01:00:42 +0000 (12:00 +1100)
Currently, deriving on packed structs has some non-trivial limitations,
related to the fact that taking references on unaligned fields is UB.

The current approach to field accesses in derived code:
- Normal case: `&self.0`
- In a packed struct that derives `Copy`: `&{self.0}`
- In a packed struct that doesn't derive `Copy`: `&self.0`

Plus, we disallow deriving any builtin traits other than `Default` for any
packed generic type, because it's possible that there might be
misaligned fields. This is a fairly broad restriction.

Plus, we disallow deriving any builtin traits other than `Default` for most
packed types that don't derive `Copy`. (The exceptions are those where the
alignments inherently satisfy the packing, e.g. in a type with
`repr(packed(N))` where all the fields have alignments of `N` or less
anyway. Such types are pretty strange, because the `packed` attribute is
not having any effect.)

This commit introduces a new, simpler approach to field accesses:
- Normal case: `&self.0`
- In a packed struct: `&{self.0}`

In the latter case, this requires that all fields impl `Copy`, which is
a new restriction. This means that the following example compiles under
the old approach and doesn't compile under the new approach.
```
 #[derive(Debug)]
 struct NonCopy(u8);

 #[derive(Debug)
 #[repr(packed)]
 struct MyType(NonCopy);
```
(Note that the old approach's support for cases like this was brittle.
Changing the `u8` to a `u16` would be enough to stop it working. So not
much capability is lost here.)

However, the other constraints from the old rules are removed. We can now
derive builtin traits for packed generic structs like this:
```
 trait Trait { type A; }

 #[derive(Hash)]
 #[repr(packed)]
 pub struct Foo<T: Trait>(T, T::A);
```
To allow this, we add a `T: Copy` bound in the derived impl and a `T::A:
Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`.

We can now also derive builtin traits for packed structs that don't derive
`Copy`, so long as the fields impl `Copy`:
```
 #[derive(Hash)]
 #[repr(packed)]
 pub struct Foo(u32);
```
This includes types that hand-impl `Copy` rather than deriving it, such as the
following, that show up in winapi-0.2:
```
 #[derive(Clone)]
 #[repr(packed)]
 struct MyType(i32);

 impl Copy for MyType {}
```
The new approach is simpler to understand and implement, and it avoids
the need for the `unsafe_derive_on_repr_packed` check.

One exception is required for backwards-compatibility: we allow `[u8]`
fields for now. There is a new lint for this,
`byte_slice_in_packed_struct_with_derive`.

25 files changed:
compiler/rustc_builtin_macros/src/deriving/bounds.rs
compiler/rustc_builtin_macros/src/deriving/clone.rs
compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
compiler/rustc_builtin_macros/src/deriving/debug.rs
compiler/rustc_builtin_macros/src/deriving/decodable.rs
compiler/rustc_builtin_macros/src/deriving/default.rs
compiler/rustc_builtin_macros/src/deriving/encodable.rs
compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
compiler/rustc_builtin_macros/src/deriving/hash.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_middle/src/query/mod.rs
compiler/rustc_mir_transform/src/check_packed_ref.rs
compiler/rustc_mir_transform/src/lib.rs
tests/ui/derives/deriving-with-repr-packed-2.rs [new file with mode: 0644]
tests/ui/derives/deriving-with-repr-packed-2.stderr [new file with mode: 0644]
tests/ui/derives/deriving-with-repr-packed.rs
tests/ui/derives/deriving-with-repr-packed.stderr
tests/ui/deriving/deriving-all-codegen.rs
tests/ui/deriving/deriving-all-codegen.stderr [new file with mode: 0644]
tests/ui/deriving/deriving-all-codegen.stdout

index 240167146e1f134c08cf93a1fe4514c53ff41a42..0481a118906902697eb25900fda82ca07c5c5d6d 100644 (file)
@@ -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(),
index ef5a75f428d4e979c8582c5708c79a8c9854180e..42f50d8ade2785c2535374a6bb2ccc69bfef2a41 100644 (file)
@@ -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 {
index 3e994f037ad7aa7e2843b0a271257b679bbab3e4..424719f97954f743b2115600469d96ee80ef7fa5 100644 (file)
@@ -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 {
index a926fca4e65f8ac21fe7eabd06a1c260d5c0b474..671f32550d2bbee957dd2775fa0976c1a8cefee7 100644 (file)
@@ -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 {
index 9051fe0b28abec750146a6435e0b50c021e99d6f..88d454fbc11230f5ad04f55269112bd8789dc1d9 100644 (file)
@@ -84,6 +84,7 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr
         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,
index 2fc30d8e05f2c6748c4e03ed0a07d056105e3439..bcc90442eb72bb91aef8f06a7cd2830155d881ff 100644 (file)
@@ -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],
index e0f487e864898d72d530efd0d1b1b0815d01894d..897048f64211e37d509d31457f1d71cf4d7edf3f 100644 (file)
@@ -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 {
index 5f9519dad1b25e91213e145a4ec768cc376f5d01..c783e46eda9416ba23bb00a77d536e61d97891af 100644 (file)
@@ -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 {
index 18270747296b8f7c7d8762e141f7c8df88da5f36..a6c8b111527a3e241f26e55dfef9fa92ddf533e3 100644 (file)
@@ -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 {
index 2afeed927ac2c7664d8e941f211f7c3f3bccff74..a5e2b599df4e8f0fae48ee2848f6c4bb2a772407 100644 (file)
@@ -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 {
index 17b7ac0eba1209de55bddbee1ba6087945b409ed..97de40bac34661f12d86e27e12a139ae76ebdd36 100644 (file)
 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 @@ pub fn expand_ext(
                     }
                     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 @@ pub fn expand_ext(
                         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 @@ pub fn expand_ext(
                                 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 @@ fn create_derived_impl(
         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 @@ fn create_derived_impl(
             .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 @@ fn create_derived_impl(
                             .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 @@ fn expand_struct_def(
         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 @@ fn expand_struct_def(
                         type_ident,
                         &selflike_args,
                         &nonselflike_args,
-                        copy_fields,
+                        is_packed,
                     )
                 };
 
@@ -806,7 +819,7 @@ fn expand_struct_def(
             })
             .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 @@ fn expand_enum_def(
             })
             .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 @@ fn create_method(
     /// ```
     /// 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 @@ fn create_method(
     ///         ::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 @@ fn expand_struct_method_body<'b>(
         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 @@ fn create_struct_field_access_fields(
         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 @@ fn create_struct_field_access_fields(
                             }),
                         ),
                     );
-                    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)
                 })
index f8570d8f86a08dd691fe82dbd23c26518afcde24..5c2e89c5697b2776478d0dd5c707d15d957bfa0c 100644 (file)
@@ -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 {
index 8046cc21cea583eb73f15cb45228593a05139af6..d1d4bb375282f004673fb63bf2141c002f7b9956 100644 (file)
@@ -882,6 +882,9 @@ fn lookup_with_diagnostics(
                         );
                     }
                 }
+                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)
index b6481d70bc8898fe2de912d9f382e90233fa28bd..4438639d635283aa27119116e5d66689749adfdb 100644 (file)
         REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
         NAMED_ARGUMENTS_USED_POSITIONALLY,
         IMPLIED_BOUNDS_ENTAILMENT,
+        BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
     ]
 }
 
         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
+}
index 7054d1e9f105e4392e513f197f3dc91d0632fe2c..6efbf5ce9eef308fa1100512b6f76ea6fc583bdf 100644 (file)
@@ -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
index 3917a97db4f08eb1ed6889c5f8011ae7ffba17b9..fd1e2c072de348492151d7888321a17e51c5d85f 100644 (file)
         }
     }
 
-    /// 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
index 51abcf51189f62b92984d8db0838fa1741f5d6fb..3e7571aa7a2e7f303fa0e02cc6fbd1f51f7906ac 100644 (file)
@@ -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 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
         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]
index abf89e550b14922973d1afeb584eb79ebd97bc97..3d9137fa10253cc4934c3f2f8e4d0aa19be96315 100644 (file)
 
 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 (file)
index 0000000..cbd7432
--- /dev/null
@@ -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 (file)
index 0000000..8354073
--- /dev/null
@@ -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`.
index 3884e397764e75e504bd1f87c9ddc77746cd0f78..eddf41f55536e4e7ecb5ceeff537a22fd7910b84 100644 (file)
@@ -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() {}
index 0ad800c398180af7c93fa4781578c8e001f0ee1b..2cb2a696d9742ffe3357c0c7892ade4838bd01ff 100644 (file)
-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)
 
index ba7809413bd804bc2b7ffa828c12b733abed418b..51f9708d3cd629518734df9d0dc9d80473430de7 100644 (file)
 #[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 (file)
index 0000000..503f0ca
--- /dev/null
@@ -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)
+
index 2a93a05c627698a2e1eb03e57133fed99215a508..b4874cef134f77df98fd94427bf3a878021c54bf 100644 (file)
@@ -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,