From dcadae6610ca22433ce0274669bdac38405a0380 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Fri, 3 Nov 2023 19:56:44 -0700 Subject: [PATCH] FromZeroes for Option where T is subject to NPO (#595) For thin pointer types, `P` (`Box`, `&T`, `&mut T`, and `NonNull` where `T: Sized`), implement `FromZeroes` for `Option

`. Release 0.7.25. Closes #293 --- Cargo.toml | 8 +++---- src/lib.rs | 43 +++++++++++++++++++++++++++++++++++++- src/macros.rs | 6 +++--- zerocopy-derive/Cargo.toml | 2 +- 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9188f719d6..6624447390 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ [package] edition = "2018" name = "zerocopy" -version = "0.7.24" +version = "0.7.25" authors = ["Joshua Liebow-Feeser "] description = "Utilities for zero-copy parsing and serialization" license = "BSD-2-Clause OR Apache-2.0 OR MIT" @@ -49,7 +49,7 @@ simd-nightly = ["simd"] __internal_use_only_features_that_work_on_stable = ["alloc", "derive", "simd"] [dependencies] -zerocopy-derive = { version = "=0.7.24", path = "zerocopy-derive", optional = true } +zerocopy-derive = { version = "=0.7.25", path = "zerocopy-derive", optional = true } [dependencies.byteorder] version = "1.3" @@ -60,7 +60,7 @@ optional = true # zerocopy-derive remain equal, even if the 'derive' feature isn't used. # See: https://github.com/matklad/macro-dep-test [target.'cfg(any())'.dependencies] -zerocopy-derive = { version = "=0.7.24", path = "zerocopy-derive" } +zerocopy-derive = { version = "=0.7.25", path = "zerocopy-derive" } [dev-dependencies] assert_matches = "1.5" @@ -75,6 +75,6 @@ testutil = { path = "testutil" } # CI test failures. trybuild = { version = "=1.0.85", features = ["diff"] } # In tests, unlike in production, zerocopy-derive is not optional -zerocopy-derive = { version = "=0.7.24", path = "zerocopy-derive" } +zerocopy-derive = { version = "=0.7.25", path = "zerocopy-derive" } # TODO(#381) Remove this dependency once we have our own layout gadgets. elain = "0.3.0" diff --git a/src/lib.rs b/src/lib.rs index 1490e6100a..afad1386c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1880,6 +1880,37 @@ safety_comment! { unsafe_impl!(Option: FromZeroes, FromBytes, AsBytes); } +safety_comment! { + /// SAFETY: + /// The following types can be transmuted from `[0u8; size_of::()]`. [1] + /// None of them contain `UnsafeCell`s, and so they all soundly implement + /// `FromZeroes`. + /// + /// [1] Per + /// https://doc.rust-lang.org/nightly/core/option/index.html#representation: + /// + /// Rust guarantees to optimize the following types `T` such that + /// [`Option`] has the same size and alignment as `T`. In some of these + /// cases, Rust further guarantees that `transmute::<_, Option>([0u8; + /// size_of::()])` is sound and produces `Option::::None`. These + /// cases are identified by the second column: + /// + /// | `T` | `transmute::<_, Option>([0u8; size_of::()])` sound? | + /// |---------------------|-----------------------------------------------------------| + /// | [`Box`] | when `U: Sized` | + /// | `&U` | when `U: Sized` | + /// | `&mut U` | when `U: Sized` | + /// | [`ptr::NonNull`] | when `U: Sized` | + /// + /// TODO(#429), TODO(https://github.com/rust-lang/rust/pull/115333): Cite + /// the Stable docs once they're available. + #[cfg(feature = "alloc")] + unsafe_impl!(T => FromZeroes for Option>); + unsafe_impl!(T => FromZeroes for Option<&'_ T>); + unsafe_impl!(T => FromZeroes for Option<&'_ mut T>); + unsafe_impl!(T => FromZeroes for Option>); +} + safety_comment! { /// SAFETY: /// For all `T`, `PhantomData` has size 0 and alignment 1. [1] @@ -3820,7 +3851,7 @@ pub use alloc_support::*; mod tests { #![allow(clippy::unreadable_literal)] - use core::{convert::TryInto as _, ops::Deref}; + use core::{cell::UnsafeCell, convert::TryInto as _, ops::Deref}; use static_assertions::assert_impl_all; @@ -5515,6 +5546,16 @@ mod tests { // Implements none of the ZC traits. struct NotZerocopy; + #[cfg(feature = "alloc")] + assert_impls!(Option>>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option]>>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static UnsafeCell>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static [UnsafeCell]>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static mut UnsafeCell>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option<&'static mut [UnsafeCell]>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option>>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(Option]>>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned); + assert_impls!(PhantomData: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned); assert_impls!(PhantomData<[u8]>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned); diff --git a/src/macros.rs b/src/macros.rs index 7d30033bd4..c54280094a 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -26,9 +26,9 @@ /// The macro invocations are emitted, each decorated with the following /// attribute: `#[allow(clippy::undocumented_unsafe_blocks)]`. macro_rules! safety_comment { - (#[doc = r" SAFETY:"] $($(#[doc = $_doc:literal])* $macro:ident!$args:tt;)*) => { - #[allow(clippy::undocumented_unsafe_blocks)] - const _: () = { $($macro!$args;)* }; + (#[doc = r" SAFETY:"] $($(#[$attr:meta])* $macro:ident!$args:tt;)*) => { + #[allow(clippy::undocumented_unsafe_blocks, unused_attributes)] + const _: () = { $($(#[$attr])* $macro!$args;)* }; } } diff --git a/zerocopy-derive/Cargo.toml b/zerocopy-derive/Cargo.toml index fc26f0261c..c73599586d 100644 --- a/zerocopy-derive/Cargo.toml +++ b/zerocopy-derive/Cargo.toml @@ -9,7 +9,7 @@ [package] edition = "2018" name = "zerocopy-derive" -version = "0.7.24" +version = "0.7.25" authors = ["Joshua Liebow-Feeser "] description = "Custom derive for traits from the zerocopy crate" license = "BSD-2-Clause OR Apache-2.0 OR MIT"