@@ -429,6 +429,7 @@ impl<'a> TraitDef<'a> {
429429 generics,
430430 from_scratch,
431431 use_temporaries,
432+ is_packed,
432433 ) ,
433434 ast:: ItemKind :: Enum ( ref enum_def, ref generics) => {
434435 // We ignore `use_temporaries` here, because
@@ -448,6 +449,7 @@ impl<'a> TraitDef<'a> {
448449 generics,
449450 from_scratch,
450451 use_temporaries,
452+ is_packed,
451453 )
452454 } else {
453455 cx. span_err ( mitem. span , "this trait cannot be derived for unions" ) ;
@@ -729,6 +731,7 @@ impl<'a> TraitDef<'a> {
729731 generics : & Generics ,
730732 from_scratch : bool ,
731733 use_temporaries : bool ,
734+ is_packed : bool ,
732735 ) -> P < ast:: Item > {
733736 let field_tys: Vec < P < ast:: Ty > > =
734737 struct_def. fields ( ) . iter ( ) . map ( |field| field. ty . clone ( ) ) . collect ( ) ;
@@ -757,6 +760,7 @@ impl<'a> TraitDef<'a> {
757760 & self_args,
758761 & nonself_args,
759762 use_temporaries,
763+ is_packed,
760764 )
761765 } ;
762766
@@ -945,6 +949,7 @@ impl<'a> MethodDef<'a> {
945949 } )
946950 }
947951
952+ /// The normal case uses field access.
948953 /// ```
949954 /// #[derive(PartialEq)]
950955 /// # struct Dummy;
@@ -953,33 +958,21 @@ impl<'a> MethodDef<'a> {
953958 /// // equivalent to:
954959 /// impl PartialEq for A {
955960 /// fn eq(&self, other: &A) -> bool {
956- /// match *self {
957- /// A {x: ref __self_0_0, y: ref __self_0_1} => {
958- /// match *other {
959- /// A {x: ref __self_1_0, y: ref __self_1_1} => {
960- /// __self_0_0.eq(__self_1_0) && __self_0_1.eq(__self_1_1)
961- /// }
962- /// }
963- /// }
964- /// }
961+ /// self.x == other.x && self.y == other.y
965962 /// }
966963 /// }
967964 /// ```
968- /// or if A is repr(packed) - note fields are matched by-value
969- /// instead of by-reference.
965+ /// But if the struct is `repr(packed)`, we can't use something like
966+ /// `&self.x` on a packed type (as required for e.g. `Debug` and `Hash`)
967+ /// because that might cause an unaligned ref. So we use let-destructuring
968+ /// instead.
970969 /// ```
971970 /// # struct A { x: i32, y: i32 }
972971 /// impl PartialEq for A {
973972 /// fn eq(&self, other: &A) -> bool {
974- /// match *self {
975- /// A {x: __self_0_0, y: __self_0_1} => {
976- /// match other {
977- /// A {x: __self_1_0, y: __self_1_1} => {
978- /// __self_0_0.eq(&__self_1_0) && __self_0_1.eq(&__self_1_1)
979- /// }
980- /// }
981- /// }
982- /// }
973+ /// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self;
974+ /// let Self { x: ref __self_1_0, y: ref __self_1_1 } = *other;
975+ /// *__self_0_0 == *__self_1_0 && *__self_0_1 == *__self_1_1
983976 /// }
984977 /// }
985978 /// ```
@@ -992,24 +985,33 @@ impl<'a> MethodDef<'a> {
992985 self_args : & [ P < Expr > ] ,
993986 nonself_args : & [ P < Expr > ] ,
994987 use_temporaries : bool ,
988+ is_packed : bool ,
995989 ) -> P < Expr > {
996990 let mut raw_fields = Vec :: new ( ) ; // Vec<[fields of self], [fields of next Self arg], [etc]>
997991 let span = trait_. span ;
998992 let mut patterns = Vec :: new ( ) ;
999- for i in 0 ..self_args. len ( ) {
1000- // We could use `type_ident` instead of `Self`, but in the case of a type parameter
1001- // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343
1002- let struct_path = cx. path ( span, vec ! [ Ident :: new( kw:: SelfUpper , type_ident. span) ] ) ;
1003- let ( pat, ident_expr) = trait_. create_struct_pattern (
1004- cx,
1005- struct_path,
1006- struct_def,
1007- & format ! ( "__self_{}" , i) ,
1008- ast:: Mutability :: Not ,
1009- use_temporaries,
1010- ) ;
1011- patterns. push ( pat) ;
1012- raw_fields. push ( ident_expr) ;
993+
994+ for ( i, self_arg) in self_args. iter ( ) . enumerate ( ) {
995+ let ident_exprs = if !is_packed {
996+ trait_. create_struct_field_accesses ( cx, self_arg, struct_def)
997+ } else {
998+ // Get the pattern for the let-destructuring.
999+ //
1000+ // We could use `type_ident` instead of `Self`, but in the case of a type parameter
1001+ // shadowing the struct name, that causes a second, unnecessary E0578 error. #97343
1002+ let struct_path = cx. path ( span, vec ! [ Ident :: new( kw:: SelfUpper , type_ident. span) ] ) ;
1003+ let ( pat, ident_exprs) = trait_. create_struct_pattern (
1004+ cx,
1005+ struct_path,
1006+ struct_def,
1007+ & format ! ( "__self_{}" , i) ,
1008+ ast:: Mutability :: Not ,
1009+ use_temporaries,
1010+ ) ;
1011+ patterns. push ( pat) ;
1012+ ident_exprs
1013+ } ;
1014+ raw_fields. push ( ident_exprs) ;
10131015 }
10141016
10151017 // transpose raw_fields
@@ -1036,7 +1038,6 @@ impl<'a> MethodDef<'a> {
10361038 cx. span_bug ( span, "no `self` parameter for method in generic `derive`" )
10371039 } ;
10381040
1039- // body of the inner most destructuring match
10401041 let mut body = self . call_substructure_method (
10411042 cx,
10421043 trait_,
@@ -1045,14 +1046,18 @@ impl<'a> MethodDef<'a> {
10451046 & Struct ( struct_def, fields) ,
10461047 ) ;
10471048
1048- // make a series of nested matches, to destructure the
1049- // structs. This is actually right-to-left, but it shouldn't
1050- // matter.
1051- for ( arg_expr, pat) in iter:: zip ( self_args, patterns) {
1052- body = cx. expr_match ( span, arg_expr. clone ( ) , vec ! [ cx. arm( span, pat. clone( ) , body) ] )
1053- }
1049+ if !is_packed {
1050+ body. span = span;
1051+ body
1052+ } else {
1053+ // Do the let-destructuring.
1054+ let mut stmts: Vec < _ > = iter:: zip ( self_args, patterns)
1055+ . map ( |( arg_expr, pat) | cx. stmt_let_pat ( span, pat, arg_expr. clone ( ) ) )
1056+ . collect ( ) ;
1057+ stmts. push ( cx. stmt_expr ( body) ) ;
10541058
1055- body
1059+ cx. expr_block ( cx. block ( span, stmts) )
1060+ }
10561061 }
10571062
10581063 fn expand_static_struct_method_body (
@@ -1522,8 +1527,6 @@ impl<'a> TraitDef<'a> {
15221527 paths. push ( ident. with_span_pos ( sp) ) ;
15231528 let val = cx. expr_path ( cx. path_ident ( sp, ident) ) ;
15241529 let val = if use_temporaries { val } else { cx. expr_deref ( sp, val) } ;
1525- let val = cx. expr ( sp, ast:: ExprKind :: Paren ( val) ) ;
1526-
15271530 ident_exprs. push ( ( sp, struct_field. ident , val, & struct_field. attrs [ ..] ) ) ;
15281531 }
15291532
@@ -1555,6 +1558,39 @@ impl<'a> TraitDef<'a> {
15551558 ( pattern, ident_exprs)
15561559 }
15571560
1561+ fn create_struct_field_accesses (
1562+ & self ,
1563+ cx : & mut ExtCtxt < ' _ > ,
1564+ mut self_arg : & P < Expr > ,
1565+ struct_def : & ' a VariantData ,
1566+ ) -> Vec < ( Span , Option < Ident > , P < Expr > , & ' a [ ast:: Attribute ] ) > {
1567+ let mut ident_exprs = Vec :: new ( ) ;
1568+ for ( i, struct_field) in struct_def. fields ( ) . iter ( ) . enumerate ( ) {
1569+ let sp = struct_field. span . with_ctxt ( self . span . ctxt ( ) ) ;
1570+
1571+ // We don't the need the deref, if there is one.
1572+ if let ast:: ExprKind :: Unary ( ast:: UnOp :: Deref , inner) = & self_arg. kind {
1573+ self_arg = inner;
1574+ }
1575+
1576+ // Note: we must use `struct_field.span` rather than `span` in the
1577+ // `unwrap_or_else` case otherwise the hygiene is wrong and we get
1578+ // "field `0` of struct `Point` is private" errors on tuple
1579+ // structs.
1580+ let val = cx. expr (
1581+ sp,
1582+ ast:: ExprKind :: Field (
1583+ self_arg. clone ( ) ,
1584+ struct_field. ident . unwrap_or_else ( || {
1585+ Ident :: from_str_and_span ( & i. to_string ( ) , struct_field. span )
1586+ } ) ,
1587+ ) ,
1588+ ) ;
1589+ ident_exprs. push ( ( sp, struct_field. ident , val, & struct_field. attrs [ ..] ) ) ;
1590+ }
1591+ ident_exprs
1592+ }
1593+
15581594 fn create_enum_variant_pattern (
15591595 & self ,
15601596 cx : & mut ExtCtxt < ' _ > ,
0 commit comments