Skip to content

Commit 78d252c

Browse files
committed
Update safety comments for NonZeroXxx types
Makes progress on #429
1 parent 8a7f874 commit 78d252c

File tree

1 file changed

+57
-35
lines changed

1 file changed

+57
-35
lines changed

src/lib.rs

+57-35
Original file line numberDiff line numberDiff line change
@@ -1832,26 +1832,28 @@ safety_comment! {
18321832
// `NonZeroXxx` is `AsBytes`, but not `FromZeroes` or `FromBytes`.
18331833
//
18341834
/// SAFETY:
1835-
/// - `AsBytes`: `NonZeroXxx` has the same layout as its associated
1836-
/// primitive. Since it is the same size, this guarantees it has no
1837-
/// padding - integers have no padding, and there's no room for padding
1838-
/// if it can represent all of the same values except 0.
1839-
/// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
1840-
/// `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
1841-
/// This is worded in a way that makes it unclear whether it's meant as a
1842-
/// guarantee, but given the purpose of those types, it's virtually
1843-
/// unthinkable that that would ever change. `Option` cannot be smaller
1844-
/// than its contained type, which implies that, and `NonZeroX8` are of
1845-
/// size 1 or 0. `NonZeroX8` can represent multiple states, so they cannot
1846-
/// be 0 bytes, which means that they must be 1 byte. The only valid
1847-
/// alignment for a 1-byte type is 1.
1835+
/// `NonZeroXxx` has the same layout and bit validity as its associated
1836+
/// primitive with the exception that 0 is not a valid instance. [1]
1837+
/// - `AsBytes`: Since none of the associated primitives allow uninitialized
1838+
/// bytes, neither do `NonZeroXxx`.
1839+
/// - `Unaligned`: For `NonZeroU8` and `NonZeroI8`, we know that the `u8`
1840+
/// and `i8` types have alignment 1 (this is true because they have size 1
1841+
/// [2] and a type's alignment cannot be greater than its size [3]).
18481842
///
1849-
/// TODO(#429): Add quotes from documentation.
1843+
/// [1] Per https://doc.rust-lang.org/beta/core/num/struct.NonZeroU16.html#layout-1:
1844+
///
1845+
/// `NonZeroU16` is guaranteed to have the same layout and bit validity as
1846+
/// `u16` with the exception that `0` is not a valid instance.
1847+
///
1848+
/// TODO(https://github.com/rust-lang/rust/pull/94786): Once the Stable docs
1849+
/// include this text, cite those docs instead of the Beta docs.
1850+
///
1851+
/// [2] Per https://doc.rust-lang.org/reference/type-layout.html#primitive-data-layout,
1852+
/// `size_of::<Type>()` for `u8` and `i8` is 1.
1853+
///
1854+
/// [3] Per https://doc.rust-lang.org/reference/type-layout.html#size-and-alignment:
18501855
///
1851-
/// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
1852-
/// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
1853-
/// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
1854-
/// that layout is the same as primitive layout.
1856+
/// The size of a value is always a multiple of its alignment.
18551857
unsafe_impl!(NonZeroU8: AsBytes, Unaligned);
18561858
unsafe_impl!(NonZeroI8: AsBytes, Unaligned);
18571859
assert_unaligned!(NonZeroU8, NonZeroI8);
@@ -1868,23 +1870,43 @@ safety_comment! {
18681870
}
18691871
safety_comment! {
18701872
/// SAFETY:
1871-
/// - `FromZeroes`, `FromBytes`, `AsBytes`: The Rust compiler reuses `0`
1872-
/// value to represent `None`, so `size_of::<Option<NonZeroXxx>>() ==
1873-
/// size_of::<xxx>()`; see `NonZeroXxx` documentation.
1874-
/// - `Unaligned`: `NonZeroU8` and `NonZeroI8` document that
1875-
/// `Option<NonZeroU8>` and `Option<NonZeroI8>` both have size 1. [1] [2]
1876-
/// This is worded in a way that makes it unclear whether it's meant as a
1877-
/// guarantee, but given the purpose of those types, it's virtually
1878-
/// unthinkable that that would ever change. The only valid alignment for
1879-
/// a 1-byte type is 1.
1880-
///
1881-
/// TODO(#429): Add quotes from documentation.
1882-
///
1883-
/// [1] https://doc.rust-lang.org/stable/std/num/struct.NonZeroU8.html
1884-
/// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
1885-
///
1886-
/// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
1887-
/// for layout guarantees.
1873+
/// - `FromZeroes`: For all of these types, `T`, `transmute::<_,
1874+
/// Option<T>>([0u8; size_of::<T>()])` is guaranteed to be sound. [1]
1875+
/// - `FromBytes`, `AsBytes`: We know that transmuting from 0 produces
1876+
/// `None`. [1] We further know that `NonZeroXxx` has the same size and
1877+
/// alignment as `Option<NonZeroXxx>`. [2] Finally, we know that
1878+
/// `NonZeroXxx` has the same bit validity as `Xxx` with the exception of
1879+
/// 0. [2] Since `Xxx: FromBytes`, in order for `Option<NonZeroXxx>:
1880+
/// FromBytes`, it only needs to be the case that 0 is a valid instance of
1881+
/// `Option<NonZeroXxx>`, which is guaranteed. Since `Xxx: AsBytes`, it
1882+
/// only needs to be the case that `Option::<NonZeroXxx>::None` has all of
1883+
/// its bytes initialized. [3]
1884+
/// - `Unaligned`: `NonZeroU8` and `NonZeroI8` both implement `Unaligned`,
1885+
/// and so have alignment 1. Per [2], `Option<NonZeroU8>` and
1886+
/// `Option<NonZeroI8>` have the same alignment.
1887+
///
1888+
/// [1] Per https://doc.rust-lang.org/nightly/core/option/#representation,
1889+
/// it is always true that, for `T` = `num::NonZero*`, `transmute::<_,
1890+
/// Option<T>>([0u8; size_of::<T>()])` and produces `Option::<T>::None`.
1891+
///
1892+
/// TODO(https://github.com/rust-lang/rust/pull/115333): Once the Stable
1893+
/// docs include this text, cite those docs instead of the Nightly docs.
1894+
///
1895+
/// [2] Per https://doc.rust-lang.org/beta/core/num/struct.NonZeroU16.html#layout-1:
1896+
///
1897+
/// `NonZeroU16` is guaranteed to have the same layout and bit validity as
1898+
/// `u16` with the exception that `0` is not a valid instance. ...
1899+
///
1900+
/// Thanks to the null pointer optimization, `NonZeroU16` and
1901+
/// `Option<NonZeroU16>` are guaranteed to have the same size and
1902+
/// alignment.
1903+
///
1904+
/// TODO(https://github.com/rust-lang/rust/pull/94786): Once the Stable docs
1905+
/// include this text, cite those docs instead of the Beta docs.
1906+
///
1907+
/// [3] TODO(#429): Cite documentation that guarantees that
1908+
/// `Option::<T>::None` has all of its bytes initialized where `T` is a
1909+
/// type subject to the null-pointer optimization (NPO).
18881910
unsafe_impl!(Option<NonZeroU8>: FromZeroes, FromBytes, AsBytes, Unaligned);
18891911
unsafe_impl!(Option<NonZeroI8>: FromZeroes, FromBytes, AsBytes, Unaligned);
18901912
assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);

0 commit comments

Comments
 (0)