Skip to content

Commit

Permalink
[derive] Support deriving NoCell
Browse files Browse the repository at this point in the history
Makes progress on #251
  • Loading branch information
joshlf committed Dec 2, 2023
1 parent 5d49262 commit b27e74d
Show file tree
Hide file tree
Showing 18 changed files with 475 additions and 269 deletions.
6 changes: 4 additions & 2 deletions src/byteorder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ example of how it can be used for parsing UDP packets.
[`AsBytes`]: crate::AsBytes
[`Unaligned`]: crate::Unaligned"),
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
#[cfg_attr(any(feature = "derive", test), derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned))]
#[cfg_attr(any(feature = "derive", test), derive(KnownLayout, NoCell, FromZeroes, FromBytes, AsBytes, Unaligned))]
#[repr(transparent)]
pub struct $name<O>([u8; $bytes], PhantomData<O>);
}
Expand All @@ -288,7 +288,9 @@ example of how it can be used for parsing UDP packets.
/// SAFETY:
/// `$name<O>` is `repr(transparent)`, and so it has the same layout
/// as its only non-zero field, which is a `u8` array. `u8` arrays
/// are `FromZeroes`, `FromBytes`, `AsBytes`, and `Unaligned`.
/// are `NoCell`, `FromZeroes`, `FromBytes`, `AsBytes`, and
/// `Unaligned`.
impl_or_verify!(O => NoCell for $name<O>);
impl_or_verify!(O => FromZeroes for $name<O>);
impl_or_verify!(O => FromBytes for $name<O>);
impl_or_verify!(O => AsBytes for $name<O>);
Expand Down
10 changes: 9 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,14 @@ pub use zerocopy_derive::Unaligned;
#[doc(hidden)]
pub use zerocopy_derive::KnownLayout;

// `pub use` separately here so that we can mark it `#[doc(hidden)]`.
//
// TODO(#251): Remove this or add a doc comment.
#[cfg(any(feature = "derive", test))]
#[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))]
#[doc(hidden)]
pub use zerocopy_derive::NoCell;

