Allow more deriving on packed structs.
Currently, deriving on packed structs has some non-trivial limitations, related to the fact that taking references on unaligned fields is UB. The current approach to field accesses in derived code: - Normal case: `&self.0` - In a packed struct that derives `Copy`: `&{self.0}` - In a packed struct that doesn't derive `Copy`: `&self.0` Plus, we disallow deriving any builtin traits other than `Default` for any packed generic type, because it's possible that there might be misaligned fields. This is a fairly broad restriction. Plus, we disallow deriving any builtin traits other than `Default` for most packed types that don't derive `Copy`. (The exceptions are those where the alignments inherently satisfy the packing, e.g. in a type with `repr(packed(N))` where all the fields have alignments of `N` or less anyway. Such types are pretty strange, because the `packed` attribute is not having any effect.) This commit introduces a new, simpler approach to field accesses: - Normal case: `&self.0` - In a packed struct: `&{self.0}` In the latter case, this requires that all fields impl `Copy`, which is a new restriction. This means that the following example compiles under the old approach and doesn't compile under the new approach. ``` #[derive(Debug)] struct NonCopy(u8); #[derive(Debug) #[repr(packed)] struct MyType(NonCopy); ``` (Note that the old approach's support for cases like this was brittle. Changing the `u8` to a `u16` would be enough to stop it working. So not much capability is lost here.) However, the other constraints from the old rules are removed. We can now derive builtin traits for packed generic structs like this: ``` trait Trait { type A; } #[derive(Hash)] #[repr(packed)] pub struct Foo<T: Trait>(T, T::A); ``` To allow this, we add a `T: Copy` bound in the derived impl and a `T::A: Copy` bound in where clauses. So `T` and `T::A` must impl `Copy`. We can now also derive builtin traits for packed structs that don't derive `Copy`, so long as the fields impl `Copy`: ``` #[derive(Hash)] #[repr(packed)] pub struct Foo(u32); ``` This includes types that hand-impl `Copy` rather than deriving it, such as the following, that show up in winapi-0.2: ``` #[derive(Clone)] #[repr(packed)] struct MyType(i32); impl Copy for MyType {} ``` The new approach is simpler to understand and implement, and it avoids the need for the `unsafe_derive_on_repr_packed` check. One exception is required for backwards-compatibility: we allow `[u8]` fields for now. There is a new lint for this, `byte_slice_in_packed_struct_with_derive`.
This commit is contained in:
parent
c7bf469fec
commit
2e93f2c92f
@ -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 @@ fn cs_eq(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> BlockOr
|
||||
span,
|
||||
path: path_std!(cmp::PartialEq),
|
||||
skip_path_as_bound: false,
|
||||
needs_copy_as_bound_if_packed: true,
|
||||
additional_bounds: Vec::new(),
|
||||
supports_unions: false,
|
||||
methods,
|
||||
|
@ -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 @@
|
||||
use crate::deriving;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::{
|
||||
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, Generics, Mutability, PatKind,
|
||||
self as ast, BindingAnnotation, ByRef, EnumDef, Expr, GenericArg, GenericParamKind, Generics,
|
||||
Mutability, PatKind, TyKind, VariantData,
|
||||
};
|
||||
use rustc_ast::{GenericArg, GenericParamKind, VariantData};
|
||||
use rustc_attr as attr;
|
||||
use rustc_expand::base::{Annotatable, ExtCtxt};
|
||||
use rustc_session::lint::builtin::BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE;
|
||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use std::cell::RefCell;
|
||||
@ -191,6 +192,9 @@ pub struct TraitDef<'a> {
|
||||
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
|
||||
pub skip_path_as_bound: bool,
|
||||
|
||||
/// Whether `Copy` is needed as an additional bound on type parameters in a packed struct.
|
||||
pub needs_copy_as_bound_if_packed: bool,
|
||||
|
||||
/// Additional bounds required of any type parameters of the type,
|
||||
/// other than the current trait
|
||||
pub additional_bounds: Vec<Ty>,
|
||||
@ -455,18 +459,6 @@ pub fn expand_ext(
|
||||
}
|
||||
false
|
||||
});
|
||||
let has_no_type_params = match &item.kind {
|
||||
ast::ItemKind::Struct(_, generics)
|
||||
| ast::ItemKind::Enum(_, generics)
|
||||
| ast::ItemKind::Union(_, generics) => !generics
|
||||
.params
|
||||
.iter()
|
||||
.any(|param| matches!(param.kind, ast::GenericParamKind::Type { .. })),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
|
||||
let copy_fields =
|
||||
is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id);
|
||||
|
||||
let newitem = match &item.kind {
|
||||
ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
|
||||
@ -475,7 +467,7 @@ pub fn expand_ext(
|
||||
item.ident,
|
||||
generics,
|
||||
from_scratch,
|
||||
copy_fields,
|
||||
is_packed,
|
||||
),
|
||||
ast::ItemKind::Enum(enum_def, generics) => {
|
||||
// We ignore `is_packed` here, because `repr(packed)`
|
||||
@ -493,7 +485,7 @@ pub fn expand_ext(
|
||||
item.ident,
|
||||
generics,
|
||||
from_scratch,
|
||||
copy_fields,
|
||||
is_packed,
|
||||
)
|
||||
} else {
|
||||
cx.span_err(mitem.span, "this trait cannot be derived for unions");
|
||||
@ -565,6 +557,7 @@ fn create_derived_impl(
|
||||
generics: &Generics,
|
||||
field_tys: Vec<P<ast::Ty>>,
|
||||
methods: Vec<P<ast::AssocItem>>,
|
||||
is_packed: bool,
|
||||
) -> P<ast::Item> {
|
||||
let trait_path = self.path.to_path(cx, self.span, type_ident, generics);
|
||||
|
||||
@ -607,20 +600,32 @@ fn create_derived_impl(
|
||||
.map(|param| match ¶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 @@ fn create_derived_impl(
|
||||
.map(|p| cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)))
|
||||
.collect();
|
||||
|
||||
// require the current trait
|
||||
// Require the current trait.
|
||||
bounds.push(cx.trait_bound(trait_path.clone()));
|
||||
|
||||
// Add a `Copy` bound if required.
|
||||
if is_packed && self.needs_copy_as_bound_if_packed {
|
||||
let p = deriving::path_std!(marker::Copy);
|
||||
bounds.push(
|
||||
cx.trait_bound(p.to_path(cx, self.span, type_ident, generics)),
|
||||
);
|
||||
}
|
||||
|
||||
let predicate = ast::WhereBoundPredicate {
|
||||
span: self.span,
|
||||
bound_generic_params: field_ty_param.bound_generic_params,
|
||||
@ -762,7 +775,7 @@ fn expand_struct_def(
|
||||
type_ident: Ident,
|
||||
generics: &Generics,
|
||||
from_scratch: bool,
|
||||
copy_fields: bool,
|
||||
is_packed: bool,
|
||||
) -> P<ast::Item> {
|
||||
let field_tys: Vec<P<ast::Ty>> =
|
||||
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
|
||||
@ -790,7 +803,7 @@ fn expand_struct_def(
|
||||
type_ident,
|
||||
&selflike_args,
|
||||
&nonselflike_args,
|
||||
copy_fields,
|
||||
is_packed,
|
||||
)
|
||||
};
|
||||
|
||||
@ -806,7 +819,7 @@ fn expand_struct_def(
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
|
||||
}
|
||||
|
||||
fn expand_enum_def(
|
||||
@ -861,7 +874,8 @@ fn expand_enum_def(
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods)
|
||||
let is_packed = false; // enums are never packed
|
||||
self.create_derived_impl(cx, type_ident, generics, field_tys, methods, is_packed)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1011,8 +1025,8 @@ fn create_method(
|
||||
/// ```
|
||||
/// But if the struct is `repr(packed)`, we can't use something like
|
||||
/// `&self.x` because that might cause an unaligned ref. So for any trait
|
||||
/// method that takes a reference, if the struct impls `Copy` then we use a
|
||||
/// local block to force a copy:
|
||||
/// method that takes a reference, we use a local block to force a copy.
|
||||
/// This requires that the field impl `Copy`.
|
||||
/// ```
|
||||
/// # struct A { x: u8, y: u8 }
|
||||
/// impl PartialEq for A {
|
||||
@ -1027,10 +1041,6 @@ fn create_method(
|
||||
/// ::core::hash::Hash::hash(&{ self.y }, state)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
/// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This
|
||||
/// only works if the fields match the alignment required by the
|
||||
/// `packed(N)` attribute. (We'll get errors later on if not.)
|
||||
fn expand_struct_method_body<'b>(
|
||||
&self,
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
@ -1039,12 +1049,12 @@ fn expand_struct_method_body<'b>(
|
||||
type_ident: Ident,
|
||||
selflike_args: &[P<Expr>],
|
||||
nonselflike_args: &[P<Expr>],
|
||||
copy_fields: bool,
|
||||
is_packed: bool,
|
||||
) -> BlockOrExpr {
|
||||
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
|
||||
|
||||
let selflike_fields =
|
||||
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields);
|
||||
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, is_packed);
|
||||
self.call_substructure_method(
|
||||
cx,
|
||||
trait_,
|
||||
@ -1514,7 +1524,7 @@ fn create_struct_field_access_fields(
|
||||
cx: &mut ExtCtxt<'_>,
|
||||
selflike_args: &[P<Expr>],
|
||||
struct_def: &'a VariantData,
|
||||
copy_fields: bool,
|
||||
is_packed: bool,
|
||||
) -> Vec<FieldInfo> {
|
||||
self.create_fields(struct_def, |i, struct_field, sp| {
|
||||
selflike_args
|
||||
@ -1533,10 +1543,39 @@ fn create_struct_field_access_fields(
|
||||
}),
|
||||
),
|
||||
);
|
||||
if copy_fields {
|
||||
field_expr = cx.expr_block(
|
||||
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
|
||||
);
|
||||
// In general, fields in packed structs are copied via a
|
||||
// block, e.g. `&{self.0}`. The one exception is `[u8]`
|
||||
// fields, which cannot be copied and also never cause
|
||||
// unaligned references. This exception is allowed to
|
||||
// handle the `FlexZeroSlice` type in the `zerovec` crate
|
||||
// within `icu4x-0.9.0`.
|
||||
//
|
||||
// Once use of `icu4x-0.9.0` has dropped sufficiently, this
|
||||
// exception should be removed.
|
||||
let is_u8_slice = if let TyKind::Slice(ty) = &struct_field.ty.kind &&
|
||||
let TyKind::Path(None, rustc_ast::Path { segments, .. }) = &ty.kind &&
|
||||
let [seg] = segments.as_slice() &&
|
||||
seg.ident.name == sym::u8 && seg.args.is_none()
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if is_packed {
|
||||
if is_u8_slice {
|
||||
cx.sess.parse_sess.buffer_lint_with_diagnostic(
|
||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||
sp,
|
||||
ast::CRATE_NODE_ID,
|
||||
"byte slice in a packed struct that derives a built-in trait",
|
||||
rustc_lint_defs::BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive
|
||||
);
|
||||
} else {
|
||||
// Wrap the expression in `{...}`, causing a copy.
|
||||
field_expr = cx.expr_block(
|
||||
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
|
||||
);
|
||||
}
|
||||
}
|
||||
cx.expr_addr_of(sp, field_expr)
|
||||
})
|
||||
|
@ -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 @@ fn lookup_with_diagnostics(
|
||||
);
|
||||
}
|
||||
}
|
||||
BuiltinLintDiagnostics::ByteSliceInPackedStructWithDerive => {
|
||||
db.help("consider implementing the trait by hand, or remove the `packed` attribute");
|
||||
}
|
||||
}
|
||||
// Rewrap `db`, and pass control to the user.
|
||||
decorate(db)
|
||||
|
@ -3381,6 +3381,7 @@
|
||||
REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
|
||||
NAMED_ARGUMENTS_USED_POSITIONALLY,
|
||||
IMPLIED_BOUNDS_ENTAILMENT,
|
||||
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||
]
|
||||
}
|
||||
|
||||
@ -4109,3 +4110,35 @@
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
|
||||
};
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
/// The `byte_slice_in_packed_struct_with_derive` lint detects cases where a byte slice field
|
||||
/// (`[u8]`) is used in a `packed` struct that derives one or more built-in traits.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```rust
|
||||
/// #[repr(packed)]
|
||||
/// #[derive(Hash)]
|
||||
/// struct FlexZeroSlice {
|
||||
/// width: u8,
|
||||
/// data: [u8],
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// {{produces}}
|
||||
///
|
||||
/// ### Explanation
|
||||
///
|
||||
/// This was previously accepted but is being phased out, because fields in packed structs are
|
||||
/// now required to implement `Copy` for `derive` to work. Byte slices are a temporary
|
||||
/// exception because certain crates depended on them.
|
||||
pub BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
|
||||
Warn,
|
||||
"`[u8]` slice used in a packed struct with `derive`",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reference: "issue #107457 <https://github.com/rust-lang/rust/issues/107457>",
|
||||
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
|
||||
};
|
||||
report_in_external_macro
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -807,15 +807,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/// HACK: when evaluated, this reports an "unsafe derive on repr(packed)" error.
|
||||
///
|
||||
/// Unsafety checking is executed for each method separately, but we only want
|
||||
/// to emit this error once per derive. As there are some impls with multiple
|
||||
/// methods, we use a query for deduplication.
|
||||
query unsafe_derive_on_repr_packed(key: LocalDefId) -> () {
|
||||
desc { |tcx| "processing `{}`", tcx.def_path_str(key.to_def_id()) }
|
||||
}
|
||||
|
||||
/// Returns the types assumed to be well formed while "inside" of the given item.
|
||||
///
|
||||
/// Note that we've liberated the late bound regions of function signatures, so
|
||||
|
@ -1,17 +1,11 @@
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_middle::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::query::Providers;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
|
||||
|
||||
use crate::util;
|
||||
use crate::MirLint;
|
||||
|
||||
pub(crate) fn provide(providers: &mut Providers) {
|
||||
*providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
|
||||
}
|
||||
|
||||
pub struct CheckPackedRef;
|
||||
|
||||
impl<'tcx> MirLint<'tcx> for CheckPackedRef {
|
||||
@ -30,32 +24,6 @@ struct PackedRefChecker<'a, 'tcx> {
|
||||
source_info: SourceInfo,
|
||||
}
|
||||
|
||||
fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
|
||||
|
||||
// FIXME: when we make this a hard error, this should have its
|
||||
// own error code.
|
||||
|
||||
let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
|
||||
"with type or const parameters"
|
||||
} else {
|
||||
"that does not derive `Copy`"
|
||||
};
|
||||
let message = format!(
|
||||
"`{}` can't be derived on this `#[repr(packed)]` struct {}",
|
||||
tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
|
||||
extra
|
||||
);
|
||||
|
||||
tcx.struct_span_lint_hir(
|
||||
UNALIGNED_REFERENCES,
|
||||
lint_hir_id,
|
||||
tcx.def_span(def_id),
|
||||
message,
|
||||
|lint| lint,
|
||||
);
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
|
||||
fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
|
||||
// Make sure we know where in the MIR we are.
|
||||
@ -73,14 +41,13 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
|
||||
if context.is_borrow() {
|
||||
if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
|
||||
let def_id = self.body.source.instance.def_id();
|
||||
if let Some(impl_def_id) = self
|
||||
.tcx
|
||||
.impl_of_method(def_id)
|
||||
.filter(|&def_id| self.tcx.is_builtin_derive(def_id))
|
||||
if let Some(impl_def_id) = self.tcx.impl_of_method(def_id)
|
||||
&& self.tcx.is_builtin_derive(impl_def_id)
|
||||
{
|
||||
// If a method is defined in the local crate,
|
||||
// the impl containing that method should also be.
|
||||
self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local());
|
||||
// If we ever reach here it means that the generated derive
|
||||
// code is somehow doing an unaligned reference, which it
|
||||
// shouldn't do.
|
||||
unreachable!();
|
||||
} else {
|
||||
let source_info = self.source_info;
|
||||
let lint_root = self.body.source_scopes[source_info.scope]
|
||||
|
@ -104,7 +104,6 @@
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
check_unsafety::provide(providers);
|
||||
check_packed_ref::provide(providers);
|
||||
coverage::query::provide(providers);
|
||||
ffi_unwind_calls::provide(providers);
|
||||
shim::provide(providers);
|
||||
|
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…
Reference in New Issue
Block a user