Skip to content

Commit 439a8e6

Browse files
authored
Rollup merge of #104662 - nnethercote:tweak-deriving-for-packed-non-copy, r=jackh726
Streamline deriving on packed structs. 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`: `let Self(ref x) = *self` The `let` pattern used in the third case is equivalent to the simpler field access in the first case. This commit changes the third case to use a field access. The commit also combines two boolean arguments (`is_packed` and `always_copy`) into a single field (`copy_fields`) earlier, to save passing both around. r? ``@jackh726``
2 parents 5b92892 + a6e09a1 commit 439a8e6

File tree

2 files changed

+30
-87
lines changed

2 files changed

+30
-87
lines changed

compiler/rustc_builtin_macros/src/deriving/generic/mod.rs

+24-70
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,8 @@ impl<'a> TraitDef<'a> {
448448
_ => unreachable!(),
449449
};
450450
let container_id = cx.current_expansion.id.expn_data().parent.expect_local();
451-
let always_copy = has_no_type_params && cx.resolver.has_derive_copy(container_id);
451+
let copy_fields =
452+
is_packed && has_no_type_params && cx.resolver.has_derive_copy(container_id);
452453

453454
let newitem = match item.kind {
454455
ast::ItemKind::Struct(ref struct_def, ref generics) => self.expand_struct_def(
@@ -457,16 +458,14 @@ impl<'a> TraitDef<'a> {
457458
item.ident,
458459
generics,
459460
from_scratch,
460-
is_packed,
461-
always_copy,
461+
copy_fields,
462462
),
463463
ast::ItemKind::Enum(ref enum_def, ref generics) => {
464-
// We ignore `is_packed`/`always_copy` here, because
465-
// `repr(packed)` enums cause an error later on.
464+
// We ignore `is_packed` here, because `repr(packed)`
465+
// enums cause an error later on.
466466
//
467467
// This can only cause further compilation errors
468-
// downstream in blatantly illegal code, so it
469-
// is fine.
468+
// downstream in blatantly illegal code, so it is fine.
470469
self.expand_enum_def(cx, enum_def, item.ident, generics, from_scratch)
471470
}
472471
ast::ItemKind::Union(ref struct_def, ref generics) => {
@@ -477,8 +476,7 @@ impl<'a> TraitDef<'a> {
477476
item.ident,
478477
generics,
479478
from_scratch,
480-
is_packed,
481-
always_copy,
479+
copy_fields,
482480
)
483481
} else {
484482
cx.span_err(mitem.span, "this trait cannot be derived for unions");
@@ -748,8 +746,7 @@ impl<'a> TraitDef<'a> {
748746
type_ident: Ident,
749747
generics: &Generics,
750748
from_scratch: bool,
751-
is_packed: bool,
752-
always_copy: bool,
749+
copy_fields: bool,
753750
) -> P<ast::Item> {
754751
let field_tys: Vec<P<ast::Ty>> =
755752
struct_def.fields().iter().map(|field| field.ty.clone()).collect();
@@ -777,8 +774,7 @@ impl<'a> TraitDef<'a> {
777774
type_ident,
778775
&selflike_args,
779776
&nonselflike_args,
780-
is_packed,
781-
always_copy,
777+
copy_fields,
782778
)
783779
};
784780

@@ -1016,19 +1012,9 @@ impl<'a> MethodDef<'a> {
10161012
/// }
10171013
/// }
10181014
/// ```
1019-
/// If the struct doesn't impl `Copy`, we use let-destructuring with `ref`:
1020-
/// ```
1021-
/// # struct A { x: u8, y: u8 }
1022-
/// impl PartialEq for A {
1023-
/// fn eq(&self, other: &A) -> bool {
1024-
/// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self;
1025-
/// let Self { x: ref __self_1_0, y: ref __self_1_1 } = *other;
1026-
/// *__self_0_0 == *__self_1_0 && *__self_0_1 == *__self_1_1
1027-
/// }
1028-
/// }
1029-
/// ```
1030-
/// This latter case only works if the fields match the alignment required
1031-
/// by the `packed(N)` attribute. (We'll get errors later on if not.)
1015+
/// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This
1016+
/// only works if the fields match the alignment required by the
1017+
/// `packed(N)` attribute. (We'll get errors later on if not.)
10321018
fn expand_struct_method_body<'b>(
10331019
&self,
10341020
cx: &mut ExtCtxt<'_>,
@@ -1037,51 +1023,19 @@ impl<'a> MethodDef<'a> {
10371023
type_ident: Ident,
10381024
selflike_args: &[P<Expr>],
10391025
nonselflike_args: &[P<Expr>],
1040-
is_packed: bool,
1041-
always_copy: bool,
1026+
copy_fields: bool,
10421027
) -> BlockOrExpr {
1043-
let span = trait_.span;
10441028
assert!(selflike_args.len() == 1 || selflike_args.len() == 2);
10451029

1046-
let mk_body = |cx, selflike_fields| {
1047-
self.call_substructure_method(
1048-
cx,
1049-
trait_,
1050-
type_ident,
1051-
nonselflike_args,
1052-
&Struct(struct_def, selflike_fields),
1053-
)
1054-
};
1055-
1056-
if !is_packed {
1057-
let selflike_fields =
1058-
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, false);
1059-
mk_body(cx, selflike_fields)
1060-
} else if always_copy {
1061-
let selflike_fields =
1062-
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, true);
1063-
mk_body(cx, selflike_fields)
1064-
} else {
1065-
// Packed and not copy. Need to use ref patterns.
1066-
let prefixes: Vec<_> =
1067-
(0..selflike_args.len()).map(|i| format!("__self_{}", i)).collect();
1068-
let selflike_fields = trait_.create_struct_pattern_fields(cx, struct_def, &prefixes);
1069-
let mut body = mk_body(cx, selflike_fields);
1070-
1071-
let struct_path = cx.path(span, vec![Ident::new(kw::SelfUpper, type_ident.span)]);
1072-
let patterns =
1073-
trait_.create_struct_patterns(cx, struct_path, struct_def, &prefixes, ByRef::Yes);
1074-
1075-
// Do the let-destructuring.
1076-
let mut stmts: Vec<_> = iter::zip(selflike_args, patterns)
1077-
.map(|(selflike_arg_expr, pat)| {
1078-
let selflike_arg_expr = cx.expr_deref(span, selflike_arg_expr.clone());
1079-
cx.stmt_let_pat(span, pat, selflike_arg_expr)
1080-
})
1081-
.collect();
1082-
stmts.extend(std::mem::take(&mut body.0));
1083-
BlockOrExpr(stmts, body.1)
1084-
}
1030+
let selflike_fields =
1031+
trait_.create_struct_field_access_fields(cx, selflike_args, struct_def, copy_fields);
1032+
self.call_substructure_method(
1033+
cx,
1034+
trait_,
1035+
type_ident,
1036+
nonselflike_args,
1037+
&Struct(struct_def, selflike_fields),
1038+
)
10851039
}
10861040