use core::{
cell::{self, RefMut},
cmp::Ordering,
Expand Down Expand Up @@ -7921,7 +7929,7 @@ mod tests {
assert_impls!(Wrapping<NotZerocopy>: KnownLayout, !NoCell, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
assert_impls!(Wrapping<UnsafeCell<()>>: KnownLayout, !NoCell, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);

assert_impls!(Unalign<u8>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned, !NoCell, !TryFromBytes);
assert_impls!(Unalign<u8>: KnownLayout, NoCell, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes);
assert_impls!(Unalign<NotZerocopy>: Unaligned, !NoCell, !KnownLayout, !TryFromBytes, !FromZeroes, !FromBytes, !AsBytes);

assert_impls!([u8]: KnownLayout, NoCell, FromZeroes, FromBytes, AsBytes, Unaligned, !TryFromBytes);
Expand Down
3 changes: 2 additions & 1 deletion src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,7 @@ pub(crate) mod testutil {
// By contrast, `AU64` is guaranteed to have alignment 8.
#[derive(
KnownLayout,
NoCell,
FromZeroes,
FromBytes,
AsBytes,
Expand Down Expand Up @@ -645,7 +646,7 @@ pub(crate) mod testutil {
}

#[derive(
FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
NoCell, FromZeroes, FromBytes, Eq, PartialEq, Ord, PartialOrd, Default, Debug, Copy, Clone,
)]
#[repr(C)]
pub(crate) struct Nested<T, U: ?Sized> {
Expand Down
5 changes: 4 additions & 1 deletion src/wrappers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ use super::*;
#[derive(Default, Copy)]
#[cfg_attr(
any(feature = "derive", test),
derive(KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned)
derive(NoCell, KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned)
)]
#[repr(C, packed)]
pub struct Unalign<T>(T);
Expand All @@ -74,7 +74,10 @@ safety_comment! {
/// alignment of `T`, and so we don't require that `T: Unaligned`
/// - `Unalign<T>` has the same bit validity as `T`, and so it is
/// `FromZeroes`, `FromBytes`, or `AsBytes` exactly when `T` is as well.
/// - `NoCell`: `Unalign<T>` has the same fields as `T`, so it contains
/// `UnsafeCell`s exactly when `T` does.
impl_or_verify!(T => Unaligned for Unalign<T>);
impl_or_verify!(T: NoCell => NoCell for Unalign<T>);
impl_or_verify!(T: FromZeroes => FromZeroes for Unalign<T>);
impl_or_verify!(T: FromBytes => FromBytes for Unalign<T>);
impl_or_verify!(T: AsBytes => AsBytes for Unalign<T>);
Expand Down
18 changes: 18 additions & 0 deletions zerocopy-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,23 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
.into()
}

#[proc_macro_derive(NoCell)]
pub fn derive_no_cell(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse_macro_input!(ts as DeriveInput);
match &ast.data {
Data::Struct(strct) => {
impl_block(&ast, strct, Trait::NoCell, RequireBoundedFields::Yes, false, None, None)
}
Data::Enum(enm) => {
impl_block(&ast, enm, Trait::NoCell, RequireBoundedFields::Yes, false, None, None)
}
Data::Union(unn) => {
impl_block(&ast, unn, Trait::NoCell, RequireBoundedFields::Yes, false, None, None)
}
}
.into()
}

#[proc_macro_derive(FromZeroes)]
pub fn derive_from_zeroes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse_macro_input!(ts as DeriveInput);
Expand Down Expand Up @@ -637,6 +654,7 @@ impl PaddingCheck {
#[derive(Debug, Eq, PartialEq)]
enum Trait {
KnownLayout,
NoCell,
FromZeroes,
FromBytes,
AsBytes,
Expand Down
125 changes: 67 additions & 58 deletions zerocopy-derive/tests/ui-msrv/enum.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -31,149 +31,149 @@ error: must have a non-align #[repr(...)] attribute in order to guarantee this t
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error: only C-like enums can implement FromZeroes
--> tests/ui-msrv/enum.rs:52:1
--> tests/ui-msrv/enum.rs:61:1
|
52 | / enum FromZeroes1 {
53 | | A(u8),
54 | | }
61 | / enum FromZeroes1 {
62 | | A(u8),
63 | | }
| |_^

error: only C-like enums can implement FromZeroes
--> tests/ui-msrv/enum.rs:57:1
--> tests/ui-msrv/enum.rs:66:1
|
57 | / enum FromZeroes2 {
58 | | A,
59 | | B(u8),
60 | | }
66 | / enum FromZeroes2 {
67 | | A,
68 | | B(u8),
69 | | }
| |_^

error: FromZeroes only supported on enums with a variant that has a discriminant of `0`
--> tests/ui-msrv/enum.rs:63:1
--> tests/ui-msrv/enum.rs:72:1
|
63 | / enum FromZeroes3 {
64 | | A = 1,
65 | | B,
66 | | }
72 | / enum FromZeroes3 {
73 | | A = 1,
74 | | B,
75 | | }
| |_^

error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
--> tests/ui-msrv/enum.rs:73:8
--> tests/ui-msrv/enum.rs:82:8
|
73 | #[repr(C)]
82 | #[repr(C)]
| ^

error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
--> tests/ui-msrv/enum.rs:79:8
--> tests/ui-msrv/enum.rs:88:8
|
79 | #[repr(usize)]
88 | #[repr(usize)]
| ^^^^^

error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
--> tests/ui-msrv/enum.rs:85:8
--> tests/ui-msrv/enum.rs:94:8
|
85 | #[repr(isize)]
94 | #[repr(isize)]
| ^^^^^

error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
--> tests/ui-msrv/enum.rs:91:8
|
91 | #[repr(u32)]
| ^^^
--> tests/ui-msrv/enum.rs:100:8
|
100 | #[repr(u32)]
| ^^^

error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
--> tests/ui-msrv/enum.rs:97:8
|
97 | #[repr(i32)]
| ^^^
--> tests/ui-msrv/enum.rs:106:8
|
106 | #[repr(i32)]
| ^^^

error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
--> tests/ui-msrv/enum.rs:103:8
--> tests/ui-msrv/enum.rs:112:8
|
103 | #[repr(u64)]
112 | #[repr(u64)]
| ^^^

error: FromBytes requires repr of "u8", "u16", "i8", or "i16"
--> tests/ui-msrv/enum.rs:109:8
--> tests/ui-msrv/enum.rs:118:8
|
109 | #[repr(i64)]
118 | #[repr(i64)]
| ^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:119:8
--> tests/ui-msrv/enum.rs:128:8
|
119 | #[repr(C)]
128 | #[repr(C)]
| ^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:125:8
--> tests/ui-msrv/enum.rs:134:8
|
125 | #[repr(u16)]
134 | #[repr(u16)]
| ^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:131:8
--> tests/ui-msrv/enum.rs:140:8
|
131 | #[repr(i16)]
140 | #[repr(i16)]
| ^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:137:8
--> tests/ui-msrv/enum.rs:146:8
|
137 | #[repr(u32)]
146 | #[repr(u32)]
| ^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:143:8
--> tests/ui-msrv/enum.rs:152:8
|
143 | #[repr(i32)]
152 | #[repr(i32)]
| ^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:149:8
--> tests/ui-msrv/enum.rs:158:8
|
149 | #[repr(u64)]
158 | #[repr(u64)]
| ^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:155:8
--> tests/ui-msrv/enum.rs:164:8
|
155 | #[repr(i64)]
164 | #[repr(i64)]
| ^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:161:8
--> tests/ui-msrv/enum.rs:170:8
|
161 | #[repr(usize)]
170 | #[repr(usize)]
| ^^^^^

error: Unaligned requires repr of "u8" or "i8", and no alignment (i.e., repr(align(N > 1)))
--> tests/ui-msrv/enum.rs:167:8
--> tests/ui-msrv/enum.rs:176:8
|
167 | #[repr(isize)]
176 | #[repr(isize)]
| ^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-msrv/enum.rs:173:12
--> tests/ui-msrv/enum.rs:182:12
|
173 | #[repr(u8, align(2))]
182 | #[repr(u8, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-msrv/enum.rs:179:12
--> tests/ui-msrv/enum.rs:188:12
|
179 | #[repr(i8, align(2))]
188 | #[repr(i8, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-msrv/enum.rs:185:18
--> tests/ui-msrv/enum.rs:194:18
|
185 | #[repr(align(1), align(2))]
194 | #[repr(align(1), align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-msrv/enum.rs:191:8
--> tests/ui-msrv/enum.rs:200:8
|
191 | #[repr(align(2), align(4))]
200 | #[repr(align(2), align(4))]
| ^^^^^^^^

error[E0565]: meta item in `repr` must be an identifier
Expand All @@ -197,3 +197,12 @@ error[E0566]: conflicting representation hints
= note: `#[deny(conflicting_repr_hints)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #68585 <https://github.com/rust-lang/rust/issues/68585>

error[E0277]: the trait bound `UnsafeCell<()>: NoCell` is not satisfied
--> tests/ui-msrv/enum.rs:51:10
|
51 | #[derive(NoCell)]
| ^^^^^^ the trait `NoCell` is not implemented for `UnsafeCell<()>`
|
= help: see issue #48214
= note: this error originates in the derive macro `NoCell` (in Nightly builds, run with -Z macro-backtrace for more info)
Loading

0 comments on commit b27e74d

Please sign in to comment.