@@ -576,19 +576,6 @@ macro_rules! safety_comment {
576
576
577
577
/// Unsafely implements trait(s) for a type.
578
578
macro_rules! unsafe_impl {
579
- // Implement `Unaligned` for `$ty` with no bounds.
580
- //
581
- // For `Unaligned` in particular, it's possible to assert at compile time
582
- // that the trait impl is sound. This provides a small speed bump to
583
- // accidentally implementing `Unaligned` for a type with alignment greater
584
- // than 1.
585
- ( $ty: ty: Unaligned ) => {
586
- // We only compile this assertion under `cfg(test)` to avoid making this
587
- // crate more expensive to compile for our dependents.
588
- #[ cfg( test) ]
589
- const _: ( ) = { static_assertions:: const_assert_eq!( core:: mem:: align_of:: <$ty>( ) , 1 ) ; } ;
590
- unsafe impl Unaligned for $ty { fn only_derive_is_allowed_to_implement_this_trait( ) { } }
591
- } ;
592
579
// Implement `$trait` for `$ty` with no bounds.
593
580
( $ty: ty: $trait: ty) => {
594
581
unsafe impl $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait( ) { } }
@@ -622,6 +609,23 @@ macro_rules! unsafe_impl {
622
609
} ;
623
610
}
624
611
612
+ /// Uses `align_of` to confirm that a type or set of types have alignment 1.
613
+ ///
614
+ /// Note that `align_of<T>` requires `T: Sized`, so this macro doesn't work for
615
+ /// unsized types.
616
+ macro_rules! assert_unaligned {
617
+ ( $ty: ty) => {
618
+ // We only compile this assertion under `cfg(test)` to avoid taking an
619
+ // extra non-dev dependency (and making this crate more expensive to
620
+ // compile for our dependents).
621
+ #[ cfg( test) ]
622
+ static_assertions:: const_assert_eq!( core:: mem:: align_of:: <$ty>( ) , 1 ) ;
623
+ } ;
624
+ ( $( $ty: ty) ,* ) => {
625
+ $( assert_unaligned!( $ty) ; ) *
626
+ } ;
627
+ }
628
+
625
629
safety_comment ! {
626
630
/// SAFETY:
627
631
/// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a
@@ -633,6 +637,7 @@ safety_comment! {
633
637
///
634
638
/// [1] https://doc.rust-lang.org/reference/type-layout.html#tuple-layout
635
639
unsafe_impl!( ( ) : FromBytes , AsBytes , Unaligned ) ;
640
+ assert_unaligned!( ( ) ) ;
636
641
}
637
642
638
643
safety_comment ! {
@@ -651,6 +656,7 @@ safety_comment! {
651
656
/// [2] https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout
652
657
unsafe_impl!( u8 : FromBytes , AsBytes , Unaligned ) ;
653
658
unsafe_impl!( i8 : FromBytes , AsBytes , Unaligned ) ;
659
+ assert_unaligned!( u8 , i8 ) ;
654
660
unsafe_impl!( u16 : FromBytes , AsBytes ) ;
655
661
unsafe_impl!( i16 : FromBytes , AsBytes ) ;
656
662
unsafe_impl!( u32 : FromBytes , AsBytes ) ;
@@ -692,6 +698,7 @@ safety_comment! {
692
698
///
693
699
/// [1] https://doc.rust-lang.org/reference/types/boolean.html
694
700
unsafe_impl!( bool : AsBytes , Unaligned ) ;
701
+ assert_unaligned!( bool ) ;
695
702
}
696
703
safety_comment ! {
697
704
/// SAFETY:
@@ -704,26 +711,41 @@ safety_comment! {
704
711
}
705
712
safety_comment ! {
706
713
/// SAFETY:
707
- /// - `AsBytes`: Per the reference [1], `str` has the same layout as `[u8]`,
708
- /// and `[u8]` is `AsBytes`.
714
+ /// - `AsBytes`, `Unaligned`: Per the reference [1], `str` has the same
715
+ /// layout as `[u8]`, and `[u8]` is `AsBytes` and `Unaligned`.
716
+ ///
717
+ /// Note that we don't `assert_unaligned!(str)` because `assert_unaligned!`
718
+ /// uses `align_of`, which only works for `Sized` types.
709
719
///
710
720
/// [1] https://doc.rust-lang.org/reference/type-layout.html#str-layout
711
- unsafe_impl!( str : AsBytes ) ;
721
+ unsafe_impl!( str : AsBytes , Unaligned ) ;
712
722
}
713
723
714
724
safety_comment ! {
715
725
// `NonZeroXxx` is `AsBytes`, but not `FromBytes`.
716
726
//
717
727
/// SAFETY:
718
- /// `NonZeroXxx` has the same layout as its associated primitive. Since it
719
- /// is the same size, this guarantees it has no padding - integers have no
720
- /// padding, and there's no room for padding if it can represent all of the
721
- /// same values except 0.
722
- ///
728
+ /// - `AsBytes`: `NonZeroXxx` has the same layout as its associated
729
+ /// primitive. Since it is the same size, this guarantees it has no
730
+ /// padding - integers have no padding, and there's no room for padding
731
+ /// if it can represent all of the same values except 0.
732
+ /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
733
+ /// `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
734
+ /// This is worded in a way that makes it unclear whether it's meant as a
735
+ /// guarantee, but given the purpose of those types, it's virtually
736
+ /// unthinkable that that would ever change. `Option` cannot be smaller
737
+ /// than its contained type, which implies that, and `NonZeroX8` are of
738
+ /// size 1 or 0. `NonZeroX8` can represent multiple states, so they cannot
739
+ /// be 0 bytes, which means that they must be 1 byte. The only valid
740
+ /// alignment for a 1-byte type is 1.
741
+ ///
742
+ /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
743
+ /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
723
744
/// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
724
745
/// that layout is the same as primitive layout.
725
- unsafe_impl!( NonZeroU8 : AsBytes ) ;
726
- unsafe_impl!( NonZeroI8 : AsBytes ) ;
746
+ unsafe_impl!( NonZeroU8 : AsBytes , Unaligned ) ;
747
+ unsafe_impl!( NonZeroI8 : AsBytes , Unaligned ) ;
748
+ assert_unaligned!( NonZeroU8 , NonZeroI8 ) ;
727
749
unsafe_impl!( NonZeroU16 : AsBytes ) ;
728
750
unsafe_impl!( NonZeroI16 : AsBytes ) ;
729
751
unsafe_impl!( NonZeroU32 : AsBytes ) ;
@@ -735,17 +757,26 @@ safety_comment! {
735
757
unsafe_impl!( NonZeroUsize : AsBytes ) ;
736
758
unsafe_impl!( NonZeroIsize : AsBytes ) ;
737
759
}
738
-
739
760
safety_comment ! {
740
761
/// SAFETY:
741
- /// The Rust compiler reuses `0` value to represent `None`, so
742
- /// `size_of::<Option<NonZeroXxx>>() == size_of::<xxx>()`; see `NonZeroXxx`
743
- /// documentation.
762
+ /// - `FromBytes`, `AsBytes`: The Rust compiler reuses `0` value to
763
+ /// represent `None`, so `size_of::<Option<NonZeroXxx>>() ==
764
+ /// size_of::<xxx>()`; see `NonZeroXxx` documentation.
765
+ /// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
766
+ /// `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
767
+ /// This is worded in a way that makes it unclear whether it's meant as a
768
+ /// guarantee, but given the purpose of those types, it's virtually
769
+ /// unthinkable that that would ever change. The only valid alignment for
770
+ /// a 1-byte type is 1.
771
+ ///
772
+ /// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
773
+ /// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
744
774
///
745
775
/// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
746
776
/// for layout guarantees.
747
- unsafe_impl!( Option <NonZeroU8 >: FromBytes , AsBytes ) ;
748
- unsafe_impl!( Option <NonZeroI8 >: FromBytes , AsBytes ) ;
777
+ unsafe_impl!( Option <NonZeroU8 >: FromBytes , AsBytes , Unaligned ) ;
778
+ unsafe_impl!( Option <NonZeroI8 >: FromBytes , AsBytes , Unaligned ) ;
779
+ assert_unaligned!( Option <NonZeroU8 >, Option <NonZeroI8 >) ;
749
780
unsafe_impl!( Option <NonZeroU16 >: FromBytes , AsBytes ) ;
750
781
unsafe_impl!( Option <NonZeroI16 >: FromBytes , AsBytes ) ;
751
782
unsafe_impl!( Option <NonZeroU32 >: FromBytes , AsBytes ) ;
@@ -776,6 +807,7 @@ safety_comment! {
776
807
unsafe_impl!( T : ?Sized => FromBytes for PhantomData <T >) ;
777
808
unsafe_impl!( T : ?Sized => AsBytes for PhantomData <T >) ;
778
809
unsafe_impl!( T : ?Sized => Unaligned for PhantomData <T >) ;
810
+ assert_unaligned!( PhantomData <( ) >, PhantomData <u8 >, PhantomData <u64 >) ;
779
811
}
780
812
safety_comment ! {
781
813
/// SAFETY:
@@ -789,17 +821,22 @@ safety_comment! {
789
821
unsafe_impl!( T : FromBytes => FromBytes for Wrapping <T >) ;
790
822
unsafe_impl!( T : AsBytes => AsBytes for Wrapping <T >) ;
791
823
unsafe_impl!( T : Unaligned => Unaligned for Wrapping <T >) ;
824
+ assert_unaligned!( Wrapping <( ) >, Wrapping <u8 >) ;
792
825
}
793
-
794
826
safety_comment ! {
795
827
// `MaybeUninit<T>` is `FromBytes`, but never `AsBytes` since it may contain
796
828
// uninitialized bytes.
797
829
//
798
830
/// SAFETY:
799
- /// `MaybeUninit<T>` has no restrictions on its contents.
831
+ /// - `FromBytes`: `MaybeUninit<T>` has no restrictions on its contents.
832
+ /// - `Unaligned`: `MaybeUninit<T>` is guaranteed by its documentation [1]
833
+ /// to have the same alignment as `T`.
834
+ ///
835
+ /// [1] https://doc.rust-lang.org/nightly/core/mem/union.MaybeUninit.html#layout-1
800
836
unsafe_impl!( T => FromBytes for MaybeUninit <T >) ;
837
+ unsafe_impl!( T : Unaligned => Unaligned for MaybeUninit <T >) ;
838
+ assert_unaligned!( MaybeUninit <( ) >, MaybeUninit <u8 >) ;
801
839
}
802
-
803
840
safety_comment ! {
804
841
/// SAFETY:
805
842
/// `ManuallyDrop` has the same layout as `T`, and accessing the inner value
@@ -818,8 +855,8 @@ safety_comment! {
818
855
unsafe_impl!( T : ?Sized + FromBytes => FromBytes for ManuallyDrop <T >) ;
819
856
unsafe_impl!( T : ?Sized + AsBytes => AsBytes for ManuallyDrop <T >) ;
820
857
unsafe_impl!( T : ?Sized + Unaligned => Unaligned for ManuallyDrop <T >) ;
858
+ assert_unaligned!( ManuallyDrop <( ) >, ManuallyDrop <u8 >) ;
821
859
}
822
-
823
860
safety_comment ! {
824
861
/// SAFETY:
825
862
/// Per the reference [1]:
@@ -839,10 +876,14 @@ safety_comment! {
839
876
/// since an array/slice has "the same alignment of `T`", `[T]` and `[T; N]`
840
877
/// are `Unaligned` if `T` is.
841
878
///
879
+ /// Note that we don't `assert_unaligned!` for slice types because
880
+ /// `assert_unaligned!` uses `align_of`, which only works for `Sized` types.
881
+ ///
842
882
/// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout
843
883
unsafe_impl!( T : FromBytes , const N : usize => FromBytes for [ T ; N ] ) ;
844
884
unsafe_impl!( T : AsBytes , const N : usize => AsBytes for [ T ; N ] ) ;
845
885
unsafe_impl!( T : Unaligned , const N : usize => Unaligned for [ T ; N ] ) ;
886
+ assert_unaligned!( [ ( ) ; 0 ] , [ ( ) ; 1 ] , [ u8 ; 0 ] , [ u8 ; 1 ] ) ;
846
887
unsafe_impl!( T : FromBytes => FromBytes for [ T ] ) ;
847
888
unsafe_impl!( T : AsBytes => AsBytes for [ T ] ) ;
848
889
unsafe_impl!( T : Unaligned => Unaligned for [ T ] ) ;
@@ -3830,10 +3871,8 @@ mod tests {
3830
3871
// `!Unaligned` at some point.
3831
3872
assert_impls ! ( str : AsBytes , !FromBytes , !Unaligned ) ;
3832
3873
3833
- // `NonZeroU8/NonZeroI8: Unaligned` is probably sound, so we can
3834
- // probably remove `!Unaligned` at some point.
3835
- assert_impls ! ( NonZeroU8 : AsBytes , !FromBytes , !Unaligned ) ;
3836
- assert_impls ! ( NonZeroI8 : AsBytes , !FromBytes , !Unaligned ) ;
3874
+ assert_impls ! ( NonZeroU8 : AsBytes , Unaligned , !FromBytes ) ;
3875
+ assert_impls ! ( NonZeroI8 : AsBytes , Unaligned , !FromBytes ) ;
3837
3876
assert_impls ! ( NonZeroU16 : AsBytes , !FromBytes , !Unaligned ) ;
3838
3877
assert_impls ! ( NonZeroI16 : AsBytes , !FromBytes , !Unaligned ) ;
3839
3878
assert_impls ! ( NonZeroU32 : AsBytes , !FromBytes , !Unaligned ) ;
@@ -3845,10 +3884,8 @@ mod tests {
3845
3884
assert_impls ! ( NonZeroUsize : AsBytes , !FromBytes , !Unaligned ) ;
3846
3885
assert_impls ! ( NonZeroIsize : AsBytes , !FromBytes , !Unaligned ) ;
3847
3886
3848
- // `Option<NonZeroU8>/Option<NonZeroI8>: Unaligned` is probably sound,
3849
- // so we can probably remove `!Unaligned` at some point.
3850
- assert_impls ! ( Option <NonZeroU8 >: FromBytes , AsBytes , !Unaligned ) ;
3851
- assert_impls ! ( Option <NonZeroI8 >: FromBytes , AsBytes , !Unaligned ) ;
3887
+ assert_impls ! ( Option <NonZeroU8 >: FromBytes , AsBytes , Unaligned ) ;
3888
+ assert_impls ! ( Option <NonZeroI8 >: FromBytes , AsBytes , Unaligned ) ;
3852
3889
assert_impls ! ( Option <NonZeroU16 >: FromBytes , AsBytes , !Unaligned ) ;
3853
3890
assert_impls ! ( Option <NonZeroI16 >: FromBytes , AsBytes , !Unaligned ) ;
3854
3891
assert_impls ! ( Option <NonZeroU32 >: FromBytes , AsBytes , !Unaligned ) ;
@@ -3871,7 +3908,7 @@ mod tests {
3871
3908
assert_impls ! ( ManuallyDrop <NotZerocopy >: !FromBytes , !AsBytes , !Unaligned ) ;
3872
3909
assert_impls ! ( ManuallyDrop <[ NotZerocopy ] >: !FromBytes , !AsBytes , !Unaligned ) ;
3873
3910
3874
- assert_impls ! ( MaybeUninit <u8 >: FromBytes , ! AsBytes , !Unaligned ) ;
3911
+ assert_impls ! ( MaybeUninit <u8 >: FromBytes , Unaligned , !AsBytes ) ;
3875
3912
assert_impls ! ( MaybeUninit <NotZerocopy >: FromBytes , !AsBytes , !Unaligned ) ;
3876
3913
3877
3914
assert_impls ! ( Wrapping <u8 >: FromBytes , AsBytes , Unaligned ) ;
0 commit comments