10871041
fn expand_static_struct_method_body(
@@ -1531,7 +1485,7 @@ impl<'a> TraitDef<'a> {
15311485
cx: &mut ExtCtxt<'_>,
15321486
selflike_args: &[P<Expr>],
15331487
struct_def: &'a VariantData,
1534-
copy: bool,
1488+
copy_fields: bool,
15351489
) -> Vec<FieldInfo> {
15361490
self.create_fields(struct_def, |i, struct_field, sp| {
15371491
selflike_args
@@ -1550,7 +1504,7 @@ impl<'a> TraitDef<'a> {
15501504
}),
15511505
),
15521506
);
1553-
if copy {
1507+
if copy_fields {
15541508
field_expr = cx.expr_block(
15551509
cx.block(struct_field.span, vec![cx.stmt_expr(field_expr)]),
15561510
);

src/test/ui/deriving/deriving-all-codegen.stdout

+6-17
Original file line numberDiff line numberDiff line change
@@ -463,16 +463,14 @@ struct PackedNonCopy(u8);
463463
impl ::core::clone::Clone for PackedNonCopy {
464464
#[inline]
465465
fn clone(&self) -> PackedNonCopy {
466-
let Self(ref __self_0_0) = *self;
467-
PackedNonCopy(::core::clone::Clone::clone(__self_0_0))
466+
PackedNonCopy(::core::clone::Clone::clone(&self.0))
468467
}
469468
}
470469
#[automatically_derived]
471470
impl ::core::fmt::Debug for PackedNonCopy {
472471
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
473-
let Self(ref __self_0_0) = *self;
474472
::core::fmt::Formatter::debug_tuple_field1_finish(f, "PackedNonCopy",
475-
&__self_0_0)
473+
&&self.0)
476474
}
477475
}
478476
#[automatically_derived]
@@ -485,20 +483,15 @@ impl ::core::default::Default for PackedNonCopy {
485483
#[automatically_derived]
486484
impl ::core::hash::Hash for PackedNonCopy {
487485
fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
488-
let Self(ref __self_0_0) = *self;
489-
::core::hash::Hash::hash(__self_0_0, state)
486+
::core::hash::Hash::hash(&self.0, state)
490487
}
491488
}
492489
#[automatically_derived]
493490
impl ::core::marker::StructuralPartialEq for PackedNonCopy { }
494491
#[automatically_derived]
495492
impl ::core::cmp::PartialEq for PackedNonCopy {
496493
#[inline]
497-
fn eq(&self, other: &PackedNonCopy) -> bool {
498-
let Self(ref __self_0_0) = *self;
499-
let Self(ref __self_1_0) = *other;
500-
*__self_0_0 == *__self_1_0
501-
}
494+
fn eq(&self, other: &PackedNonCopy) -> bool { self.0 == other.0 }
502495
}
503496
#[automatically_derived]
504497
impl ::core::marker::StructuralEq for PackedNonCopy { }
@@ -516,18 +509,14 @@ impl ::core::cmp::PartialOrd for PackedNonCopy {
516509
#[inline]
517510
fn partial_cmp(&self, other: &PackedNonCopy)
518511
-> ::core::option::Option<::core::cmp::Ordering> {
519-
let Self(ref __self_0_0) = *self;
520-
let Self(ref __self_1_0) = *other;
521-
::core::cmp::PartialOrd::partial_cmp(__self_0_0, __self_1_0)
512+
::core::cmp::PartialOrd::partial_cmp(&self.0, &other.0)
522513
}
523514
}
524515
#[automatically_derived]
525516
impl ::core::cmp::Ord for PackedNonCopy {
526517
#[inline]
527518
fn cmp(&self, other: &PackedNonCopy) -> ::core::cmp::Ordering {
528-
let Self(ref __self_0_0) = *self;
529-
let Self(ref __self_1_0) = *other;
530-
::core::cmp::Ord::cmp(__self_0_0, __self_1_0)
519+
::core::cmp::Ord::cmp(&self.0, &other.0)
531520
}
532521
}
533522

0 commit comments

Comments
 (0)