diff --git a/src/impls.rs b/src/impls.rs index 0ee2719a87..0c67838c70 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -7,7 +7,11 @@ // This file may not be copied, modified, or distributed except according to // those terms. -use core::{cell::UnsafeCell, mem::MaybeUninit as CoreMaybeUninit, ptr::NonNull}; +use core::{ + cell::{Cell, UnsafeCell}, + mem::MaybeUninit as CoreMaybeUninit, + ptr::NonNull, +}; use super::*; @@ -96,32 +100,14 @@ safety_comment! { unsafe_impl!(bool: Immutable, FromZeros, IntoBytes, Unaligned); assert_unaligned!(bool); /// SAFETY: - /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` - /// closure: - /// - Given `t: *mut bool` and `let r = *mut u8`, `r` refers to an object - /// of the same size as that referred to by `t`. This is true because - /// `bool` and `u8` have the same size (1 byte) [1]. Neither `r` nor `t` - /// contain `UnsafeCell`s because neither `bool` nor `u8` do [3]. - /// - The impl must only return `true` for its argument if the original - /// `Maybe` refers to a valid `bool`. We only return true if the - /// `u8` value is 0 or 1, and both of these are valid values for `bool`. - /// [2] + /// The impl must only return `true` for its argument if the original + /// `Maybe` refers to a valid `bool`. We only return true if the `u8` + /// value is 0 or 1, and both of these are valid values for `bool` [1]. /// - /// [1] Per https://doc.rust-lang.org/1.81.0/reference/type-layout.html#primitive-data-layout: - /// - /// The size of most primitives is given in this table. - /// - /// | Type | `size_of::() ` | - /// |-----------|----------------------| - /// | `bool` | 1 | - /// | `u8`/`i8` | 1 | - /// - /// [2] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html: + /// [1] Per https://doc.rust-lang.org/1.81.0/reference/types/boolean.html: /// /// The value false has the bit pattern 0x00 and the value true has the /// bit pattern 0x01. - /// - /// [3] TODO(#429): Justify this claim. unsafe_impl!(=> TryFromBytes for bool; |byte| { let byte = byte.transmute::(); *byte.unaligned_as_ref() < 2 @@ -144,27 +130,14 @@ safety_comment! { /// [1] https://doc.rust-lang.org/1.81.0/reference/types/textual.html unsafe_impl!(char: Immutable, FromZeros, IntoBytes); /// SAFETY: - /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` - /// closure: - /// - Given `t: *mut char` and `let r = *mut u32`, `r` refers to an object - /// of the same size as that referred to by `t`. This is true because - /// `char` and `u32` have the same size [1]. Neither `r` nor `t` contain - /// `UnsafeCell`s because neither `char` nor `u32` do [3]. - /// - The impl must only return `true` for its argument if the original - /// `Maybe` refers to a valid `char`. `char::from_u32` guarantees - /// that it returns `None` if its input is not a valid `char`. [2] - /// - /// [1] Per https://doc.rust-lang.org/nightly/reference/types/textual.html#layout-and-bit-validity: + /// The impl must only return `true` for its argument if the original + /// `Maybe` refers to a valid `char`. `char::from_u32` guarantees that + /// it returns `None` if its input is not a valid `char` [1]. /// - /// `char` is guaranteed to have the same size and alignment as `u32` on - /// all platforms. - /// - /// [2] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32: + /// [1] Per https://doc.rust-lang.org/core/primitive.char.html#method.from_u32: /// /// `from_u32()` will return `None` if the input is not a valid value for /// a `char`. - /// - /// [3] TODO(#429): Justify this claim. unsafe_impl!(=> TryFromBytes for char; |c| { let c = c.transmute::, invariant::Valid, _>(); let c = c.read_unaligned().into_inner(); @@ -192,20 +165,9 @@ safety_comment! { /// [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#str-layout unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unaligned); /// SAFETY: - /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` - /// closure: - /// - Given `t: *mut str` and `let r = *mut [u8]`, `r` refers to an object - /// of the same size as that referred to by `t`. This is true because - /// `str` and `[u8]` have the same representation. [1] Neither `t` nor - /// `r` contain `UnsafeCell`s because `[u8]` doesn't, and both `t` and - /// `r` have that representation. - /// - The impl must only return `true` for its argument if the original - /// `Maybe` refers to a valid `str`. `str::from_utf8` guarantees - /// that it returns `Err` if its input is not a valid `str`. [2] - /// - /// [1] Per https://doc.rust-lang.org/1.81.0/reference/types/textual.html: - /// - /// A value of type `str` is represented the same was as `[u8]`. + /// The impl must only return `true` for its argument if the original + /// `Maybe` refers to a valid `str`. `str::from_utf8` guarantees that + /// it returns `Err` if its input is not a valid `str` [1]. /// /// [2] Per https://doc.rust-lang.org/core/str/fn.from_utf8.html#errors: /// @@ -303,25 +265,6 @@ safety_comment! { unsafe_impl!(NonZeroI128: Immutable, IntoBytes); unsafe_impl!(NonZeroUsize: Immutable, IntoBytes); unsafe_impl!(NonZeroIsize: Immutable, IntoBytes); - /// SAFETY: - /// - The safety requirements for `unsafe_impl!` with an `is_bit_valid` - /// closure: - /// - Given `t: *mut NonZeroXxx` and `let r = *mut xxx`, `r` refers to an - /// object of the same size as that referred to by `t`. This is true - /// because `NonZeroXxx` and `xxx` have the same size. [1] Neither `r` - /// nor `t` refer to any `UnsafeCell`s because neither `NonZeroXxx` [2] - /// nor `xxx` do. - /// - The impl must only return `true` for its argument if the original - /// `Maybe` refers to a valid `NonZeroXxx`. The only `xxx` - /// which is not also a valid `NonZeroXxx` is 0. [1] - /// - /// [1] Per https://doc.rust-lang.org/1.81.0/core/num/type.NonZeroU16.html: - /// - /// `NonZeroU16` is guaranteed to have the same layout and bit validity as - /// `u16` with the exception that `0` is not a valid instance. - /// - /// [2] `NonZeroXxx` self-evidently does not contain `UnsafeCell`s. This is - /// not a proof, but we are accepting this as a known risk per #1358. unsafe_impl_try_from_bytes_for_nonzero!( NonZeroU8[u8], NonZeroI8[i8], @@ -862,6 +805,21 @@ safety_comment! { } assert_unaligned!(ManuallyDrop<()>, ManuallyDrop); +impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for Cell[UnsafeCell]); +impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for Cell[UnsafeCell]); +impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for Cell[UnsafeCell]); +impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for Cell[UnsafeCell]); +safety_comment! { + /// SAFETY: + /// `Cell` has the same in-memory representation as `T` [1], and thus has + /// the same alignment as `T`. + /// + /// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.Cell.html#memory-layout: + /// + /// `Cell` has the same in-memory representation as its inner type `T`. + unsafe_impl!(T: ?Sized + Unaligned => Unaligned for Cell); +} + impl_for_transmute_from!(T: ?Sized + FromZeros => FromZeros for UnsafeCell[]); impl_for_transmute_from!(T: ?Sized + FromBytes => FromBytes for UnsafeCell[]); impl_for_transmute_from!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell[]); diff --git a/src/lib.rs b/src/lib.rs index d507a21267..7458b72038 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -357,7 +357,7 @@ pub use crate::r#ref::*; pub use crate::wrappers::*; use core::{ - cell::UnsafeCell, + cell::{Cell, UnsafeCell}, cmp::Ordering, fmt::{self, Debug, Display, Formatter}, hash::Hasher, @@ -983,29 +983,27 @@ impl_known_layout!(const N: usize, T => [T; N]); safety_comment! { /// SAFETY: - /// `str`, `ManuallyDrop<[T]>` [1], and `UnsafeCell` [2] have the same - /// representations as `[u8]`, `[T]`, and `T` repsectively. `str` has - /// different bit validity than `[u8]`, but that doesn't affect the - /// soundness of this impl. + /// `str` has the same representation as `[u8]`. `ManuallyDrop` [1], + /// `UnsafeCell` [2], and `Cell` [3] have the same representation as + /// `T`. /// - /// [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: + /// [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: /// /// `ManuallyDrop` is guaranteed to have the same layout and bit /// validity as `T` /// - /// [2] Per https://doc.rust-lang.org/core/cell/struct.UnsafeCell.html#memory-layout: + /// [2] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.UnsafeCell.html#memory-layout: /// /// `UnsafeCell` has the same in-memory representation as its inner /// type `T`. /// - /// TODO(#429): - /// - Add quotes from docs. - /// - Once [1] (added in - /// https://github.com/rust-lang/rust/pull/115522) is available on stable, - /// quote the stable docs instead of the nightly docs. + /// [3] Per https://doc.rust-lang.org/1.85.0/core/cell/struct.Cell.html#memory-layout: + /// + /// `Cell` has the same in-memory representation as `T`. unsafe_impl_known_layout!(#[repr([u8])] str); unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] ManuallyDrop); unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] UnsafeCell); + unsafe_impl_known_layout!(T: ?Sized + KnownLayout => #[repr(T)] Cell); } safety_comment! { diff --git a/src/pointer/transmute.rs b/src/pointer/transmute.rs index d98e7a795a..a774cd8d31 100644 --- a/src/pointer/transmute.rs +++ b/src/pointer/transmute.rs @@ -7,7 +7,7 @@ // those terms. use core::{ - cell::UnsafeCell, + cell::{Cell, UnsafeCell}, mem::{ManuallyDrop, MaybeUninit}, num::Wrapping, ptr::NonNull, @@ -405,20 +405,44 @@ safety_comment! { unsafe_impl_invariants_eq!(T => T, Wrapping); /// SAFETY: - /// - `Unalign` has the same size as `T` [1]. - /// - Per [1], `Unalign` has the same bit validity as `T`. Technically + /// - `UnsafeCell` has the same size as `T` [1]. + /// - Per [1], `UnsafeCell` has the same bit validity as `T`. Technically /// the term "representation" doesn't guarantee this, but the subsequent /// sentence in the documentation makes it clear that this is the /// intention. /// /// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: /// - /// `UnsafeCell` has the same in-memory representation as its inner type - /// `T`. A consequence of this guarantee is that it is possible to convert - /// between `T` and `UnsafeCell`. + /// `UnsafeCell` has the same in-memory representation as its inner + /// type `T`. A consequence of this guarantee is that it is possible to + /// convert between `T` and `UnsafeCell`. unsafe_impl_for_transparent_wrapper!(T: ?Sized => UnsafeCell); + + /// SAFETY: + /// - `Cell` has the same size as `T` [1]. + /// - Per [1], `Cell` has the same bit validity as `T`. Technically the + /// term "representation" doesn't guarantee this, but it does promise to + /// have the "same memory layout and caveats as `UnsafeCell`." The + /// `UnsafeCell` docs [2] make it clear that bit validity is the intention + /// even if that phrase isn't used. + /// + /// [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.Cell.html#memory-layout: + /// + /// `Cell` has the same memory layout and caveats as `UnsafeCell`. + /// In particular, this means that `Cell` has the same in-memory + /// representation as its inner type `T`. + /// + /// [2] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: + /// + /// `UnsafeCell` has the same in-memory representation as its inner + /// type `T`. A consequence of this guarantee is that it is possible to + /// convert between `T` and `UnsafeCell`. + unsafe_impl_for_transparent_wrapper!(T: ?Sized => Cell); } +impl_transitive_transmute_from!(T: ?Sized => Cell => T => UnsafeCell); +impl_transitive_transmute_from!(T: ?Sized => UnsafeCell => T => Cell); + // SAFETY: `MaybeUninit` has no validity requirements. Currently this is not // explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation // that this is the intention: diff --git a/src/wrappers.rs b/src/wrappers.rs index be7bd64139..d683d12618 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -129,12 +129,6 @@ safety_comment! { /// `UnsafeCell`s exactly when `T` does. /// - `TryFromBytes`: `Unalign` has the same the same bit validity as /// `T`, so `T::is_bit_valid` is a sound implementation of `is_bit_valid`. - /// Furthermore: - /// - Since `T` and `Unalign` have the same layout, they have the same - /// size (as required by `unsafe_impl!`). - /// - Since `T` and `Unalign` have the same fields, they have - /// `UnsafeCell`s at the same byte ranges (as required by - /// `unsafe_impl!`). impl_or_verify!(T => Unaligned for Unalign); impl_or_verify!(T: Immutable => Immutable for Unalign); impl_or_verify!( diff --git a/tests/ui-nightly/diagnostic-not-implemented-unaligned.stderr b/tests/ui-nightly/diagnostic-not-implemented-unaligned.stderr index 4ee17e1b9a..9ff575a23c 100644 --- a/tests/ui-nightly/diagnostic-not-implemented-unaligned.stderr +++ b/tests/ui-nightly/diagnostic-not-implemented-unaligned.stderr @@ -10,10 +10,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others note: required by a bound in `takes_unaligned` --> tests/ui-nightly/diagnostic-not-implemented-unaligned.rs:21:23 diff --git a/tests/ui-stable/diagnostic-not-implemented-unaligned.stderr b/tests/ui-stable/diagnostic-not-implemented-unaligned.stderr index 27b3769ed2..d9463715de 100644 --- a/tests/ui-stable/diagnostic-not-implemented-unaligned.stderr +++ b/tests/ui-stable/diagnostic-not-implemented-unaligned.stderr @@ -10,10 +10,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others note: required by a bound in `takes_unaligned` --> tests/ui-stable/diagnostic-not-implemented-unaligned.rs:21:23 diff --git a/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr b/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr index ffad1b5041..c287a19c26 100644 --- a/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-nightly/derive_transparent.stderr @@ -126,10 +126,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others note: required for `TransparentStruct` to implement `zerocopy::Unaligned` --> tests/ui-nightly/derive_transparent.rs:24:32 diff --git a/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr b/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr index 5ced90a5e9..41d63e096d 100644 --- a/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-nightly/late_compile_pass.stderr @@ -186,10 +186,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -210,10 +210,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -234,10 +234,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-nightly/struct.stderr b/zerocopy-derive/tests/ui-nightly/struct.stderr index 010e8d6d38..43e643bf06 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.stderr +++ b/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -284,10 +284,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -386,10 +386,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others note: required for `IntoBytes11` to implement `zerocopy::IntoBytes` --> tests/ui-nightly/struct.rs:150:10 diff --git a/zerocopy-derive/tests/ui-stable/derive_transparent.stderr b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr index b122ce48f9..762c65fde7 100644 --- a/zerocopy-derive/tests/ui-stable/derive_transparent.stderr +++ b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr @@ -126,10 +126,10 @@ error[E0277]: the trait bound `NotZerocopy: zerocopy::Unaligned` is not satisfie AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others note: required for `TransparentStruct` to implement `zerocopy::Unaligned` --> tests/ui-stable/derive_transparent.rs:24:32 diff --git a/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr b/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr index 4fed0f6a42..8552a73ea6 100644 --- a/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr +++ b/zerocopy-derive/tests/ui-stable/late_compile_pass.stderr @@ -158,10 +158,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -178,10 +178,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -198,10 +198,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/struct.stderr b/zerocopy-derive/tests/ui-stable/struct.stderr index ea0e40aa15..5c5a680945 100644 --- a/zerocopy-derive/tests/ui-stable/struct.stderr +++ b/zerocopy-derive/tests/ui-stable/struct.stderr @@ -257,10 +257,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) @@ -347,10 +347,10 @@ error[E0277]: the trait bound `AU16: zerocopy::Unaligned` is not satisfied AtomicBool AtomicI8 AtomicU8 + Cell F32 F64 I128 - I16 and $N others note: required for `IntoBytes11` to implement `zerocopy::IntoBytes` --> tests/ui-stable/struct.rs:150:10