@@ -165,11 +165,12 @@ pub use SubstructureFields::*;
165
165
use crate :: deriving;
166
166
use rustc_ast:: ptr:: P ;
167
167
use rustc_ast:: {
168
- self as ast, BindingAnnotation , ByRef , EnumDef , Expr , Generics , Mutability , PatKind ,
168
+ self as ast, BindingAnnotation , ByRef , EnumDef , Expr , GenericArg , GenericParamKind , Generics ,
169
+ Mutability , PatKind , TyKind , VariantData ,
169
170
} ;
170
- use rustc_ast:: { GenericArg , GenericParamKind , VariantData } ;
171
171
use rustc_attr as attr;
172
172
use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
173
+ use rustc_session:: lint:: builtin:: BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE ;
173
174
use rustc_span:: symbol:: { kw, sym, Ident , Symbol } ;
174
175
use rustc_span:: { Span , DUMMY_SP } ;
175
176
use std:: cell:: RefCell ;
@@ -191,6 +192,9 @@ pub struct TraitDef<'a> {
191
192
/// Whether to skip adding the current trait as a bound to the type parameters of the type.
192
193
pub skip_path_as_bound : bool ,
193
194
195
+ /// Whether `Copy` is needed as an additional bound on type parameters in a packed struct.
196
+ pub needs_copy_as_bound_if_packed : bool ,
197
+
194
198
/// Additional bounds required of any type parameters of the type,
195
199
/// other than the current trait
196
200
pub additional_bounds : Vec < Ty > ,
@@ -455,18 +459,6 @@ impl<'a> TraitDef<'a> {
455
459
}
456
460
false
457
461
} ) ;
458
- let has_no_type_params = match & item. kind {
459
- ast:: ItemKind :: Struct ( _, generics)
460
- | ast:: ItemKind :: Enum ( _, generics)
461
- | ast:: ItemKind :: Union ( _, generics) => !generics
462
- . params
463
- . iter ( )
464
- . any ( |param| matches ! ( param. kind, ast:: GenericParamKind :: Type { .. } ) ) ,
465
- _ => unreachable ! ( ) ,
466
- } ;
467
- let container_id = cx. current_expansion . id . expn_data ( ) . parent . expect_local ( ) ;
468
- let copy_fields =
469
- is_packed && has_no_type_params && cx. resolver . has_derive_copy ( container_id) ;
470
462
471
463
let newitem = match & item. kind {
472
464
ast:: ItemKind :: Struct ( struct_def, generics) => self . expand_struct_def (
@@ -475,7 +467,7 @@ impl<'a> TraitDef<'a> {
475
467
item. ident ,
476
468
generics,
477
469
from_scratch,
478
- copy_fields ,
470
+ is_packed ,
479
471
) ,
480
472
ast:: ItemKind :: Enum ( enum_def, generics) => {
481
473
// We ignore `is_packed` here, because `repr(packed)`
@@ -493,7 +485,7 @@ impl<'a> TraitDef<'a> {
493
485
item. ident ,
494
486
generics,
495
487
from_scratch,
496
- copy_fields ,
488
+ is_packed ,
497
489
)
498
490
} else {
499
491
cx. span_err ( mitem. span , "this trait cannot be derived for unions" ) ;
@@ -565,6 +557,7 @@ impl<'a> TraitDef<'a> {
565
557
generics : & Generics ,
566
558
field_tys : Vec < P < ast:: Ty > > ,
567
559
methods : Vec < P < ast:: AssocItem > > ,
560
+ is_packed : bool ,
568
561
) -> P < ast:: Item > {
569
562
let trait_path = self . path . to_path ( cx, self . span , type_ident, generics) ;
570
563
@@ -607,20 +600,32 @@ impl<'a> TraitDef<'a> {
607
600
. map ( |param| match & param. kind {
608
601
GenericParamKind :: Lifetime { .. } => param. clone ( ) ,
609
602
GenericParamKind :: Type { .. } => {
610
- // I don't think this can be moved out of the loop, since
611
- // a GenericBound requires an ast id
612
- let bounds: Vec < _ > =
613
- // extra restrictions on the generics parameters to the
614
- // type being derived upon
615
- self . additional_bounds . iter ( ) . map ( |p| {
616
- cx. trait_bound ( p. to_path ( cx, self . span , type_ident, generics) )
617
- } ) . chain (
618
- // require the current trait
619
- self . skip_path_as_bound . not ( ) . then ( || cx. trait_bound ( trait_path. clone ( ) ) )
620
- ) . chain (
621
- // also add in any bounds from the declaration
622
- param. bounds . iter ( ) . cloned ( )
623
- ) . collect ( ) ;
603
+ // Extra restrictions on the generics parameters to the
604
+ // type being derived upon.
605
+ let bounds: Vec < _ > = self
606
+ . additional_bounds
607
+ . iter ( )
608
+ . map ( |p| cx. trait_bound ( p. to_path ( cx, self . span , type_ident, generics) ) )
609
+ . chain (
610
+ // Add a bound for the current trait.
611
+ self . skip_path_as_bound
612
+ . not ( )
613
+ . then ( || cx. trait_bound ( trait_path. clone ( ) ) ) ,
614
+ )
615
+ . chain ( {
616
+ // Add a `Copy` bound if required.
617
+ if is_packed && self . needs_copy_as_bound_if_packed {
618
+ let p = deriving:: path_std!( marker:: Copy ) ;
619
+ Some ( cx. trait_bound ( p. to_path ( cx, self . span , type_ident, generics) ) )
620
+ } else {
621
+ None
622
+ }
623
+ } )
624
+ . chain (
625
+ // Also add in any bounds from the declaration.
626
+ param. bounds . iter ( ) . cloned ( ) ,
627
+ )
628
+ . collect ( ) ;
624
629
625
630
cx. typaram ( param. ident . span . with_ctxt ( ctxt) , param. ident , bounds, None )
626
631
}
@@ -692,9 +697,17 @@ impl<'a> TraitDef<'a> {
692
697
. map ( |p| cx. trait_bound ( p. to_path ( cx, self . span , type_ident, generics) ) )
693
698
. collect ( ) ;
694
699
695
- // require the current trait
700
+ // Require the current trait.
696
701
bounds. push ( cx. trait_bound ( trait_path. clone ( ) ) ) ;
697
702
703
+ // Add a `Copy` bound if required.
704
+ if is_packed && self . needs_copy_as_bound_if_packed {
705
+ let p = deriving:: path_std!( marker:: Copy ) ;
706
+ bounds. push (
707
+ cx. trait_bound ( p. to_path ( cx, self . span , type_ident, generics) ) ,
708
+ ) ;
709
+ }
710
+
698
711
let predicate = ast:: WhereBoundPredicate {
699
712
span : self . span ,
700
713
bound_generic_params : field_ty_param. bound_generic_params ,
@@ -762,7 +775,7 @@ impl<'a> TraitDef<'a> {
762
775
type_ident : Ident ,
763
776
generics : & Generics ,
764
777
from_scratch : bool ,
765
- copy_fields : bool ,
778
+ is_packed : bool ,
766
779
) -> P < ast:: Item > {
767
780
let field_tys: Vec < P < ast:: Ty > > =
768
781
struct_def. fields ( ) . iter ( ) . map ( |field| field. ty . clone ( ) ) . collect ( ) ;
@@ -790,7 +803,7 @@ impl<'a> TraitDef<'a> {
790
803
type_ident,
791
804
& selflike_args,
792
805
& nonselflike_args,
793
- copy_fields ,
806
+ is_packed ,
794
807
)
795
808
} ;
796
809
@@ -806,7 +819,7 @@ impl<'a> TraitDef<'a> {
806
819
} )
807
820
. collect ( ) ;
808
821
809
- self . create_derived_impl ( cx, type_ident, generics, field_tys, methods)
822
+ self . create_derived_impl ( cx, type_ident, generics, field_tys, methods, is_packed )
810
823
}
811
824
812
825
fn expand_enum_def (
@@ -861,7 +874,8 @@ impl<'a> TraitDef<'a> {
861
874
} )
862
875
. collect ( ) ;
863
876
864
- self . create_derived_impl ( cx, type_ident, generics, field_tys, methods)
877
+ let is_packed = false ; // enums are never packed
878
+ self . create_derived_impl ( cx, type_ident, generics, field_tys, methods, is_packed)
865
879
}
866
880
}
867
881
@@ -1011,8 +1025,8 @@ impl<'a> MethodDef<'a> {
1011
1025
/// ```
1012
1026
/// But if the struct is `repr(packed)`, we can't use something like
1013
1027
/// `&self.x` because that might cause an unaligned ref. So for any trait
1014
- /// method that takes a reference, if the struct impls `Copy` then we use a
1015
- /// local block to force a copy:
1028
+ /// method that takes a reference, we use a local block to force a copy.
1029
+ /// This requires that the field impl `Copy`.
1016
1030
/// ```
1017
1031
/// # struct A { x: u8, y: u8 }
1018
1032
/// impl PartialEq for A {
@@ -1027,10 +1041,6 @@ impl<'a> MethodDef<'a> {
1027
1041
/// ::core::hash::Hash::hash(&{ self.y }, state)
1028
1042
/// }
1029
1043
/// }
1030
- /// ```
1031
- /// If the struct doesn't impl `Copy`, we use the normal `&self.x`. This
1032
- /// only works if the fields match the alignment required by the
1033
- /// `packed(N)` attribute. (We'll get errors later on if not.)
1034
1044
fn expand_struct_method_body < ' b > (
1035
1045
& self ,
1036
1046
cx : & mut ExtCtxt < ' _ > ,
@@ -1039,12 +1049,12 @@ impl<'a> MethodDef<'a> {
1039
1049
type_ident : Ident ,
1040
1050
selflike_args : & [ P < Expr > ] ,
1041
1051
nonselflike_args : & [ P < Expr > ] ,
1042
- copy_fields : bool ,
1052
+ is_packed : bool ,
1043
1053
) -> BlockOrExpr {
1044
1054
assert ! ( selflike_args. len( ) == 1 || selflike_args. len( ) == 2 ) ;
1045
1055
1046
1056
let selflike_fields =
1047
- trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def, copy_fields ) ;
1057
+ trait_. create_struct_field_access_fields ( cx, selflike_args, struct_def, is_packed ) ;
1048
1058
self . call_substructure_method (
1049
1059
cx,
1050
1060
trait_,
@@ -1514,7 +1524,7 @@ impl<'a> TraitDef<'a> {
1514
1524
cx : & mut ExtCtxt < ' _ > ,
1515
1525
selflike_args : & [ P < Expr > ] ,
1516
1526
struct_def : & ' a VariantData ,
1517
- copy_fields : bool ,
1527
+ is_packed : bool ,
1518
1528
) -> Vec < FieldInfo > {
1519
1529
self . create_fields ( struct_def, |i, struct_field, sp| {
1520
1530
selflike_args
@@ -1533,10 +1543,39 @@ impl<'a> TraitDef<'a> {
1533
1543
} ) ,
1534
1544
) ,
1535
1545
) ;
1536
- if copy_fields {
1537
- field_expr = cx. expr_block (
1538
- cx. block ( struct_field. span , vec ! [ cx. stmt_expr( field_expr) ] ) ,
1539
- ) ;
1546
+ // In general, fields in packed structs are copied via a
1547
+ // block, e.g. `&{self.0}`. The one exception is `[u8]`
1548
+ // fields, which cannot be copied and also never cause
1549
+ // unaligned references. This exception is allowed to
1550
+ // handle the `FlexZeroSlice` type in the `zerovec` crate
1551
+ // within `icu4x-0.9.0`.
1552
+ //
1553
+ // Once use of `icu4x-0.9.0` has dropped sufficiently, this
1554
+ // exception should be removed.
1555
+ let is_u8_slice = if let TyKind :: Slice ( ty) = & struct_field. ty . kind &&
1556
+ let TyKind :: Path ( None , rustc_ast:: Path { segments, .. } ) = & ty. kind &&
1557
+ let [ seg] = segments. as_slice ( ) &&
1558
+ seg. ident . name == sym:: u8 && seg. args . is_none ( )
1559
+ {
1560
+ true
1561
+ } else {
1562
+ false
1563
+ } ;
1564
+ if is_packed {
1565
+ if is_u8_slice {
1566
+ cx. sess . parse_sess . buffer_lint_with_diagnostic (
1567
+ BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE ,
1568
+ sp,
1569
+ ast:: CRATE_NODE_ID ,
1570
+ "byte slice in a packed struct that derives a built-in trait" ,
1571
+ rustc_lint_defs:: BuiltinLintDiagnostics :: ByteSliceInPackedStructWithDerive
1572
+ ) ;
1573
+ } else {
1574
+ // Wrap the expression in `{...}`, causing a copy.
1575
+ field_expr = cx. expr_block (
1576
+ cx. block ( struct_field. span , vec ! [ cx. stmt_expr( field_expr) ] ) ,
1577
+ ) ;
1578
+ }
1540
1579
}
1541
1580
cx. expr_addr_of ( sp, field_expr)
1542
1581
} )
0 commit comments