Skip to content

Commit 04ce6e1

Browse files
committed
Initial commit of NoCell
Makes progress on #251
1 parent 9e966a2 commit 04ce6e1

File tree

1 file changed

+98
-39
lines changed

1 file changed

+98
-39
lines changed

src/lib.rs

+98-39
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,30 @@ safety_comment! {
10571057
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
10581058
pub use zerocopy_derive::FromZeroes;
10591059

1060+
/// Types which do not contain any [`UnsafeCell`]s.
1061+
///
1062+
/// WARNING: Do not implement this trait yourself! Instead, use
1063+
/// `#[derive(NoCell)]`.
1064+
///
1065+
/// # Safety
1066+
///
1067+
/// If a type implements `NoCell`, unsafe code may assume that that type does
1068+
/// not contain any [`UnsafeCell`]s and does not contain any types which contain
1069+
/// any [`UnsafeCell`]s transitively. If a type implements `NoCell` which
1070+
/// violates this assumption, it may cause [undefined behavior].
1071+
///
1072+
/// [`UnsafeCell`]: core::cell::UnsafeCell
1073+
/// [undefined behavior]: https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html
1074+
#[doc(hidden)]
1075+
pub unsafe trait NoCell {
1076+
// The `Self: Sized` bound makes it so that `NoCell` is still object
1077+
// safe.
1078+
#[doc(hidden)]
1079+
fn only_derive_is_allowed_to_implement_this_trait()
1080+
where
1081+
Self: Sized;
1082+
}
1083+
10601084
/// Types whose validity can be checked at runtime, allowing them to be
10611085
/// conditionally converted from byte slices.
10621086
///
@@ -2127,18 +2151,20 @@ safety_comment! {
21272151
/// SAFETY:
21282152
/// Per the reference [1], "the unit tuple (`()`) ... is guaranteed as a
21292153
/// zero-sized type to have a size of 0 and an alignment of 1."
2154+
/// - `NoCell`: `()` self-evidently does not contain any `UnsafeCell`s.
21302155
/// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: There
21312156
/// is only one possible sequence of 0 bytes, and `()` is inhabited.
21322157
/// - `AsBytes`: Since `()` has size 0, it contains no padding bytes.
21332158
/// - `Unaligned`: `()` has alignment 1.
21342159
///
21352160
/// [1] https://doc.rust-lang.org/reference/type-layout.html#tuple-layout
2136-
unsafe_impl!((): TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
2161+
unsafe_impl!((): NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
21372162
assert_unaligned!(());
21382163
}
21392164

21402165
safety_comment! {
21412166
/// SAFETY:
2167+
/// - `NoCell`: These types self-evidently do not contain any `UnsafeCell`s.
21422168
/// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`: all bit
21432169
/// patterns are valid for numeric types [1]
21442170
/// - `AsBytes`: numeric types have no padding bytes [1]
@@ -2171,25 +2197,26 @@ safety_comment! {
21712197
/// TODO(#278): Once we've updated the trait docs to refer to `u8`s rather
21722198
/// than bits or bytes, update this comment, especially the reference to
21732199
/// [1].
2174-
unsafe_impl!(u8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
2175-
unsafe_impl!(i8: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
2200+
unsafe_impl!(u8: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
2201+
unsafe_impl!(i8: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
21762202
assert_unaligned!(u8, i8);
2177-
unsafe_impl!(u16: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2178-
unsafe_impl!(i16: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2179-
unsafe_impl!(u32: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2180-
unsafe_impl!(i32: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2181-
unsafe_impl!(u64: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2182-
unsafe_impl!(i64: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2183-
unsafe_impl!(u128: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2184-
unsafe_impl!(i128: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2185-
unsafe_impl!(usize: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2186-
unsafe_impl!(isize: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2187-
unsafe_impl!(f32: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2188-
unsafe_impl!(f64: TryFromBytes, FromZeroes, FromBytes, AsBytes);
2203+
unsafe_impl!(u16: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2204+
unsafe_impl!(i16: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2205+
unsafe_impl!(u32: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2206+
unsafe_impl!(i32: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2207+
unsafe_impl!(u64: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2208+
unsafe_impl!(i64: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2209+
unsafe_impl!(u128: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2210+
unsafe_impl!(i128: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2211+
unsafe_impl!(usize: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2212+
unsafe_impl!(isize: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2213+
unsafe_impl!(f32: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
2214+
unsafe_impl!(f64: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes);
21892215
}
21902216

21912217
safety_comment! {
21922218
/// SAFETY:
2219+
/// - `NoCell`: `bool` self-evidently does not contain any `UnsafeCell`s.
21932220
/// - `FromZeroes`: Valid since "[t]he value false has the bit pattern
21942221
/// 0x00" [1].
21952222
/// - `AsBytes`: Since "the boolean type has a size and alignment of 1 each"
@@ -2200,7 +2227,7 @@ safety_comment! {
22002227
/// has a size and alignment of 1 each."
22012228
///
22022229
/// [1] https://doc.rust-lang.org/reference/types/boolean.html
2203-
unsafe_impl!(bool: FromZeroes, AsBytes, Unaligned);
2230+
unsafe_impl!(bool: NoCell, FromZeroes, AsBytes, Unaligned);
22042231
assert_unaligned!(bool);
22052232
/// SAFETY:
22062233
/// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
@@ -2243,6 +2270,7 @@ safety_comment! {
22432270
}
22442271
safety_comment! {
22452272
/// SAFETY:
2273+
/// - `NoCell`: `char` self-evidently does not contain any `UnsafeCell`s.
22462274
/// - `FromZeroes`: Per reference [1], "[a] value of type char is a Unicode
22472275
/// scalar value (i.e. a code point that is not a surrogate), represented
22482276
/// as a 32-bit unsigned word in the 0x0000 to 0xD7FF or 0xE000 to
@@ -2252,7 +2280,7 @@ safety_comment! {
22522280
/// all bit patterns are valid for `char`.
22532281
///
22542282
/// [1] https://doc.rust-lang.org/reference/types/textual.html
2255-
unsafe_impl!(char: FromZeroes, AsBytes);
2283+
unsafe_impl!(char: NoCell, FromZeroes, AsBytes);
22562284
/// SAFETY:
22572285
/// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
22582286
/// closure:
@@ -2289,14 +2317,18 @@ safety_comment! {
22892317
}
22902318
safety_comment! {
22912319
/// SAFETY:
2292-
/// - `FromZeroes`, `AsBytes`, `Unaligned`: Per the reference [1], `str`
2293-
/// has the same layout as `[u8]`, and `[u8]` is `FromZeroes`, `AsBytes`,
2294-
/// and `Unaligned`.
2320+
/// Per the Reference [1], `str` has the same layout as `[u8]`.
2321+
/// - `NoCell`: `[u8]` does not contain any `UnsafeCell`s.
2322+
/// - `FromZeroes`, `AsBytes`, `Unaligned`: `[u8]` is `FromZeroes`,
2323+
/// `AsBytes`, and `Unaligned`.
22952324
///
22962325
/// Note that we don't `assert_unaligned!(str)` because `assert_unaligned!`
22972326
/// uses `align_of`, which only works for `Sized` types.
22982327
///
2299-
/// TODO(#429): Add quotes from documentation.
2328+
/// TODO(#429):
2329+
/// - Add quotes from documentation.
2330+
/// - Improve safety proof for `FromZeroes` and `AsBytes`; having the same
2331+
/// layout as `[u8]` isn't sufficient.
23002332
///
23012333
/// [1] https://doc.rust-lang.org/reference/type-layout.html#str-layout
23022334
unsafe_impl!(str: FromZeroes, AsBytes, Unaligned);
@@ -2333,6 +2365,7 @@ safety_comment! {
23332365
// `NonZeroXxx` is `AsBytes`, but not `FromZeroes` or `FromBytes`.
23342366
//
23352367
/// SAFETY:
2368+
/// - `NoCell`: TODO
23362369
/// - `AsBytes`: `NonZeroXxx` has the same layout as its associated
23372370
/// primitive. Since it is the same size, this guarantees it has no
23382371
/// padding - integers have no padding, and there's no room for padding
@@ -2353,19 +2386,19 @@ safety_comment! {
23532386
/// [2] https://doc.rust-lang.org/stable/std/num/struct.NonZeroI8.html
23542387
/// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
23552388
/// that layout is the same as primitive layout.
2356-
unsafe_impl!(NonZeroU8: AsBytes, Unaligned);
2357-
unsafe_impl!(NonZeroI8: AsBytes, Unaligned);
2389+
unsafe_impl!(NonZeroU8: NoCell, AsBytes, Unaligned);
2390+
unsafe_impl!(NonZeroI8: NoCell, AsBytes, Unaligned);
23582391
assert_unaligned!(NonZeroU8, NonZeroI8);
2359-
unsafe_impl!(NonZeroU16: AsBytes);
2360-
unsafe_impl!(NonZeroI16: AsBytes);
2361-
unsafe_impl!(NonZeroU32: AsBytes);
2362-
unsafe_impl!(NonZeroI32: AsBytes);
2363-
unsafe_impl!(NonZeroU64: AsBytes);
2364-
unsafe_impl!(NonZeroI64: AsBytes);
2365-
unsafe_impl!(NonZeroU128: AsBytes);
2366-
unsafe_impl!(NonZeroI128: AsBytes);
2367-
unsafe_impl!(NonZeroUsize: AsBytes);
2368-
unsafe_impl!(NonZeroIsize: AsBytes);
2392+
unsafe_impl!(NonZeroU16: NoCell, AsBytes);
2393+
unsafe_impl!(NonZeroI16: NoCell, AsBytes);
2394+
unsafe_impl!(NonZeroU32: NoCell, AsBytes);
2395+
unsafe_impl!(NonZeroI32: NoCell, AsBytes);
2396+
unsafe_impl!(NonZeroU64: NoCell, AsBytes);
2397+
unsafe_impl!(NonZeroI64: NoCell, AsBytes);
2398+
unsafe_impl!(NonZeroU128: NoCell, AsBytes);
2399+
unsafe_impl!(NonZeroI128: NoCell, AsBytes);
2400+
unsafe_impl!(NonZeroUsize: NoCell, AsBytes);
2401+
unsafe_impl!(NonZeroIsize: NoCell, AsBytes);
23692402
/// SAFETY:
23702403
/// - The safety requirements for `unsafe_impl!` with an `is_bit_valid`
23712404
/// closure:
@@ -2424,6 +2457,9 @@ safety_comment! {
24242457
///
24252458
/// TODO(https://github.com/rust-lang/rust/pull/104082): Cite documentation
24262459
/// for layout guarantees.
2460+
///
2461+
/// TODO(#251): Implement `NoCell` (possibly by implementing it for
2462+
/// `Option<T>` where `T: NoCell`).
24272463
unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
24282464
unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeroes, FromBytes, AsBytes, Unaligned);
24292465
assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);
@@ -2507,6 +2543,8 @@ safety_comment! {
25072543
/// that the `#[repr(transparent)]` attribute is "considered part of the
25082544
/// public ABI".
25092545
///
2546+
/// - `NoCell`: `Wrapping<T>` has `UnsafeCell`s exactly when `T` does, so
2547+
/// `T: NoCell` guarantees that `Wrapping<T>` has no `UnsafeCell`s.
25102548
/// - `TryFromBytes`: The safety requirements for `unsafe_impl!` with an
25112549
/// `is_bit_valid` closure:
25122550
/// - Given `t: *mut Wrapping<T>` and `let r = *mut T`, `r` refers to an
@@ -2542,6 +2580,7 @@ safety_comment! {
25422580
/// Reference this documentation once it's available on stable.
25432581
///
25442582
/// [2] https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
2583+
unsafe_impl!(T: NoCell => NoCell for Wrapping<T>);
25452584
unsafe_impl!(T: TryFromBytes => TryFromBytes for Wrapping<T>; |candidate: Ptr<T>| {
25462585
// SAFETY:
25472586
// - Since `T` and `Wrapping<T>` have the same layout and bit validity
@@ -2565,6 +2604,8 @@ safety_comment! {
25652604
// since it may contain uninitialized bytes.
25662605
//
25672606
/// SAFETY:
2607+
/// - `NoCell`: `MaybeUninit<T>` has `UnsafeCell`s exactly when `T` does, so
2608+
/// `T: NoCell` guarantees that `MaybeUninit<T>` has no `UnsafeCell`s.
25682609
/// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`:
25692610
/// `MaybeUninit<T>` has no restrictions on its contents. Unfortunately,
25702611
/// in addition to bit validity, `TryFromBytes`, `FromZeroes` and
@@ -2581,6 +2622,7 @@ safety_comment! {
25812622
/// `FromBytes` and `RefFromBytes`, or if we introduce a separate
25822623
/// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes`
25832624
/// and `FromBytes`.
2625+
unsafe_impl!(T: NoCell => NoCell for MaybeUninit<T>);
25842626
unsafe_impl!(T: TryFromBytes => TryFromBytes for MaybeUninit<T>);
25852627
unsafe_impl!(T: FromZeroes => FromZeroes for MaybeUninit<T>);
25862628
unsafe_impl!(T: FromBytes => FromBytes for MaybeUninit<T>);
@@ -2593,6 +2635,8 @@ safety_comment! {
25932635
/// accessing the inner value is safe (meaning that it's unsound to leave
25942636
/// the inner value uninitialized while exposing the `ManuallyDrop` to safe
25952637
/// code).
2638+
/// - `NoCell`: `ManuallyDrop<T>` has `UnsafeCell`s exactly when `T` does,
2639+
/// so `T: NoCell` guarantees that `ManuallyDrop<T>` has no `UnsafeCell`s.
25962640
/// - `FromZeroes`, `FromBytes`: Since it has the same layout as `T`, any
25972641
/// valid `T` is a valid `ManuallyDrop<T>`. If `T: FromZeroes`, a sequence
25982642
/// of zero bytes is a valid `T`, and thus a valid `ManuallyDrop<T>`. If
@@ -2616,6 +2660,7 @@ safety_comment! {
26162660
/// - Once [1] (added in
26172661
/// https://github.com/rust-lang/rust/pull/115522) is available on stable,
26182662
/// quote the stable docs instead of the nightly docs.
2663+
unsafe_impl!(T: ?Sized + NoCell => NoCell for ManuallyDrop<T>);
26192664
unsafe_impl!(T: ?Sized + FromZeroes => FromZeroes for ManuallyDrop<T>);
26202665
unsafe_impl!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>);
26212666
unsafe_impl!(T: ?Sized + AsBytes => AsBytes for ManuallyDrop<T>);
@@ -2635,28 +2680,32 @@ safety_comment! {
26352680
///
26362681
/// Slices have the same layout as the section of the array they slice.
26372682
///
2638-
/// In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s
2639-
/// laid out back-to-back with no bytes in between. Therefore, `[T]` or `[T;
2640-
/// N]` are `FromZeroes`, `FromBytes`, and `AsBytes` if `T` is
2641-
/// (respectively). Furthermore, since an array/slice has "the same
2642-
/// alignment of `T`", `[T]` and `[T; N]` are `Unaligned` if `T` is.
2683+
/// In other words, the layout and bit validity of a `[T]` or `[T; N]` is
2684+
/// that of a sequence of `T`s laid out back-to-back with no bytes in
2685+
/// between. Therefore, `[T]` or `[T; N]` are `NoCell`, `FromZeroes`,
2686+
/// `FromBytes`, and `AsBytes` if `T` is (respectively). Furthermore, since
2687+
/// an array/slice has "the same alignment of `T`", `[T]` and `[T; N]` are
2688+
/// `Unaligned` if `T` is.
26432689
///
26442690
/// Note that we don't `assert_unaligned!` for slice types because
26452691
/// `assert_unaligned!` uses `align_of`, which only works for `Sized` types.
26462692
///
26472693
/// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout
2694+
unsafe_impl!(const N: usize, T: NoCell => NoCell for [T; N]);
26482695
unsafe_impl!(const N: usize, T: FromZeroes => FromZeroes for [T; N]);
26492696
unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
26502697
unsafe_impl!(const N: usize, T: AsBytes => AsBytes for [T; N]);
26512698
unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]);
26522699
assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
2700+
unsafe_impl!(T: NoCell => NoCell for [T]);
26532701
unsafe_impl!(T: FromZeroes => FromZeroes for [T]);
26542702
unsafe_impl!(T: FromBytes => FromBytes for [T]);
26552703
unsafe_impl!(T: AsBytes => AsBytes for [T]);
26562704
unsafe_impl!(T: Unaligned => Unaligned for [T]);
26572705
}
26582706
safety_comment! {
26592707
/// SAFETY:
2708+
/// - `NoCell`: Raw pointers do not contain any `UnsafeCell`s.
26602709
/// - `FromZeroes`: For thin pointers (note that `T: Sized`), the zero
26612710
/// pointer is considered "null". [1] No operations which require
26622711
/// provenance are legal on null pointers, so this is not a footgun.
@@ -2668,9 +2717,17 @@ safety_comment! {
26682717
///
26692718
/// [1] TODO(https://github.com/rust-lang/rust/pull/116988): Cite the
26702719
/// documentation once this PR lands.
2720+
unsafe_impl!(T => NoCell for *const T);
2721+
unsafe_impl!(T => NoCell for *mut T);
26712722
unsafe_impl!(T => FromZeroes for *const T);
26722723
unsafe_impl!(T => FromZeroes for *mut T);
26732724
}
2725+
safety_comment! {
2726+
/// SAFETY:
2727+
/// Reference types do not contain any `UnsafeCell`s.
2728+
unsafe_impl!(T: ?Sized => NoCell for &'_ T);
2729+
unsafe_impl!(T: ?Sized => NoCell for &'_ mut T);
2730+
}
26742731

26752732
// SIMD support
26762733
//
@@ -2721,6 +2778,7 @@ safety_comment! {
27212778
// also `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` respectively.
27222779
// - Since no upper bound is placed on the alignment, no SIMD type can be
27232780
// guaranteed to be `Unaligned`.
2781+
// - `NoCell`: TODO
27242782
//
27252783
// Also per [1]:
27262784
//
@@ -2761,7 +2819,7 @@ mod simd {
27612819
safety_comment! {
27622820
/// SAFETY:
27632821
/// See comment on module definition for justification.
2764-
$( unsafe_impl!($typ: TryFromBytes, FromZeroes, FromBytes, AsBytes); )*
2822+
$( unsafe_impl!($typ: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes); )*
27652823
}
27662824
}
27672825
};
@@ -5344,6 +5402,7 @@ mod tests {
53445402

53455403
#[test]
53465404
fn test_object_safety() {
5405+
fn _takes_no_cell(_: &dyn NoCell) {}
53475406
fn _takes_from_zeroes(_: &dyn FromZeroes) {}
53485407
fn _takes_from_bytes(_: &dyn FromBytes) {}
53495408
fn _takes_unaligned(_: &dyn Unaligned) {}

0 commit comments

Comments
 (0)