66
66
//!
67
67
//! # "`cs`" functions
68
68
//!
69
- //! The `cs_...` functions ("combine substructure) are designed to
69
+ //! The `cs_...` functions ("combine substructure" ) are designed to
70
70
//! make life easier by providing some pre-made recipes for common
71
71
//! threads; mostly calling the function being derived on all the
72
72
//! arguments and then combining them back together in some way (or
@@ -429,6 +429,7 @@ impl<'a> TraitDef<'a> {
429
429
generics,
430
430
from_scratch,
431
431
use_temporaries,
432
+ is_packed,
432
433
) ,
433
434
ast:: ItemKind :: Enum ( ref enum_def, ref generics) => {
434
435
// We ignore `use_temporaries` here, because
@@ -448,6 +449,7 @@ impl<'a> TraitDef<'a> {
448
449
generics,
449
450
from_scratch,
450
451
use_temporaries,
452
+ is_packed,
451
453
)
452
454
} else {
453
455
cx. span_err ( mitem. span , "this trait cannot be derived for unions" ) ;
@@ -729,6 +731,7 @@ impl<'a> TraitDef<'a> {
729
731
generics : & Generics ,
730
732
from_scratch : bool ,
731
733
use_temporaries : bool ,
734
+ is_packed : bool ,
732
735
) -> P < ast:: Item > {
733
736
let field_tys: Vec < P < ast:: Ty > > =
734
737
struct_def. fields ( ) . iter ( ) . map ( |field| field. ty . clone ( ) ) . collect ( ) ;
@@ -757,6 +760,7 @@ impl<'a> TraitDef<'a> {
757
760
& self_args,
758
761
& nonself_args,
759
762
use_temporaries,
763
+ is_packed,
760
764
)
761
765
} ;
762
766
@@ -945,6 +949,7 @@ impl<'a> MethodDef<'a> {
945
949
} )
946
950
}
947
951
952
+ /// The normal case uses field access.
948
953
/// ```
949
954
/// #[derive(PartialEq)]
950
955
/// # struct Dummy;
@@ -953,33 +958,21 @@ impl<'a> MethodDef<'a> {
953
958
/// // equivalent to:
954
959
/// impl PartialEq for A {
955
960
/// 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
965
962
/// }
966
963
/// }
967
964
/// ```
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.
970
969
/// ```
971
970
/// # struct A { x: i32, y: i32 }
972
971
/// impl PartialEq for A {
973
972
/// 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
983
976
/// }
984
977
/// }
985
978
/// ```
@@ -992,24 +985,33 @@ impl<'a> MethodDef<'a> {
992
985
self_args : & [ P < Expr > ] ,
993
986
nonself_args : & [ P < Expr > ] ,
994
987
use_temporaries : bool ,
988
+ is_packed : bool ,
995
989
) -> P < Expr > {
996
990
let mut raw_fields = Vec :: new ( ) ; // Vec<[fields of self], [fields of next Self arg], [etc]>
997
991
let span = trait_. span ;
998
992
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) ;
1013
1015
}
1014
1016
1015
1017
// transpose raw_fields
@@ -1036,7 +1038,6 @@ impl<'a> MethodDef<'a> {
1036
1038
cx. span_bug ( span, "no `self` parameter for method in generic `derive`" )
1037
1039
} ;
1038
1040
1039
- // body of the inner most destructuring match
1040
1041
let mut body = self . call_substructure_method (
1041
1042
cx,
1042
1043
trait_,
@@ -1045,14 +1046,18 @@ impl<'a> MethodDef<'a> {
1045
1046
& Struct ( struct_def, fields) ,
1046
1047
) ;
1047
1048
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) ) ;
1054
1058
1055
- body
1059
+ cx. expr_block ( cx. block ( span, stmts) )
1060
+ }
1056
1061
}
1057
1062
1058
1063
fn expand_static_struct_method_body (
@@ -1522,8 +1527,6 @@ impl<'a> TraitDef<'a> {
1522
1527
paths. push ( ident. with_span_pos ( sp) ) ;
1523
1528
let val = cx. expr_path ( cx. path_ident ( sp, ident) ) ;
1524
1529
let val = if use_temporaries { val } else { cx. expr_deref ( sp, val) } ;
1525
- let val = cx. expr ( sp, ast:: ExprKind :: Paren ( val) ) ;
1526
-
1527
1530
ident_exprs. push ( ( sp, struct_field. ident , val, & struct_field. attrs [ ..] ) ) ;
1528
1531
}
1529
1532
@@ -1555,6 +1558,39 @@ impl<'a> TraitDef<'a> {
1555
1558
( pattern, ident_exprs)
1556
1559
}
1557
1560
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
+
1558
1594
fn create_enum_variant_pattern (
1559
1595
& self ,
1560
1596
cx : & mut ExtCtxt < ' _ > ,
@@ -1643,7 +1679,6 @@ where
1643
1679
/// fields.
1644
1680
/// When the `substructure` is an `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
1645
1681
/// is returned. Statics may not be folded over.
1646
- /// See `cs_op` in `partial_ord.rs` for a model example.
1647
1682
pub fn cs_fold1 < F , B > (
1648
1683
use_foldl : bool ,
1649
1684
f : F ,
0 commit comments