Auto merge of #104429 - nnethercote:more-deriving-on-packed-structs, r=RalfJung

More deriving on packed structs

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

r? `@RalfJung`
This commit is contained in:
bors 2023-01-30 07:02:01 +00:00
commit 3f25e56496
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 @@ pub fn expand_deriving_partial_eq(
span,
path: path_std!(cmp::PartialEq),
skip_path_as_bound: false,
needs_copy_as_bound_if_packed: true,
additional_bounds: Vec::new(),
supports_unions: false,
methods,

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 @@ pub use SubstructureFields::*;
use crate::deriving;
use rustc_ast::ptr::P;
use rustc_ast::{
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
Mutability, PatKind, TyKind, VariantData,
};
use rustc_ast::{GenericArg, GenericParamKind, VariantData};
use rustc_attr as attr;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use std::cell::RefCell;
@ -191,6 +192,9 @@ pub struct TraitDef<'a> {
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
pub skip_path_as_bound: bool,
/// Whether `Copy` is needed as an additional bound on type parameters in a packed struct.
pub needs_copy_as_bound_if_packed: bool,
/// Additional bounds required of any type parameters of the type,
/// other than the current trait
pub additional_bounds: Vec<Ty>,
@ -455,18 +459,6 @@ impl<'a> TraitDef<'a> {
}
false
});
let has_no_type_params = match &item.kind {
ast::ItemKind::Struct(_, generics)
| ast::ItemKind::Enum(_, generics)
| ast::ItemKind::Union(_, generics) => !generics
.params
.iter()
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
_ => unreachable!(),
};
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
let copy_fields =
is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id);
let newitem = match &item.kind {
ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
@ -475,7 +467,7 @@ impl<'a> TraitDef<'a> {
item.ident,
generics,
from_scratch,
copy_fields,
is_packed,
),
ast::ItemKind::Enum(enum_def, generics) => {
// We ignore `is_packed` here, because `repr(packed)`
@ -493,7 +485,7 @@ impl<'a> TraitDef<'a> {
item.ident,
generics,
from_scratch,
copy_fields,
is_packed,
)
} else {
cx.span_err(mitem.span, "this trait cannot be derived for unions");
@ -565,6 +557,7 @@ impl<'a> TraitDef<'a> {
generics: &Generics,
field_tys: Vec<P<ast::Ty>>,
methods: Vec<P<ast::AssocItem>>,
is_packed: bool,
) -> P<ast::Item> {
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
@ -607,20 +600,32 @@ impl<'a> TraitDef<'a> {
.map(|param| match &param.kind {
GenericParamKind::Lifetime { .. } => param.clone(),
GenericParamKind::Type { .. } => {
// I don't think this can be moved out of the loop, since
// a GenericBound requires an ast id
let bounds: Vec<_> =
// extra restrictions on the generics parameters to the
// type being derived upon
self.additional_bounds.iter().map(|p| {
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics))
}).chain(
// require the current trait
self.skip_path_as_bound.not().then(|| cx.trait_bound(trait_path.clone()))
).chain(
// also add in any bounds from the declaration
param.bounds.iter().cloned()
).collect();
// Extra restrictions on the generics parameters to the
// type being derived upon.
let bounds: Vec<_> = self
.additional_bounds
.iter()
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
.chain(
// Add a bound for the current trait.
self.skip_path_as_bound
.not()
.then(|| cx.trait_bound(trait_path.clone())),
)
.chain({
// Add a `Copy` bound if required.
if is_packed && self.needs_copy_as_bound_if_packed {
let p = deriving::path_std!(marker::Copy);
Some(cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
} else {
None
}
})
.chain(
// Also add in any bounds from the declaration.
param.bounds.iter().cloned(),
)
.collect();
cx.typaram(param.ident.span.with_ctxt(ctxt), param.ident, bounds, None)
}
@ -692,9 +697,17 @@ impl<'a> TraitDef<'a> {
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
.collect();
// require the current trait
// Require the current trait.
bounds.push(cx.trait_bound(trait_path.clone()));
// Add a `Copy` bound if required.
if is_packed && self.needs_copy_as_bound_if_packed {
let p = deriving::path_std!(marker::Copy);
bounds.push(
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)),
);
}
let predicate = ast::WhereBoundPredicate {
span: self.span,
bound_generic_params: field_ty_param.bound_generic_params,
@ -762,7 +775,7 @@ impl<'a> TraitDef<'a> {
type_ident: Ident,
generics: &Generics,
from_scratch: bool,
copy_fields: bool,
is_packed: bool,
) -> P<ast::Item> {
let field_tys: Vec<P<ast::Ty>> =
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
@ -790,7 +803,7 @@ impl<'a> TraitDef<'a> {
type_ident,
&selflike_args,
&nonselflike_args,
copy_fields,
is_packed,
)
};
@ -806,7 +819,7 @@ impl<'a> TraitDef<'a> {
})
.collect();
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
}
fn expand_enum_def(
@ -861,7 +874,8 @@ impl<'a> TraitDef<'a> {
})
.collect();
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
let is_packed = false; // enums are never packed
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
}
}
@ -1011,8 +1025,8 @@ impl<'a> MethodDef<'a> {
/// ```
/// But if the struct is `repr(packed)`, we can't use something like
/// `&self.x` because that might cause an unaligned ref. So for any trait
/// method that takes a reference, if the struct impls `Copy` then we use a
/// local block to force a copy:
/// method that takes a reference, we use a local block to force a copy.
/// This requires that the field impl `Copy`.
/// ```
/// # struct A { x: u8, y: u8 }
/// impl PartialEq for A {
@ -1027,10 +1041,6 @@ impl<'a> MethodDef<'a> {
/// ::core::hash::Hash::hash(&{ self.y }, state)
/// }
/// }
/// ```
/// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This
/// only works if the fields match the alignment required by the
/// `packed(N)` attribute. (We'll get errors later on if not.)
fn expand_struct_method_body<'b>(
&self,
cx: &mut ExtCtxt<'_>,
@ -1039,12 +1049,12 @@ impl<'a> MethodDef<'a> {
type_ident: Ident,
selflike_args: &[P<Expr>],
nonselflike_args: &[P<Expr>],
copy_fields: bool,
is_packed: bool,
) -> BlockOrExpr {
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
let selflike_fields =
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields);
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed);
self.call_substructure_method(
cx,
trait_,
@ -1514,7 +1524,7 @@ impl<'a> TraitDef<'a> {
cx: &mut ExtCtxt<'_>,
selflike_args: &[P<Expr>],
struct_def: &'a VariantData,
copy_fields: bool,
is_packed: bool,
) -> Vec<FieldInfo> {
self.create_fields(struct_def, |i, struct_field, sp| {
selflike_args
@ -1533,10 +1543,39 @@ impl<'a> TraitDef<'a> {
}),
),
);
if copy_fields {
field_expr = cx.expr_block(
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
);
// In general, fields in packed structs are copied via a
// block, e.g. `&{self.0}`. The one exception is `[u8]`
// fields, which cannot be copied and also never cause
// unaligned references. This exception is allowed to
// handle the `FlexZeroSlice` type in the `zerovec` crate
// within `icu4x-0.9.0`.
//
// Once use of `icu4x-0.9.0` has dropped sufficiently, this
// exception should be removed.
let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind &&
let [seg] = segments.as_slice() &&
seg.ident.name == sym::u8 && seg.args.is_none()
{
true
} else {
false
};
if is_packed {
if is_u8_slice {
cx.sess.parse_sess.buffer_lint_with_diagnostic(
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
sp,
ast::CRATE_NODE_ID,
"byte slice in a packed struct that derives a built-in trait",
rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
);
} else {
// Wrap the expression in `{...}`, causing a copy.
field_expr = cx.expr_block(
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
);
}
}
cx.expr_addr_of(sp, field_expr)
})

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 @@ pub trait LintContext: Sized {
);
}
}
BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => {
db.help("consider implementing the trait by hand, or remove the `packed` attribute");
}
}
// Rewrap `db`, and pass control to the user.
decorate(db)

