@@ -576,19 +576,6 @@ macro_rules! safety_comment {
576576
577577/// Unsafely implements trait(s) for a type.
578578macro_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- } ;
592579 // Implement `$trait` for `$ty` with no bounds.
593580 ( $ty: ty: $trait: ty) => {
594581 unsafe impl $trait for $ty { fn only_derive_is_allowed_to_implement_this_trait( ) { } }
@@ -622,6 +609,23 @@ macro_rules! unsafe_impl {
622609 } ;
623610}
624611
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+
625629safety_comment ! {
626630 /// SAFETY:
627631 /// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a
@@ -633,6 +637,7 @@ safety_comment! {
633637 ///
634638 /// [1] https://doc.rust-lang.org/reference/type-layout.html#tuple-layout
635639 unsafe_impl!( ( ) : FromBytes , AsBytes , Unaligned ) ;
640+ assert_unaligned!( ( ) ) ;
636641}
637642
638643safety_comment ! {
@@ -651,6 +656,7 @@ safety_comment! {
651656 /// [2] https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout
652657 unsafe_impl!( u8 : FromBytes , AsBytes , Unaligned ) ;
653658 unsafe_impl!( i8 : FromBytes , AsBytes , Unaligned ) ;
659+ assert_unaligned!( u8 , i8 ) ;
654660 unsafe_impl!( u16 : FromBytes , AsBytes ) ;
655661 unsafe_impl!( i16 : FromBytes , AsBytes ) ;
656662 unsafe_impl!( u32 : FromBytes , AsBytes ) ;
@@ -692,6 +698,7 @@ safety_comment! {
692698 ///
693699 /// [1] https://doc.rust-lang.org/reference/types/boolean.html
694700 unsafe_impl!( bool : AsBytes , Unaligned ) ;
701+ assert_unaligned!( bool ) ;
695702}
696703safety_comment ! {
697704 /// SAFETY:
@@ -704,26 +711,41 @@ safety_comment! {
704711}
705712safety_comment ! {
706713 /// 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.
709719 ///
710720 /// [1] https://doc.rust-lang.org/reference/type-layout.html#str-layout
711- unsafe_impl!( str : AsBytes ) ;
721+ unsafe_impl!( str : AsBytes , Unaligned ) ;
712722}
713723
714724safety_comment ! {
715725 // `NonZeroXxx` is `AsBytes`, but not `FromBytes`.
716726 //
717727 /// 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
723744 /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
724745 /// 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 ) ;
727749 unsafe_impl!( NonZeroU16 : AsBytes ) ;
728750 unsafe_impl!( NonZeroI16 : AsBytes ) ;
729751 unsafe_impl!( NonZeroU32 : AsBytes ) ;
@@ -735,17 +757,26 @@ safety_comment! {
735757 unsafe_impl!( NonZeroUsize : AsBytes ) ;
736758 unsafe_impl!( NonZeroIsize : AsBytes ) ;
737759}
738-
739760safety_comment ! {
740761 /// 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
744774 ///
745775 /// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
746776 /// 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 >) ;
749780 unsafe_impl!( Option <NonZeroU16 >: FromBytes , AsBytes ) ;
750781 unsafe_impl!( Option <NonZeroI16 >: FromBytes , AsBytes ) ;
751782 unsafe_impl!( Option <NonZeroU32 >: FromBytes , AsBytes ) ;
@@ -776,6 +807,7 @@ safety_comment! {
776807 unsafe_impl!( T : ?Sized => FromBytes for PhantomData <T >) ;
777808 unsafe_impl!( T : ?Sized => AsBytes for PhantomData <T >) ;
778809 unsafe_impl!( T : ?Sized => Unaligned for PhantomData <T >) ;
810+ assert_unaligned!( PhantomData <( ) >, PhantomData <u8 >, PhantomData <u64 >) ;
779811}
780812safety_comment ! {
781813 /// SAFETY:
@@ -789,17 +821,22 @@ safety_comment! {
789821 unsafe_impl!( T : FromBytes => FromBytes for Wrapping <T >) ;
790822 unsafe_impl!( T : AsBytes => AsBytes for Wrapping <T >) ;
791823 unsafe_impl!( T : Unaligned => Unaligned for Wrapping <T >) ;
824+ assert_unaligned!( Wrapping <( ) >, Wrapping <u8 >) ;
792825}
793-
794826safety_comment ! {
795827 // `MaybeUninit<T>` is `FromBytes`, but never `AsBytes` since it may contain
796828 // uninitialized bytes.
797829 //
798830 /// 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
800836 unsafe_impl!( T => FromBytes for MaybeUninit <T >) ;
837+ unsafe_impl!( T : Unaligned => Unaligned for MaybeUninit <T >) ;
838+ assert_unaligned!( MaybeUninit <( ) >, MaybeUninit <u8 >) ;
801839}
802-
803840safety_comment ! {
804841 /// SAFETY:
805842 /// `ManuallyDrop` has the same layout as `T`, and accessing the inner value
@@ -818,8 +855,8 @@ safety_comment! {
818855 unsafe_impl!( T : ?Sized + FromBytes => FromBytes for ManuallyDrop <T >) ;
819856 unsafe_impl!( T : ?Sized + AsBytes => AsBytes for ManuallyDrop <T >) ;
820857 unsafe_impl!( T : ?Sized + Unaligned => Unaligned for ManuallyDrop <T >) ;
858+ assert_unaligned!( ManuallyDrop <( ) >, ManuallyDrop <u8 >) ;
821859}
822-
823860safety_comment ! {
824861 /// SAFETY:
825862 /// Per the reference [1]:
@@ -839,10 +876,14 @@ safety_comment! {
839876 /// since an array/slice has "the same alignment of `T`", `[T]` and `[T; N]`
840877 /// are `Unaligned` if `T` is.
841878 ///
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+ ///
842882 /// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout
843883 unsafe_impl!( T : FromBytes , const N : usize => FromBytes for [ T ; N ] ) ;
844884 unsafe_impl!( T : AsBytes , const N : usize => AsBytes for [ T ; N ] ) ;
845885 unsafe_impl!( T : Unaligned , const N : usize => Unaligned for [ T ; N ] ) ;
886+ assert_unaligned!( [ ( ) ; 0 ] , [ ( ) ; 1 ] , [ u8 ; 0 ] , [ u8 ; 1 ] ) ;
846887 unsafe_impl!( T : FromBytes => FromBytes for [ T ] ) ;
847888 unsafe_impl!( T : AsBytes => AsBytes for [ T ] ) ;
848889 unsafe_impl!( T : Unaligned => Unaligned for [ T ] ) ;
@@ -3830,10 +3871,8 @@ mod tests {
38303871 // `!Unaligned` at some point.
38313872 assert_impls ! ( str : AsBytes , !FromBytes , !Unaligned ) ;
38323873
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 ) ;
38373876 assert_impls ! ( NonZeroU16 : AsBytes , !FromBytes , !Unaligned ) ;
38383877 assert_impls ! ( NonZeroI16 : AsBytes , !FromBytes , !Unaligned ) ;
38393878 assert_impls ! ( NonZeroU32 : AsBytes , !FromBytes , !Unaligned ) ;
@@ -3845,10 +3884,8 @@ mod tests {
38453884 assert_impls ! ( NonZeroUsize : AsBytes , !FromBytes , !Unaligned ) ;
38463885 assert_impls ! ( NonZeroIsize : AsBytes , !FromBytes , !Unaligned ) ;
38473886
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 ) ;
38523889 assert_impls ! ( Option <NonZeroU16 >: FromBytes , AsBytes , !Unaligned ) ;
38533890 assert_impls ! ( Option <NonZeroI16 >: FromBytes , AsBytes , !Unaligned ) ;
38543891 assert_impls ! ( Option <NonZeroU32 >: FromBytes , AsBytes , !Unaligned ) ;
@@ -3871,7 +3908,7 @@ mod tests {
38713908 assert_impls ! ( ManuallyDrop <NotZerocopy >: !FromBytes , !AsBytes , !Unaligned ) ;
38723909 assert_impls ! ( ManuallyDrop <[ NotZerocopy ] >: !FromBytes , !AsBytes , !Unaligned ) ;
38733910
3874- assert_impls ! ( MaybeUninit <u8 >: FromBytes , ! AsBytes , !Unaligned ) ;
3911+ assert_impls ! ( MaybeUninit <u8 >: FromBytes , Unaligned , !AsBytes ) ;
38753912 assert_impls ! ( MaybeUninit <NotZerocopy >: FromBytes , !AsBytes , !Unaligned ) ;
38763913
38773914 assert_impls ! ( Wrapping <u8 >: FromBytes , AsBytes , Unaligned ) ;
0 commit comments