@@ -1013,20 +1013,25 @@ impl<'a> MethodDef<'a> {
1013
1013
/// }
1014
1014
/// ```
1015
1015
/// But if the struct is `repr(packed)`, we can't use something like
1016
- /// `&self.x` on a packed type (as required for e.g. `Debug` and `Hash`)
1017
- /// because that might cause an unaligned ref. So we use let-destructuring
1018
- /// instead. If the struct impls `Copy` :
1016
+ /// `&self.x` because that might cause an unaligned ref. So for any trait
1017
+ /// method that takes a reference, if the struct impls `Copy` then we use a
1018
+ /// local block to force a copy :
1019
1019
/// ```
1020
1020
/// # struct A { x: u8, y: u8 }
1021
1021
/// impl PartialEq for A {
1022
1022
/// fn eq(&self, other: &A) -> bool {
1023
- /// let Self { x: __self_0_0, y: __self_0_1 } = *self;
1024
- /// let Self { x: __self_1_0, y: __self_1_1 } = *other;
1025
- /// __self_0_0 == __self_1_0 && __self_0_1 == __self_1_1
1023
+ /// // Desugars to `{ self.x }.eq(&{ other.y }) && ...`
1024
+ /// { self.x } == { other.y } && { self.y } == { other.y }
1025
+ /// }
1026
+ /// }
1027
+ /// impl Hash for A {
1028
+ /// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
1029
+ /// ::core::hash::Hash::hash(&{ self.x }, state);
1030
+ /// ::core::hash::Hash::hash(&{ self.y }, state)
1026
1031
/// }
1027
1032
/// }
1028
1033
/// ```
1029
- /// If it doesn't impl `Copy`:
1034
+ /// If the struct doesn't impl `Copy`, we use let-destructuring with `ref `:
1030
1035
/// ```
1031
1036
/// # struct A { x: u8, y: u8 }
1032
1037
/// impl PartialEq for A {
@@ -1038,7 +1043,7 @@ impl<'a> MethodDef<'a> {
1038
1043
/// }
1039
1044
/// ```
1040
1045
/// This latter case only works if the fields match the alignment required
1041
- /// by the `packed(N)` attribute.
1046
+ /// by the `packed(N)` attribute. (We'll get errors later on if not.)
1042
1047
fn expand_struct_method_body < ' b > (
1043
1048
& self ,
1044
1049
cx : & mut ExtCtxt < ' _ > ,
@@ -1065,9 +1070,14 @@ impl<'a> MethodDef<'a> {
1065
1070
1066
1071
if !is_packed {
1067
1072
let selflike_fields =
1068
- trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def) ;
1073
+ trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def, false ) ;
1074
+ mk_body ( cx, selflike_fields)
1075
+ } else if always_copy {
1076
+ let selflike_fields =
1077
+ trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def, true ) ;
1069
1078
mk_body ( cx, selflike_fields)
1070
1079
} else {
1080
+ // Neither packed nor copy. Need to use ref patterns.
1071
1081
let prefixes: Vec < _ > =
1072
1082
( 0 ..selflike_args. len ( ) ) . map ( |i| format ! ( "__self_{}" , i) ) . collect ( ) ;
1073
1083
let addr_of = always_copy;
@@ -1536,6 +1546,7 @@ impl<'a> TraitDef<'a> {
1536
1546
cx : & mut ExtCtxt < ' _ > ,
1537
1547
selflike_args : & [ P < Expr > ] ,
1538
1548
struct_def : & ' a VariantData ,
1549
+ copy : bool ,
1539
1550
) -> Vec < FieldInfo > {
1540
1551
self . create_fields ( struct_def, |i, struct_field, sp| {
1541
1552
selflike_args
@@ -1545,18 +1556,21 @@ impl<'a> TraitDef<'a> {
1545
1556
// `unwrap_or_else` case otherwise the hygiene is wrong and we get
1546
1557
// "field `0` of struct `Point` is private" errors on tuple
1547
1558
// structs.
1548
- cx. expr_addr_of (
1559
+ let mut field_expr = cx. expr (
1549
1560
sp,
1550
- cx. expr (
1551
- sp,
1552
- ast:: ExprKind :: Field (
1553
- selflike_arg. clone ( ) ,
1554
- struct_field. ident . unwrap_or_else ( || {
1555
- Ident :: from_str_and_span ( & i. to_string ( ) , struct_field. span )
1556
- } ) ,
1557
- ) ,
1561
+ ast:: ExprKind :: Field (
1562
+ selflike_arg. clone ( ) ,
1563
+ struct_field. ident . unwrap_or_else ( || {
1564
+ Ident :: from_str_and_span ( & i. to_string ( ) , struct_field. span )
1565
+ } ) ,
1558
1566
) ,
1559
- )
1567
+ ) ;
1568
+ if copy {
1569
+ field_expr = cx. expr_block (
1570
+ cx. block ( struct_field. span , vec ! [ cx. stmt_expr( field_expr) ] ) ,
1571
+ ) ;
1572
+ }
1573
+ cx. expr_addr_of ( sp, field_expr)
1560
1574
} )
1561
1575
. collect ( )
1562
1576
} )
0 commit comments