View file

@ -3381,6 +3381,7 @@ declare_lint_pass! {
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
NAMED_ARGUMENTS_USED_POSITIONALLY,
IMPLIED_BOUNDS_ENTAILMENT,
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
]
}
@ -4115,3 +4116,35 @@ declare_lint! {
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
}
declare_lint! {
/// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field
/// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits.
///
/// ### Example
///
/// ```rust
/// #[repr(packed)]
/// #[derive(Hash)]
/// struct FlexZeroSlice {
/// width: u8,
/// data: [u8],
/// }
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// This was previously accepted but is being phased out, because fields in packed structs are
/// now required to implement `Copy` for `derive` to work. Byte slices are a temporary
/// exception because certain crates depended on them.
pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
Warn,
"`[u8]` slice used in a packed struct with `derive`",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
report_in_external_macro
}

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

@ -814,15 +814,6 @@ rustc_queries! {
}
}
/// HACK: when evaluated, this reports an "unsafe derive on repr(packed)" error.
///
/// Unsafety checking is executed for each method separately, but we only want
/// to emit this error once per derive. As there are some impls with multiple
/// methods, we use a query for deduplication.
query unsafe_derive_on_repr_packed(key: LocalDefId) -> () {
desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
}
/// Returns the types assumed to be well formed while "inside" of the given item.
///
/// Note that we've liberated the late bound regions of function signatures, so

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 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
if context.is_borrow() {
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
let def_id = self.body.source.instance.def_id();
if let Some(impl_def_id) = self
.tcx
.impl_of_method(def_id)
.filter(|&def_id| self.tcx.is_builtin_derive(def_id))
if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
&& self.tcx.is_builtin_derive(impl_def_id)
{
// If a method is defined in the local crate,
// the impl containing that method should also be.
self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local());
// If we ever reach here it means that the generated derive
// code is somehow doing an unaligned reference, which it
// shouldn't do.
unreachable!();
} else {
let source_info = self.source_info;
let lint_root = self.body.source_scopes[source_info.scope]

View file

@ -104,7 +104,6 @@ use rustc_mir_dataflow::rustc_peek;
pub fn provide(providers: &mut Providers) {
check_unsafety::provide(providers);
check_packed_ref::provide(providers);
coverage::query::provide(providers);
ffi_unwind_calls::provide(providers);
shim::provide(providers);

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,