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(),
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 {
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 {
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 {
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,
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],
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 {
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 {
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 {
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 {
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;
/// 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>,
}
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(
item.ident,
generics,
from_scratch,
- copy_fields,
+ is_packed,
),
ast::ItemKind::Enum(enum_def, generics) => {
// We ignore `is_packed` here, because `repr(packed)`
item.ident,
generics,
from_scratch,
- copy_fields,
+ is_packed,
)
} else {
cx.span_err(mitem.span, "this trait cannot be derived for unions");
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);
.map(|param| match ¶m.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)
}
.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,
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();
type_ident,
&selflike_args,
&nonselflike_args,
- copy_fields,
+ is_packed,
)
};
})
.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(
})
.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)
}
}
/// ```
/// 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 {
/// ::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<'_>,
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_,
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
}),
),
);
- 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)
})
span,
path,
skip_path_as_bound: false,
+ needs_copy_as_bound_if_packed: true,
additional_bounds: Vec::new(),
supports_unions: false,
methods: vec![MethodDef {
);
}
}
+ 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)
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
NAMED_ARGUMENTS_USED_POSITIONALLY,
IMPLIED_BOUNDS_ENTAILMENT,
+ BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
]
}
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
}
+
+declare_lint! {
+ /// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field
+ /// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// #[repr(packed)]
+ /// #[derive(Hash)]
+ /// struct FlexZeroSlice {
+ /// width: u8,
+ /// data: [u8],
+ /// }
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// This was previously accepted but is being phased out, because fields in packed structs are
+ /// now required to implement `Copy` for `derive` to work. Byte slices are a temporary
+ /// exception because certain crates depended on them.
+ pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
+ Warn,
+ "`[u8]` slice used in a packed struct with `derive`",
+ @future_incompatible = FutureIncompatibleInfo {
+ reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
+ reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
+ };
+ report_in_external_macro
+}
/// 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
}
}
- /// 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
-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 {
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.
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]
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);
--- /dev/null
+#![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
+}
--- /dev/null
+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`.
#![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() {}
-error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
- --> $DIR/deriving-with-repr-packed.rs:11:16
+warning: byte slice in a packed struct that derives a built-in trait
+ --> $DIR/deriving-with-repr-packed.rs:33:5
|
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
- | ^^^^^
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+...
+LL | data: [u8],
+ | ^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
- --> $DIR/deriving-with-repr-packed.rs:1:9
- |
-LL | #![deny(unaligned_references)]
- | ^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
- --> $DIR/deriving-with-repr-packed.rs:11:32
- |
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
- | ^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
- --> $DIR/deriving-with-repr-packed.rs:19:19
- |
-LL | #[derive(Default, Hash)]
- | ^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
- = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
+ = help: consider implementing the trait by hand, or remove the `packed` attribute
+ = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+ = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
- --> $DIR/deriving-with-repr-packed.rs:39:10
+error[E0507]: cannot move out of `self` which is behind a shared reference
+ --> $DIR/deriving-with-repr-packed.rs:24:10
|
LL | #[derive(Debug, Default)]
- | ^^^^^
+ | ----- in this derive macro expansion
+LL | #[repr(packed)]
+LL | struct X(Y);
+ | ^ move occurs because `self.0` has type `Y`, which does not implement the `Copy` trait
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 4 previous errors
+error: aborting due to previous error; 1 warning emitted
+For more information about this error, try `rustc --explain E0507`.
Future incompatibility report: Future breakage diagnostic:
-error: `Clone` can't be derived on this `#[repr(packed)]` struct with type or const parameters
- --> $DIR/deriving-with-repr-packed.rs:11:16
- |
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
- | ^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
- --> $DIR/deriving-with-repr-packed.rs:1:9
- |
-LL | #![deny(unaligned_references)]
- | ^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: `PartialEq` can't be derived on this `#[repr(packed)]` struct with type or const parameters
- --> $DIR/deriving-with-repr-packed.rs:11:32
- |
-LL | #[derive(Copy, Clone, Default, PartialEq, Eq)]
- | ^^^^^^^^^
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
- --> $DIR/deriving-with-repr-packed.rs:1:9
- |
-LL | #![deny(unaligned_references)]
- | ^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: `Hash` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
- --> $DIR/deriving-with-repr-packed.rs:19:19
- |
-LL | #[derive(Default, Hash)]
- | ^^^^
+warning: byte slice in a packed struct that derives a built-in trait
+ --> $DIR/deriving-with-repr-packed.rs:33:5
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
- --> $DIR/deriving-with-repr-packed.rs:1:9
- |
-LL | #![deny(unaligned_references)]
- | ^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: `Debug` can't be derived on this `#[repr(packed)]` struct that does not derive `Copy`
- --> $DIR/deriving-with-repr-packed.rs:39:10
- |
-LL | #[derive(Debug, Default)]
- | ^^^^^
+LL | #[derive(Debug)]
+ | ----- in this derive macro expansion
+...
+LL | data: [u8],
+ | ^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
-note: the lint level is defined here
- --> $DIR/deriving-with-repr-packed.rs:1:9
- |
-LL | #![deny(unaligned_references)]
- | ^^^^^^^^^^^^^^^^^^^^
- = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: for more information, see issue #107457 <https://github.com/rust-lang/rust/issues/107457>
+ = help: consider implementing the trait by hand, or remove the `packed` attribute
+ = note: `#[warn(byte_slice_in_packed_struct_with_derive)]` on by default
+ = note: this warning originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Empty;
-// A basic struct.
+// A basic struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Point {
x: u32,
y: u32,
}
-// A large struct.
-#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+// A basic packed struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(packed)]
+struct PackedPoint {
+ x: u32,
+ y: u32,
+}
+
+// A large struct. Note: because this derives `Copy`, it gets the simple
+// `clone` implemention that just does `*self`.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Big {
b1: u32, b2: u32, b3: u32, b4: u32, b5: u32, b6: u32, b7: u32, b8: u32,
}
+// A struct that doesn't impl `Copy`, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+struct NonCopy(u32);
+
+// A packed struct that doesn't impl `Copy`, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+#[repr(packed)]
+struct PackedNonCopy(u32);
+
+// A struct that impls `Copy` manually, which means it gets the non-simple
+// `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+struct ManualCopy(u32);
+impl Copy for ManualCopy {}
+
+// A packed struct that impls `Copy` manually, which means it gets the
+// non-simple `clone` implemention that clones the fields individually.
+#[derive(Clone)]
+#[repr(packed)]
+struct PackedManualCopy(u32);
+impl Copy for PackedManualCopy {}
+
// A struct with an unsized field. Some derives are not usable in this case.
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
struct Unsized([u32]);
-// A packed tuple struct that impls `Copy`.
-#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+// A packed struct with an unsized `[u8]` field. This is currently allowed, but
+// causes a warning and will be phased out at some point.
+#[derive(Debug, Hash)]
#[repr(packed)]
-struct PackedCopy(u32);
+struct PackedUnsizedU8([u8]);
+//~^ WARNING byte slice in a packed struct that derives a built-in trait
+//~^^ WARNING byte slice in a packed struct that derives a built-in trait
+//~^^^ this was previously accepted
+//~^^^^ this was previously accepted
-// A packed tuple struct that does not impl `Copy`. Note that the alignment of
-// the field must be 1 for this code to be valid. Otherwise it triggers an
-// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not
-// derive Copy (error E0133)" at MIR building time. This is a weird case and
-// it's possible that this struct is not supposed to work, but for now it does.
-#[derive(Clone, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+trait Trait {
+ type A;
+}
+
+// A generic struct involving an associated type.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
+struct Generic<T: Trait, U> {
+ t: T,
+ ta: T::A,
+ u: U,
+}
+
+// A packed, generic tuple struct involving an associated type. Because it is
+// packed, a `T: Copy` bound is added to all impls (and where clauses within
+// them) except for `Default`. This is because we must access fields using
+// copies (e.g. `&{self.0}`), instead of using direct references (e.g.
+// `&self.0`) which may be misaligned in a packed struct.
+#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(packed)]
-struct PackedNonCopy(u8);
+struct PackedGeneric<T: Trait, U>(T, T::A, U);
// An empty enum.
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
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 {
--- /dev/null
+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)
+
}
}
-// 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,
}
}
-// 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,
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 _ =
}
}
+// 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]
}
}
-// A packed tuple struct that impls `Copy`.
+// A packed struct with an unsized `[u8]` field. This is currently allowed, but
+// causes a warning and will be phased out at some point.
#[repr(packed)]
-struct PackedCopy(u32);
+struct PackedUnsizedU8([u8]);
+#[automatically_derived]
+impl ::core::fmt::Debug for PackedUnsizedU8 {
+ fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
+ ::core::fmt::Formatter::debug_tuple_field1_finish(f,
+ "PackedUnsizedU8", &&self.0)
+ }
+}
#[automatically_derived]
-impl ::core::clone::Clone for PackedCopy {
+impl ::core::hash::Hash for PackedUnsizedU8 {
+ fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
+ ::core::hash::Hash::hash(&self.0, state)
+ }
+}
+
+trait Trait {
+ type A;
+}
+
+// A generic struct involving an associated type.
+struct Generic<T: Trait, U> {
+ t: T,
+ ta: T::A,
+ u: U,
+}
+#[automatically_derived]
+impl<T: ::core::clone::Clone + Trait, U: ::core::clone::Clone>
+ ::core::clone::Clone for Generic<T, U> where T::A: ::core::clone::Clone {
#[inline]
- fn clone(&self) -> PackedCopy {
- let _: ::core::clone::AssertParamIsClone<u32>;
- *self
+ fn clone(&self) -> Generic<T, U> {
+ Generic {
+ t: ::core::clone::Clone::clone(&self.t),
+ ta: ::core::clone::Clone::clone(&self.ta),
+ u: ::core::clone::Clone::clone(&self.u),
+ }
}
}
#[automatically_derived]
-impl ::core::marker::Copy for PackedCopy { }
+impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy>
+ ::core::marker::Copy for Generic<T, U> where T::A: ::core::marker::Copy {
+}
#[automatically_derived]
-impl ::core::fmt::Debug for PackedCopy {
+impl<T: ::core::fmt::Debug + Trait, U: ::core::fmt::Debug> ::core::fmt::Debug
+ for Generic<T, U> where T::A: ::core::fmt::Debug {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
- ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedCopy",
- &&{ self.0 })
+ ::core::fmt::Formatter::debug_struct_field3_finish(f, "Generic", "t",
+ &&self.t, "ta", &&self.ta, "u", &&self.u)
}
}
#[automatically_derived]
-impl ::core::default::Default for PackedCopy {
+impl<T: ::core::default::Default + Trait, U: ::core::default::Default>
+ ::core::default::Default for Generic<T, U> where
+ T::A: ::core::default::Default {
#[inline]
- fn default() -> PackedCopy {
- PackedCopy(::core::default::Default::default())
+ fn default() -> Generic<T, U> {
+ Generic {
+ t: ::core::default::Default::default(),
+ ta: ::core::default::Default::default(),
+ u: ::core::default::Default::default(),
+ }
}
}
#[automatically_derived]
-impl ::core::hash::Hash for PackedCopy {
+impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash
+ for Generic<T, U> where T::A: ::core::hash::Hash {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
- ::core::hash::Hash::hash(&{ self.0 }, state)
+ ::core::hash::Hash::hash(&self.t, state);
+ ::core::hash::Hash::hash(&self.ta, state);
+ ::core::hash::Hash::hash(&self.u, state)
}
}
#[automatically_derived]
-impl ::core::marker::StructuralPartialEq for PackedCopy { }
+impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { }
#[automatically_derived]
-impl ::core::cmp::PartialEq for PackedCopy {
+impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
+ ::core::cmp::PartialEq for Generic<T, U> where
+ T::A: ::core::cmp::PartialEq {
#[inline]
- fn eq(&self, other: &PackedCopy) -> bool { { self.0 } == { other.0 } }
+ fn eq(&self, other: &Generic<T, U>) -> bool {
+ self.t == other.t && self.ta == other.ta && self.u == other.u
+ }
}
#[automatically_derived]
-impl ::core::marker::StructuralEq for PackedCopy { }
+impl<T: Trait, U> ::core::marker::StructuralEq for Generic<T, U> { }
#[automatically_derived]
-impl ::core::cmp::Eq for PackedCopy {
+impl<T: ::core::cmp::Eq + Trait, U: ::core::cmp::Eq> ::core::cmp::Eq for
+ Generic<T, U> where T::A: ::core::cmp::Eq {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq(&self) -> () {
- let _: ::core::cmp::AssertParamIsEq<u32>;
+ let _: ::core::cmp::AssertParamIsEq<T>;
+ let _: ::core::cmp::AssertParamIsEq<T::A>;
+ let _: ::core::cmp::AssertParamIsEq<U>;
}
}
#[automatically_derived]
-impl ::core::cmp::PartialOrd for PackedCopy {
+impl<T: ::core::cmp::PartialOrd + Trait, U: ::core::cmp::PartialOrd>
+ ::core::cmp::PartialOrd for Generic<T, U> where
+ T::A: ::core::cmp::PartialOrd {
#[inline]
- fn partial_cmp(&self, other: &PackedCopy)
+ fn partial_cmp(&self, other: &Generic<T, U>)
-> ::core::option::Option<::core::cmp::Ordering> {
- ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
+ match ::core::cmp::PartialOrd::partial_cmp(&self.t, &other.t) {
+ ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+ match ::core::cmp::PartialOrd::partial_cmp(&self.ta,
+ &other.ta) {
+ ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+ => ::core::cmp::PartialOrd::partial_cmp(&self.u, &other.u),
+ cmp => cmp,
+ },
+ cmp => cmp,
+ }
}
}
#[automatically_derived]
-impl ::core::cmp::Ord for PackedCopy {
+impl<T: ::core::cmp::Ord + Trait, U: ::core::cmp::Ord> ::core::cmp::Ord for
+ Generic<T, U> where T::A: ::core::cmp::Ord {
#[inline]
- fn cmp(&self, other: &PackedCopy) -> ::core::cmp::Ordering {
- ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 })
+ fn cmp(&self, other: &Generic<T, U>) -> ::core::cmp::Ordering {
+ match ::core::cmp::Ord::cmp(&self.t, &other.t) {
+ ::core::cmp::Ordering::Equal =>
+ match ::core::cmp::Ord::cmp(&self.ta, &other.ta) {
+ ::core::cmp::Ordering::Equal =>
+ ::core::cmp::Ord::cmp(&self.u, &other.u),
+ cmp => cmp,
+ },
+ cmp => cmp,
+ }
}
}
-// A packed tuple struct that does not impl `Copy`. Note that the alignment of
-// the field must be 1 for this code to be valid. Otherwise it triggers an
-// error "`#[derive]` can't be used on a `#[repr(packed)]` struct that does not
-// derive Copy (error E0133)" at MIR building time. This is a weird case and
-// it's possible that this struct is not supposed to work, but for now it does.
+// A packed, generic tuple struct involving an associated type. Because it is
+// packed, a `T: Copy` bound is added to all impls (and where clauses within
+// them) except for `Default`. This is because we must access fields using
+// copies (e.g. `&{self.0}`), instead of using direct references (e.g.
+// `&self.0`) which may be misaligned in a packed struct.
#[repr(packed)]
-struct PackedNonCopy(u8);
+struct PackedGeneric<T: Trait, U>(T, T::A, U);
#[automatically_derived]
-impl ::core::clone::Clone for PackedNonCopy {
+impl<T: ::core::clone::Clone + ::core::marker::Copy + Trait,
+ U: ::core::clone::Clone + ::core::marker::Copy> ::core::clone::Clone for
+ PackedGeneric<T, U> where T::A: ::core::clone::Clone +
+ ::core::marker::Copy {
#[inline]
- fn clone(&self) -> PackedNonCopy {
- PackedNonCopy(::core::clone::Clone::clone(&self.0))
+ fn clone(&self) -> PackedGeneric<T, U> {
+ PackedGeneric(::core::clone::Clone::clone(&{ self.0 }),
+ ::core::clone::Clone::clone(&{ self.1 }),
+ ::core::clone::Clone::clone(&{ self.2 }))
}
}
#[automatically_derived]
-impl ::core::fmt::Debug for PackedNonCopy {
+impl<T: ::core::marker::Copy + Trait, U: ::core::marker::Copy>
+ ::core::marker::Copy for PackedGeneric<T, U> where
+ T::A: ::core::marker::Copy {
+}
+#[automatically_derived]
+impl<T: ::core::fmt::Debug + ::core::marker::Copy + Trait,
+ U: ::core::fmt::Debug + ::core::marker::Copy> ::core::fmt::Debug for
+ PackedGeneric<T, U> where T::A: ::core::fmt::Debug + ::core::marker::Copy
+ {
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
- ::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy",
- &&self.0)
+ ::core::fmt::Formatter::debug_tuple_field3_finish(f, "PackedGeneric",
+ &&{ self.0 }, &&{ self.1 }, &&{ self.2 })
}
}
#[automatically_derived]
-impl ::core::default::Default for PackedNonCopy {
+impl<T: ::core::default::Default + Trait, U: ::core::default::Default>
+ ::core::default::Default for PackedGeneric<T, U> where
+ T::A: ::core::default::Default {
#[inline]
- fn default() -> PackedNonCopy {
- PackedNonCopy(::core::default::Default::default())
+ fn default() -> PackedGeneric<T, U> {
+ PackedGeneric(::core::default::Default::default(),
+ ::core::default::Default::default(),
+ ::core::default::Default::default())
}
}
#[automatically_derived]
-impl ::core::hash::Hash for PackedNonCopy {
+impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait,
+ U: ::core::hash::Hash + ::core::marker::Copy> ::core::hash::Hash for
+ PackedGeneric<T, U> where T::A: ::core::hash::Hash + ::core::marker::Copy
+ {
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
- ::core::hash::Hash::hash(&self.0, state)
+ ::core::hash::Hash::hash(&{ self.0 }, state);
+ ::core::hash::Hash::hash(&{ self.1 }, state);
+ ::core::hash::Hash::hash(&{ self.2 }, state)
}
}
#[automatically_derived]
-impl ::core::marker::StructuralPartialEq for PackedNonCopy { }
+impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U>
+ {
+}
#[automatically_derived]
-impl ::core::cmp::PartialEq for PackedNonCopy {
+impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
+ U: ::core::cmp::PartialEq + ::core::marker::Copy> ::core::cmp::PartialEq
+ for PackedGeneric<T, U> where T::A: ::core::cmp::PartialEq +
+ ::core::marker::Copy {
#[inline]
- fn eq(&self, other: &PackedNonCopy) -> bool { self.0 == other.0 }
+ fn eq(&self, other: &PackedGeneric<T, U>) -> bool {
+ { self.0 } == { other.0 } && { self.1 } == { other.1 } &&
+ { self.2 } == { other.2 }
+ }
}
#[automatically_derived]
-impl ::core::marker::StructuralEq for PackedNonCopy { }
+impl<T: Trait, U> ::core::marker::StructuralEq for PackedGeneric<T, U> { }
#[automatically_derived]
-impl ::core::cmp::Eq for PackedNonCopy {
+impl<T: ::core::cmp::Eq + ::core::marker::Copy + Trait, U: ::core::cmp::Eq +
+ ::core::marker::Copy> ::core::cmp::Eq for PackedGeneric<T, U> where
+ T::A: ::core::cmp::Eq + ::core::marker::Copy {
#[inline]
#[doc(hidden)]
#[no_coverage]
fn assert_receiver_is_total_eq(&self) -> () {
- let _: ::core::cmp::AssertParamIsEq<u8>;
+ let _: ::core::cmp::AssertParamIsEq<T>;
+ let _: ::core::cmp::AssertParamIsEq<T::A>;
+ let _: ::core::cmp::AssertParamIsEq<U>;
}
}
#[automatically_derived]
-impl ::core::cmp::PartialOrd for PackedNonCopy {
+impl<T: ::core::cmp::PartialOrd + ::core::marker::Copy + Trait,
+ U: ::core::cmp::PartialOrd + ::core::marker::Copy> ::core::cmp::PartialOrd
+ for PackedGeneric<T, U> where T::A: ::core::cmp::PartialOrd +
+ ::core::marker::Copy {
#[inline]
- fn partial_cmp(&self, other: &PackedNonCopy)
+ fn partial_cmp(&self, other: &PackedGeneric<T, U>)
-> ::core::option::Option<::core::cmp::Ordering> {
- ::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
+ match ::core::cmp::PartialOrd::partial_cmp(&{ self.0 }, &{ other.0 })
+ {
+ ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
+ match ::core::cmp::PartialOrd::partial_cmp(&{ self.1 },
+ &{ other.1 }) {
+ ::core::option::Option::Some(::core::cmp::Ordering::Equal)
+ =>
+ ::core::cmp::PartialOrd::partial_cmp(&{ self.2 },
+ &{ other.2 }),
+ cmp => cmp,
+ },
+ cmp => cmp,
+ }
}
}
#[automatically_derived]
-impl ::core::cmp::Ord for PackedNonCopy {
+impl<T: ::core::cmp::Ord + ::core::marker::Copy + Trait, U: ::core::cmp::Ord +
+ ::core::marker::Copy> ::core::cmp::Ord for PackedGeneric<T, U> where
+ T::A: ::core::cmp::Ord + ::core::marker::Copy {
#[inline]
- fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering {
- ::core::cmp::Ord::cmp(&self.0, &other.0)
+ fn cmp(&self, other: &PackedGeneric<T, U>) -> ::core::cmp::Ordering {
+ match ::core::cmp::Ord::cmp(&{ self.0 }, &{ other.0 }) {
+ ::core::cmp::Ordering::Equal =>
+ match ::core::cmp::Ord::cmp(&{ self.1 }, &{ other.1 }) {
+ ::core::cmp::Ordering::Equal =>
+ ::core::cmp::Ord::cmp(&{ self.2 }, &{ other.2 }),
+ cmp => cmp,
+ },
+ cmp => cmp,
+ }
}
}
}
}
+// 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,