Allow more deriving on packed structs.

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`.
This commit is contained in:
Nicholas Nethercote 2022-11-21 14:40:32 +11:00
parent c7bf469fec
commit 2e93f2c92f
25 changed files with 874 additions and 349 deletions

View 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(),

View 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 {

View 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 {

View 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 {

View 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,

View 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],

View 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 {

View 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 {

View 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 {

View 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 {

View file

@ -165,11 +165,12 @@
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)
})

View 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 {

View 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)

View file

@ -3381,6 +3381,7 @@
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
NAMED_ARGUMENTS_USED_POSITIONALLY,
IMPLIED_BOUNDS_ENTAILMENT,
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
]
}
@ -4109,3 +4110,35 @@
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
}

View 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

View file

@ -807,15 +807,6 @@
}
}
/// 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

View 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]

View file

@ -104,7 +104,6 @@
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);

View file

@ -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
}

View file

@ -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`.

View 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() {}

View file

@ -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)
= 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: `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)
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
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)
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: 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)]
| ^^^^^
|
= 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)

View file

@ -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`.
// 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 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
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 PackedCopy(u32);
// 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)]
#[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 {

View file

@ -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)

View 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::clone::Clone for PackedCopy {
#[inline]
fn clone(&self) -> PackedCopy {
let _: ::core::clone::AssertParamIsClone<u32>;
*self
}
}
#[automatically_derived]
impl ::core::marker::Copy for PackedCopy { }
#[automatically_derived]
impl ::core::fmt::Debug for PackedCopy {
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, "PackedCopy",
&&{ self.0 })
::core::fmt::Formatter::debug_tuple_field1_finish(f,
"PackedUnsizedU8", &&self.0)
}
}
#[automatically_derived]
impl ::core::default::Default for PackedCopy {
#[inline]
fn default() -> PackedCopy {
PackedCopy(::core::default::Default::default())
}
}
#[automatically_derived]
impl ::core::hash::Hash for PackedCopy {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&{ self.0 }, state)
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for PackedCopy { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PackedCopy {
#[inline]
fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
}
#[automatically_derived]
impl ::core::marker::StructuralEq for PackedCopy { }
#[automatically_derived]
impl ::core::cmp::Eq for PackedCopy {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq(&self) -> () {
let _: ::core::cmp::AssertParamIsEq<u32>;
}
}
#[automatically_derived]
impl ::core::cmp::PartialOrd for PackedCopy {
#[inline]
fn partial_cmp(&self, other: &PackedCopy)
-> ::core::option::Option<::core::cmp::Ordering> {
::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
}
}
#[automatically_derived]
impl ::core::cmp::Ord for PackedCopy {
#[inline]
fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 })
}
}
// 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.
#[repr(packed)]
struct PackedNonCopy(u8);
#[automatically_derived]
impl ::core::clone::Clone for PackedNonCopy {
#[inline]
fn clone(&self) -> PackedNonCopy {
PackedNonCopy(::core::clone::Clone::clone(&self.0))
}
}
#[automatically_derived]
impl ::core::fmt::Debug for PackedNonCopy {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy",
&&self.0)
}
}
#[automatically_derived]
impl ::core::default::Default for PackedNonCopy {
#[inline]
fn default() -> PackedNonCopy {
PackedNonCopy(::core::default::Default::default())
}
}
#[automatically_derived]
impl ::core::hash::Hash for PackedNonCopy {
impl ::core::hash::Hash for PackedUnsizedU8 {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
::core::hash::Hash::hash(&self.0, state)
}
}
#[automatically_derived]
impl ::core::marker::StructuralPartialEq for PackedNonCopy { }
#[automatically_derived]
impl ::core::cmp::PartialEq for PackedNonCopy {
#[inline]
fn eq(&self, other: &PackedNonCopy) -> bool { self.0 == other.0 }
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 ::core::marker::StructuralEq for PackedNonCopy { }
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) -> 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::cmp::Eq for PackedNonCopy {
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<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_struct_field3_finish(f, "Generic", "t",
&&self.t, "ta", &&self.ta, "u", &&self.u)
}
}
#[automatically_derived]
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() -> Generic<T, U> {
Generic {
t: ::core::default::Default::default(),
ta: ::core::default::Default::default(),
u: ::core::default::Default::default(),
}
}
}
#[automatically_derived]
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.t, state);
::core::hash::Hash::hash(&self.ta, state);
::core::hash::Hash::hash(&self.u, state)
}
}
#[automatically_derived]
impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { }
#[automatically_derived]
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: &Generic<T, U>) -> bool {
self.t == other.t && self.ta == other.ta && self.u == other.u
}
}
#[automatically_derived]
impl<T: Trait, U> ::core::marker::StructuralEq for Generic<T, U> { }
#[automatically_derived]
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<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 + Trait, U: ::core::cmp::PartialOrd>
::core::cmp::PartialOrd for Generic<T, U> where
T::A: ::core::cmp::PartialOrd {
#[inline]
fn partial_cmp(&self, other: &PackedNonCopy)
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 PackedNonCopy {
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: &PackedNonCopy) -> ::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, 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 PackedGeneric<T: Trait, U>(T, T::A, U);
#[automatically_derived]
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) -> 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<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_field3_finish(f, "PackedGeneric",
&&{ self.0 }, &&{ self.1 }, &&{ self.2 })
}
}
#[automatically_derived]
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() -> PackedGeneric<T, U> {
PackedGeneric(::core::default::Default::default(),
::core::default::Default::default(),
::core::default::Default::default())
}
}
#[automatically_derived]
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.1 }, state);
::core::hash::Hash::hash(&{ self.2 }, state)
}
}
#[automatically_derived]
impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U>
{
}
#[automatically_derived]
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: &PackedGeneric<T, U>) -> bool {
{ self.0 } == { other.0 } && { self.1 } == { other.1 } &&
{ self.2 } == { other.2 }
}
}
#[automatically_derived]
impl<T: Trait, U> ::core::marker::StructuralEq for PackedGeneric<T, U> { }
#[automatically_derived]
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<T>;
let _: ::core::cmp::AssertParamIsEq<T::A>;
let _: ::core::cmp::AssertParamIsEq<U>;
}
}
#[automatically_derived]
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: &PackedGeneric<T, U>)
-> ::core::option::Option<::core::cmp::Ordering> {
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<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: &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,