@@ -413,6 +413,12 @@ fn find_type_parameters(
413
413
visitor. type_params
414
414
}
415
415
416
+ #[ derive( Clone , Copy ) ]
417
+ struct PackedStatus {
418
+ has_type_params : bool ,
419
+ has_derive_copy : bool ,
420
+ }
421
+
416
422
impl < ' a > TraitDef < ' a > {
417
423
pub fn expand (
418
424
self ,
@@ -442,17 +448,22 @@ impl<'a> TraitDef<'a> {
442
448
}
443
449
false
444
450
} ) ;
445
- let has_no_type_params = match item. kind {
446
- ast:: ItemKind :: Struct ( _, ref generics)
447
- | ast:: ItemKind :: Enum ( _, ref generics)
448
- | ast:: ItemKind :: Union ( _, ref generics) => !generics
449
- . params
450
- . iter ( )
451
- . any ( |param| matches ! ( param. kind, ast:: GenericParamKind :: Type { .. } ) ) ,
452
- _ => unreachable ! ( ) ,
451
+ let packed_status = if !is_packed {
452
+ None
453
+ } else {
454
+ let has_type_params = match item. kind {
455
+ ast:: ItemKind :: Struct ( _, ref generics)
456
+ | ast:: ItemKind :: Enum ( _, ref generics)
457
+ | ast:: ItemKind :: Union ( _, ref generics) => generics
458
+ . params
459
+ . iter ( )
460
+ . any ( |param| matches ! ( param. kind, ast:: GenericParamKind :: Type { .. } ) ) ,
461
+ _ => unreachable ! ( ) ,
462
+ } ;
463
+ let container_id = cx. current_expansion . id . expn_data ( ) . parent . expect_local ( ) ;
464
+ let has_derive_copy = cx. resolver . has_derive_copy ( container_id) ;
465
+ Some ( PackedStatus { has_type_params, has_derive_copy } )
453
466
} ;
454
- let container_id = cx. current_expansion . id . expn_data ( ) . parent . expect_local ( ) ;
455
- let always_copy = has_no_type_params && cx. resolver . has_derive_copy ( container_id) ;
456
467
457
468
let newitem = match item. kind {
458
469
ast:: ItemKind :: Struct ( ref struct_def, ref generics) => self . expand_struct_def (
@@ -461,11 +472,10 @@ impl<'a> TraitDef<'a> {
461
472
item. ident ,
462
473
generics,
463
474
from_scratch,
464
- is_packed,
465
- always_copy,
475
+ packed_status,
466
476
) ,
467
477
ast:: ItemKind :: Enum ( ref enum_def, ref generics) => {
468
- // We ignore `is_packed`/`always_copy ` here, because
478
+ // We ignore `packed_status ` here, because
469
479
// `repr(packed)` enums cause an error later on.
470
480
//
471
481
// This can only cause further compilation errors
@@ -481,8 +491,7 @@ impl<'a> TraitDef<'a> {
481
491
item. ident ,
482
492
generics,
483
493
from_scratch,
484
- is_packed,
485
- always_copy,
494
+ packed_status,
486
495
)
487
496
} else {
488
497
cx. span_err ( mitem. span , "this trait cannot be derived for unions" ) ;
@@ -763,8 +772,7 @@ impl<'a> TraitDef<'a> {
763
772
type_ident : Ident ,
764
773
generics : & Generics ,
765
774
from_scratch : bool ,
766
- is_packed : bool ,
767
- always_copy : bool ,
775
+ packed_status : Option < PackedStatus > ,
768
776
) -> P < ast:: Item > {
769
777
let field_tys: Vec < P < ast:: Ty > > =
770
778
struct_def. fields ( ) . iter ( ) . map ( |field| field. ty . clone ( ) ) . collect ( ) ;
@@ -783,6 +791,7 @@ impl<'a> TraitDef<'a> {
783
791
struct_def,
784
792
type_ident,
785
793
& nonselflike_args,
794
+ packed_status,
786
795
)
787
796
} else {
788
797
method_def. expand_struct_method_body (
@@ -792,8 +801,7 @@ impl<'a> TraitDef<'a> {
792
801
type_ident,
793
802
& selflike_args,
794
803
& nonselflike_args,
795
- is_packed,
796
- always_copy,
804
+ packed_status,
797
805
)
798
806
} ;
799
807
@@ -1013,33 +1021,24 @@ impl<'a> MethodDef<'a> {
1013
1021
/// }
1014
1022
/// ```
1015
1023
/// 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. If the struct impls `Copy`,
1018
- /// we use a local block to force a copy :
1024
+ /// `&self.x` on a packed type because that might cause an unaligned ref.
1025
+ /// So for any trait method that takes a reference we use a local block to
1026
+ /// force a copy, which works because such structs must be `Copy` :
1019
1027
/// ```
1020
1028
/// # struct A { x: u8, y: u8 }
1021
1029
/// impl PartialEq for A {
1022
1030
/// fn eq(&self, other: &A) -> bool {
1031
+ /// // Desugars to `{ self.x }.eq(&{ other.y }) && ...`
1023
1032
/// { self.x } == { other.y } && { self.y } == { other.y }
1024
1033
/// }
1025
1034
/// }
1026
- /// ```
1027
- /// (The copy isn't necessary for `eq`, but it makes more sense for other
1028
- /// functions that use e.g. `&{ self.x }`.)
1029
- ///
1030
- /// If it doesn't impl `Copy`, we use let-destructuring with `ref`:
1031
- /// ```
1032
- /// # struct A { x: u8, y: u8 }
1033
- /// impl PartialEq for A {
1034
- /// fn eq(&self, other: &A) -> bool {
1035
- /// let Self { x: ref __self_0_0, y: ref __self_0_1 } = *self;
1036
- /// let Self { x: ref __self_1_0, y: ref __self_1_1 } = *other;
1037
- /// *__self_0_0 == *__self_1_0 && *__self_0_1 == *__self_1_1
1035
+ /// impl Hash for A {
1036
+ /// fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) -> () {
1037
+ /// ::core::hash::Hash::hash(&{ self.x }, state);
1038
+ /// ::core::hash::Hash::hash(&{ self.y }, state)
1038
1039
/// }
1039
1040
/// }
1040
1041
/// ```
1041
- /// This latter case only works if the fields match the alignment required
1042
- /// by the `packed(N)` attribute.
1043
1042
fn expand_struct_method_body < ' b > (
1044
1043
& self ,
1045
1044
cx : & mut ExtCtxt < ' _ > ,
@@ -1048,54 +1047,24 @@ impl<'a> MethodDef<'a> {
1048
1047
type_ident : Ident ,
1049
1048
selflike_args : & [ P < Expr > ] ,
1050
1049
nonselflike_args : & [ P < Expr > ] ,
1051
- is_packed : bool ,
1052
- always_copy : bool ,
1050
+ packed_status : Option < PackedStatus > ,
1053
1051
) -> BlockOrExpr {
1054
1052
let span = trait_. span ;
1055
1053
assert ! ( selflike_args. len( ) == 1 || selflike_args. len( ) == 2 ) ;
1056
1054
1057
- let mk_body = |cx, selflike_fields| {
1058
- self . call_substructure_method (
1059
- cx,
1060
- trait_,
1061
- type_ident,
1062
- nonselflike_args,
1063
- & Struct ( struct_def, selflike_fields) ,
1064
- )
1065
- } ;
1066
-
1067
- if !is_packed {
1068
- let selflike_fields =
1069
- trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def, false ) ;
1070
- mk_body ( cx, selflike_fields)
1071
- } else if always_copy {
1072
- let selflike_fields =
1073
- trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def, true ) ;
1074
- mk_body ( cx, selflike_fields)
1075
- } else {
1076
- // Neither packed nor copy. Need to use ref patterns.
1077
- let prefixes: Vec < _ > =
1078
- ( 0 ..selflike_args. len ( ) ) . map ( |i| format ! ( "__self_{}" , i) ) . collect ( ) ;
1079
- let addr_of = always_copy;
1080
- let selflike_fields =
1081
- trait_. create_struct_pattern_fields ( cx, struct_def, & prefixes, addr_of) ;
1082
- let mut body = mk_body ( cx, selflike_fields) ;
1083
-
1084
- let struct_path = cx. path ( span, vec ! [ Ident :: new( kw:: SelfUpper , type_ident. span) ] ) ;
1085
- let use_ref_pat = is_packed && !always_copy;
1086
- let patterns =
1087
- trait_. create_struct_patterns ( cx, struct_path, struct_def, & prefixes, use_ref_pat) ;
1088
-
1089
- // Do the let-destructuring.
1090
- let mut stmts: Vec < _ > = iter:: zip ( selflike_args, patterns)
1091
- . map ( |( selflike_arg_expr, pat) | {
1092
- let selflike_arg_expr = cx. expr_deref ( span, selflike_arg_expr. clone ( ) ) ;
1093
- cx. stmt_let_pat ( span, pat, selflike_arg_expr)
1094
- } )
1095
- . collect ( ) ;
1096
- stmts. extend ( std:: mem:: take ( & mut body. 0 ) ) ;
1097
- BlockOrExpr ( stmts, body. 1 )
1055
+ if let Err ( res) = Self :: check_packed_status ( cx, span, packed_status) {
1056
+ return res;
1098
1057
}
1058
+
1059
+ let selflike_fields =
1060
+ trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def, packed_status) ;
1061
+ self . call_substructure_method (
1062
+ cx,
1063
+ trait_,
1064
+ type_ident,
1065
+ nonselflike_args,
1066
+ & Struct ( struct_def, selflike_fields) ,
1067
+ )
1099
1068
}
1100
1069
1101
1070
fn expand_static_struct_method_body (
@@ -1105,9 +1074,15 @@ impl<'a> MethodDef<'a> {
1105
1074
struct_def : & VariantData ,
1106
1075
type_ident : Ident ,
1107
1076
nonselflike_args : & [ P < Expr > ] ,
1077
+ packed_status : Option < PackedStatus > ,
1108
1078
) -> BlockOrExpr {
1109
- let summary = trait_. summarise_struct ( cx, struct_def) ;
1079
+ let span = trait_. span ;
1080
+
1081
+ if Self :: check_packed_status ( cx, span, packed_status) . is_err ( ) {
1082
+ return BlockOrExpr ( vec ! [ ] , Some ( deriving:: call_abort ( cx, span) ) ) ;
1083
+ }
1110
1084
1085
+ let summary = trait_. summarise_struct ( cx, struct_def) ;
1111
1086
self . call_substructure_method (
1112
1087
cx,
1113
1088
trait_,
@@ -1117,6 +1092,32 @@ impl<'a> MethodDef<'a> {
1117
1092
)
1118
1093
}
1119
1094
1095
+ fn check_packed_status (
1096
+ cx : & ExtCtxt < ' _ > ,
1097
+ span : Span ,
1098
+ packed_status : Option < PackedStatus > ,
1099
+ ) -> Result < ( ) , BlockOrExpr > {
1100
+ let mut res = Ok ( ( ) ) ;
1101
+ let err = || Err ( BlockOrExpr ( vec ! [ ] , Some ( deriving:: call_abort ( cx, span) ) ) ) ;
1102
+ if let Some ( PackedStatus { has_type_params, has_derive_copy } ) = packed_status {
1103
+ // FIXME: when we make this a hard error, this should have its
1104
+ // own error code.
1105
+ if has_type_params {
1106
+ let msg = "`#[derive]` can't be used on a `#[repr(packed)]` struct with \
1107
+ type or const parameters (error E0133)";
1108
+ cx. sess . struct_span_err ( span, msg) . emit ( ) ;
1109
+ res = err ( ) ;
1110
+ }
1111
+ if !has_derive_copy {
1112
+ let msg = "`#[derive]` can't be used on a `#[repr(packed)]` struct that \
1113
+ does not derive Copy (error E0133)";
1114
+ cx. sess . struct_span_err ( span, msg) . emit ( ) ;
1115
+ res = err ( ) ;
1116
+ }
1117
+ }
1118
+ res
1119
+ }
1120
+
1120
1121
/// ```
1121
1122
/// #[derive(PartialEq)]
1122
1123
/// # struct Dummy;
@@ -1542,7 +1543,7 @@ impl<'a> TraitDef<'a> {
1542
1543
cx : & mut ExtCtxt < ' _ > ,
1543
1544
selflike_args : & [ P < Expr > ] ,
1544
1545
struct_def : & ' a VariantData ,
1545
- copy : bool ,
1546
+ packed_status : Option < PackedStatus > ,
1546
1547
) -> Vec < FieldInfo > {
1547
1548
self . create_fields ( struct_def, |i, struct_field, sp| {
1548
1549
selflike_args
@@ -1561,7 +1562,7 @@ impl<'a> TraitDef<'a> {
1561
1562
} ) ,
1562
1563
) ,
1563
1564
) ;
1564
- if copy {
1565
+ if packed_status . is_some ( ) {
1565
1566
field_expr = cx. expr_block (
1566
1567
cx. block ( struct_field. span , vec ! [ cx. stmt_expr( field_expr) ] ) ,
1567
1568
) ;
0 commit comments