@@ -1491,6 +1491,9 @@ bitflags! {
14911491 const IS_LINEAR = 1 << 3 ;
14921492 // If true, don't expose any niche to type's context.
14931493 const HIDE_NICHE = 1 << 4 ;
1494+ // If true, the type's layout can be randomized using
1495+ // the seed stored in `ReprOptions.layout_seed`
1496+ const RANDOMIZE_LAYOUT = 1 << 5 ;
14941497 // Any of these flags being set prevent field reordering optimisation.
14951498 const IS_UNOPTIMISABLE = ReprFlags :: IS_C . bits |
14961499 ReprFlags :: IS_SIMD . bits |
@@ -1505,6 +1508,14 @@ pub struct ReprOptions {
15051508 pub align : Option < Align > ,
15061509 pub pack : Option < Align > ,
15071510 pub flags : ReprFlags ,
1511+ /// The seed to be used for randomizing a type's layout
1512+ ///
1513+ /// Note: This could technically be a `[u8; 16]` (a `u128`) which would
1514+ /// be the "most accurate" hash as it'd encompass the item and crate
1515+ /// hash without loss, but it does pay the price of being larger.
1516+ /// Everything's a tradeoff, a `u64` seed should be sufficient for our
1517+ /// purposes (primarily `-Z randomize-layout`)
1518+ pub field_shuffle_seed : u64 ,
15081519}
15091520
15101521impl ReprOptions {
@@ -1513,6 +1524,11 @@ impl ReprOptions {
15131524 let mut size = None ;
15141525 let mut max_align: Option < Align > = None ;
15151526 let mut min_pack: Option < Align > = None ;
1527+
1528+ // Generate a deterministically-derived seed from the item's path hash
1529+ // to allow for cross-crate compilation to actually work
1530+ let field_shuffle_seed = tcx. def_path_hash ( did) . 0 . to_smaller_hash ( ) ;
1531+
15161532 for attr in tcx. get_attrs ( did) . iter ( ) {
15171533 for r in attr:: find_repr_attrs ( & tcx. sess , attr) {
15181534 flags. insert ( match r {
@@ -1541,33 +1557,45 @@ impl ReprOptions {
15411557 }
15421558 }
15431559
1560+ // If `-Z randomize-layout` was enabled for the type definition then we can
1561+ // consider performing layout randomization
1562+ if tcx. sess . opts . debugging_opts . randomize_layout {
1563+ flags. insert ( ReprFlags :: RANDOMIZE_LAYOUT ) ;
1564+ }
1565+
15441566 // This is here instead of layout because the choice must make it into metadata.
15451567 if !tcx. consider_optimizing ( || format ! ( "Reorder fields of {:?}" , tcx. def_path_str( did) ) ) {
15461568 flags. insert ( ReprFlags :: IS_LINEAR ) ;
15471569 }
1548- ReprOptions { int : size, align : max_align, pack : min_pack, flags }
1570+
1571+ Self { int : size, align : max_align, pack : min_pack, flags, field_shuffle_seed }
15491572 }
15501573
15511574 #[ inline]
15521575 pub fn simd ( & self ) -> bool {
15531576 self . flags . contains ( ReprFlags :: IS_SIMD )
15541577 }
1578+
15551579 #[ inline]
15561580 pub fn c ( & self ) -> bool {
15571581 self . flags . contains ( ReprFlags :: IS_C )
15581582 }
1583+
15591584 #[ inline]
15601585 pub fn packed ( & self ) -> bool {
15611586 self . pack . is_some ( )
15621587 }
1588+
15631589 #[ inline]
15641590 pub fn transparent ( & self ) -> bool {
15651591 self . flags . contains ( ReprFlags :: IS_TRANSPARENT )
15661592 }
1593+
15671594 #[ inline]
15681595 pub fn linear ( & self ) -> bool {
15691596 self . flags . contains ( ReprFlags :: IS_LINEAR )
15701597 }
1598+
15711599 #[ inline]
15721600 pub fn hide_niche ( & self ) -> bool {
15731601 self . flags . contains ( ReprFlags :: HIDE_NICHE )
@@ -1594,9 +1622,17 @@ impl ReprOptions {
15941622 return true ;
15951623 }
15961624 }
1625+
15971626 self . flags . intersects ( ReprFlags :: IS_UNOPTIMISABLE ) || self . int . is_some ( )
15981627 }
15991628
1629+ /// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
1630+ /// was enabled for its declaration crate
1631+ pub fn can_randomize_type_layout ( & self ) -> bool {
1632+ !self . inhibit_struct_field_reordering_opt ( )
1633+ && self . flags . contains ( ReprFlags :: RANDOMIZE_LAYOUT )
1634+ }
1635+
16001636 /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
16011637 pub fn inhibit_union_abi_opt ( & self ) -> bool {
16021638 self . c ( )
0 commit comments