Skip to content

Commit 7288795

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

File tree

1 file changed

+87
-35
lines changed

1 file changed

+87
-35
lines changed

src/lib.rs

Lines changed: 87 additions & 35 deletions
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:
@@ -2507,6 +2540,7 @@ safety_comment! {
25072540
/// that the `#[repr(transparent)]` attribute is "considered part of the
25082541
/// public ABI".
25092542
///
2543+
/// - `NoCell`: TODO
25102544
/// - `TryFromBytes`: The safety requirements for `unsafe_impl!` with an
25112545
/// `is_bit_valid` closure:
25122546
/// - Given `t: *mut Wrapping<T>` and `let r = *mut T`, `r` refers to an
@@ -2542,6 +2576,7 @@ safety_comment! {
25422576
/// Reference this documentation once it's available on stable.
25432577
///
25442578
/// [2] https://doc.rust-lang.org/nomicon/other-reprs.html#reprtransparent
2579+
unsafe_impl!(T: NoCell => NoCell for Wrapping<T>);
25452580
unsafe_impl!(T: TryFromBytes => TryFromBytes for Wrapping<T>; |candidate: Ptr<T>| {
25462581
// SAFETY:
25472582
// - Since `T` and `Wrapping<T>` have the same layout and bit validity
@@ -2565,6 +2600,7 @@ safety_comment! {
25652600
// since it may contain uninitialized bytes.
25662601
//
25672602
/// SAFETY:
2603+
/// - `NoCell`: TODO
25682604
/// - `TryFromBytes` (with no validator), `FromZeroes`, `FromBytes`:
25692605
/// `MaybeUninit<T>` has no restrictions on its contents. Unfortunately,
25702606
/// in addition to bit validity, `TryFromBytes`, `FromZeroes` and
@@ -2581,6 +2617,7 @@ safety_comment! {
25812617
/// `FromBytes` and `RefFromBytes`, or if we introduce a separate
25822618
/// `NoCell`/`Freeze` trait, we can relax the trait bounds for `FromZeroes`
25832619
/// and `FromBytes`.
2620+
unsafe_impl!(T: NoCell => NoCell for MaybeUninit<T>);
25842621
unsafe_impl!(T: TryFromBytes => TryFromBytes for MaybeUninit<T>);
25852622
unsafe_impl!(T: FromZeroes => FromZeroes for MaybeUninit<T>);
25862623
unsafe_impl!(T: FromBytes => FromBytes for MaybeUninit<T>);
@@ -2593,6 +2630,7 @@ safety_comment! {
25932630
/// accessing the inner value is safe (meaning that it's unsound to leave
25942631
/// the inner value uninitialized while exposing the `ManuallyDrop` to safe
25952632
/// code).
2633+
/// - `NoCell`: TODO
25962634
/// - `FromZeroes`, `FromBytes`: Since it has the same layout as `T`, any
25972635
/// valid `T` is a valid `ManuallyDrop<T>`. If `T: FromZeroes`, a sequence
25982636
/// of zero bytes is a valid `T`, and thus a valid `ManuallyDrop<T>`. If
@@ -2616,6 +2654,7 @@ safety_comment! {
26162654
/// - Once [1] (added in
26172655
/// https://github.com/rust-lang/rust/pull/115522) is available on stable,
26182656
/// quote the stable docs instead of the nightly docs.
2657+
unsafe_impl!(T: ?Sized + NoCell => NoCell for ManuallyDrop<T>);
26192658
unsafe_impl!(T: ?Sized + FromZeroes => FromZeroes for ManuallyDrop<T>);
26202659
unsafe_impl!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop<T>);
26212660
unsafe_impl!(T: ?Sized + AsBytes => AsBytes for ManuallyDrop<T>);
@@ -2637,26 +2676,29 @@ safety_comment! {
26372676
///
26382677
/// In other words, the layout of a `[T]` or `[T; N]` is a sequence of `T`s
26392678
/// laid out back-to-back with no bytes in between. Therefore, `[T]` or `[T;
2640-
/// N]` are `FromZeroes`, `FromBytes`, and `AsBytes` if `T` is
2679+
/// N]` are `NoCell`, `FromZeroes`, `FromBytes`, and `AsBytes` if `T` is
26412680
/// (respectively). Furthermore, since an array/slice has "the same
26422681
/// alignment of `T`", `[T]` and `[T; N]` are `Unaligned` if `T` is.
26432682
///
26442683
/// Note that we don't `assert_unaligned!` for slice types because
26452684
/// `assert_unaligned!` uses `align_of`, which only works for `Sized` types.
26462685
///
26472686
/// [1] https://doc.rust-lang.org/reference/type-layout.html#array-layout
2687+
unsafe_impl!(const N: usize, T: NoCell => NoCell for [T; N]);
26482688
unsafe_impl!(const N: usize, T: FromZeroes => FromZeroes for [T; N]);
26492689
unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
26502690
unsafe_impl!(const N: usize, T: AsBytes => AsBytes for [T; N]);
26512691
unsafe_impl!(const N: usize, T: Unaligned => Unaligned for [T; N]);
26522692
assert_unaligned!([(); 0], [(); 1], [u8; 0], [u8; 1]);
2693+
unsafe_impl!(T: NoCell => NoCell for [T]);
26532694
unsafe_impl!(T: FromZeroes => FromZeroes for [T]);
26542695
unsafe_impl!(T: FromBytes => FromBytes for [T]);
26552696
unsafe_impl!(T: AsBytes => AsBytes for [T]);
26562697
unsafe_impl!(T: Unaligned => Unaligned for [T]);
26572698
}
26582699
safety_comment! {
26592700
/// SAFETY:
2701+
/// - `NoCell`: TODO
26602702
/// - `FromZeroes`: For thin pointers (note that `T: Sized`), the zero
26612703
/// pointer is considered "null". [1] No operations which require
26622704
/// provenance are legal on null pointers, so this is not a footgun.
@@ -2668,9 +2710,17 @@ safety_comment! {
26682710
///
26692711
/// [1] TODO(https://github.com/rust-lang/rust/pull/116988): Cite the
26702712
/// documentation once this PR lands.
2713+
unsafe_impl!(T => NoCell for *const T);
2714+
unsafe_impl!(T => NoCell for *mut T);
26712715
unsafe_impl!(T => FromZeroes for *const T);
26722716
unsafe_impl!(T => FromZeroes for *mut T);
26732717
}
2718+
safety_comment! {
2719+
/// SAFETY:
2720+
/// TODO
2721+
unsafe_impl!(T: ?Sized => NoCell for &'_ T);
2722+
unsafe_impl!(T: ?Sized => NoCell for &'_ mut T);
2723+
}
26742724

26752725
// SIMD support
26762726
//
@@ -2721,6 +2771,7 @@ safety_comment! {
27212771
// also `TryFromBytes`, `FromZeroes`, `FromBytes`, or `AsBytes` respectively.
27222772
// - Since no upper bound is placed on the alignment, no SIMD type can be
27232773
// guaranteed to be `Unaligned`.
2774+
// - `NoCell`: TODO
27242775
//
27252776
// Also per [1]:
27262777
//
@@ -2761,7 +2812,7 @@ mod simd {
27612812
safety_comment! {
27622813
/// SAFETY:
27632814
/// See comment on module definition for justification.
2764-
$( unsafe_impl!($typ: TryFromBytes, FromZeroes, FromBytes, AsBytes); )*
2815+
$( unsafe_impl!($typ: NoCell, TryFromBytes, FromZeroes, FromBytes, AsBytes); )*
27652816
}
27662817
}
27672818
};
@@ -5344,6 +5395,7 @@ mod tests {
53445395

53455396
#[test]
53465397
fn test_object_safety() {
5398+
fn _takes_no_cell(_: &dyn NoCell) {}
53475399
fn _takes_from_zeroes(_: &dyn FromZeroes) {}
53485400
fn _takes_from_bytes(_: &dyn FromBytes) {}
53495401
fn _takes_unaligned(_: &dyn Unaligned) {}

0 commit comments

Comments
 (0)