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:
commit
3f25e56496
25 changed files with 874 additions and 349 deletions
|
@ -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(),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 ¶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)
|
||||
}
|
||||
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
|
|
22
tests/ui/derives/deriving-with-repr-packed-2.rs
Normal file
22
tests/ui/derives/deriving-with-repr-packed-2.rs
Normal 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
|
||||
}
|
33
tests/ui/derives/deriving-with-repr-packed-2.stderr
Normal file
33
tests/ui/derives/deriving-with-repr-packed-2.stderr
Normal 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`.
|
|
@ -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() {}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
63
tests/ui/deriving/deriving-all-codegen.stderr
Normal file
63
tests/ui/deriving/deriving-all-codegen.stderr
Normal 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)
|
||||
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue