Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[derive] Fix AsBytes for #[repr(C, packed(N))] #672

Merged
merged 2 commits into from Dec 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 11 additions & 7 deletions zerocopy-derive/src/repr.rs
Expand Up @@ -106,23 +106,24 @@ pub trait KindRepr: 'static + Sized + Ord {
// etc), and provide implementations of `KindRepr`, `Ord`, and `Display`, and
// those traits' super-traits.
macro_rules! define_kind_specific_repr {
($type_name:expr, $repr_name:ident, $($repr_variant:ident),*) => {
($type_name:expr, $repr_name:ident, [ $($repr_variant:ident),* ] , [ $($repr_variant_aligned:ident),* ]) => {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum $repr_name {
$($repr_variant,)*
Align(u64),
$($repr_variant_aligned(u64),)*
}

impl KindRepr for $repr_name {
fn is_align(&self) -> bool {
match self {
$repr_name::Align(_) => true,
$($repr_name::$repr_variant_aligned(_) => true,)*
_ => false,
}
}

fn is_align_gt_one(&self) -> bool {
match self {
// `packed(n)` only lowers alignment
$repr_name::Align(n) => n > &1,
_ => false,
}
Expand All @@ -131,7 +132,7 @@ macro_rules! define_kind_specific_repr {
fn parse(meta: &Meta) -> syn::Result<$repr_name> {
match Repr::from_meta(meta)? {
$(Repr::$repr_variant => Ok($repr_name::$repr_variant),)*
Repr::Align(u) => Ok($repr_name::Align(u)),
$(Repr::$repr_variant_aligned(u) => Ok($repr_name::$repr_variant_aligned(u)),)*
_ => Err(Error::new_spanned(meta, concat!("unsupported representation for deriving FromBytes, AsBytes, or Unaligned on ", $type_name)))
}
}
Expand All @@ -155,16 +156,19 @@ macro_rules! define_kind_specific_repr {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
$($repr_name::$repr_variant => Repr::$repr_variant,)*
$repr_name::Align(u) => Repr::Align(*u),
$($repr_name::$repr_variant_aligned(u) => Repr::$repr_variant_aligned(*u),)*
}.fmt(f)
}
}
}
}

define_kind_specific_repr!("a struct", StructRepr, C, Transparent, Packed);
define_kind_specific_repr!("a struct", StructRepr, [C, Transparent, Packed], [Align, PackedN]);
define_kind_specific_repr!(
"an enum", EnumRepr, C, U8, U16, U32, U64, Usize, I8, I16, I32, I64, Isize
"an enum",
EnumRepr,
[C, U8, U16, U32, U64, Usize, I8, I16, I32, I64, Isize],
[Align]
);

// All representations known to Rust.
Expand Down
12 changes: 12 additions & 0 deletions zerocopy-derive/tests/struct_as_bytes.rs
Expand Up @@ -79,6 +79,18 @@ struct CPacked {

assert_impl_all!(CPacked: AsBytes);

#[derive(AsBytes)]
#[repr(C, packed(2))]
// The same caveats as for CPacked apply - we're assuming u64 is at least
// 4-byte aligned by default. Without packed(2), this should fail, as there
// would be padding between a/b assuming u64 is 4+ byte aligned.
struct CPacked2 {
a: u16,
b: u64,
}

assert_impl_all!(CPacked2: AsBytes);

#[derive(AsBytes)]
#[repr(C, packed)]
struct CPackedGeneric<T, U: ?Sized> {
Expand Down
35 changes: 23 additions & 12 deletions zerocopy-derive/tests/ui-msrv/struct.stderr
Expand Up @@ -7,39 +7,39 @@ error: unsupported on generic structs that are not repr(transparent) or repr(pac
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-msrv/struct.rs:71:11
--> tests/ui-msrv/struct.rs:80:11
|
71 | #[repr(C, align(2))]
80 | #[repr(C, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-msrv/struct.rs:75:21
--> tests/ui-msrv/struct.rs:84:21
|
75 | #[repr(transparent, align(2))]
84 | #[repr(transparent, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-msrv/struct.rs:81:16
--> tests/ui-msrv/struct.rs:90:16
|
81 | #[repr(packed, align(2))]
90 | #[repr(packed, align(2))]
| ^^^^^^^^

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

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

error[E0692]: transparent struct cannot have other repr hints
--> tests/ui-msrv/struct.rs:75:8
--> tests/ui-msrv/struct.rs:84:8
|
75 | #[repr(transparent, align(2))]
84 | #[repr(transparent, align(2))]
| ^^^^^^^^^^^ ^^^^^^^^

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
Expand Down Expand Up @@ -100,3 +100,14 @@ error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is n
<HasPadding<T, VALUE> as ShouldBe<VALUE>>
= help: see issue #48214
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
--> tests/ui-msrv/struct.rs:66:10
|
66 | #[derive(AsBytes)]
| ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
|
= help: the following implementations were found:
<HasPadding<T, VALUE> as ShouldBe<VALUE>>
= help: see issue #48214
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
9 changes: 9 additions & 0 deletions zerocopy-derive/tests/ui-nightly/struct.rs
Expand Up @@ -63,6 +63,15 @@ struct AsBytes2 {
bar: AU16,
}

#[derive(AsBytes)]
#[repr(C, packed(2))]
struct AsBytes3 {
foo: u8,
// We'd prefer to use AU64 here, but you can't use aligned types in
// packed structs.
bar: u64,
}

//
// Unaligned errors
//
Expand Down
39 changes: 25 additions & 14 deletions zerocopy-derive/tests/ui-nightly/struct.stderr
Expand Up @@ -7,39 +7,39 @@ error: unsupported on generic structs that are not repr(transparent) or repr(pac
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-nightly/struct.rs:71:11
--> tests/ui-nightly/struct.rs:80:11
|
71 | #[repr(C, align(2))]
80 | #[repr(C, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-nightly/struct.rs:75:21
--> tests/ui-nightly/struct.rs:84:21
|
75 | #[repr(transparent, align(2))]
84 | #[repr(transparent, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-nightly/struct.rs:81:16
--> tests/ui-nightly/struct.rs:90:16
|
81 | #[repr(packed, align(2))]
90 | #[repr(packed, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-nightly/struct.rs:85:18
--> tests/ui-nightly/struct.rs:94:18
|
85 | #[repr(align(1), align(2))]
94 | #[repr(align(1), align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-nightly/struct.rs:89:8
--> tests/ui-nightly/struct.rs:98:8
|
89 | #[repr(align(2), align(4))]
98 | #[repr(align(2), align(4))]
| ^^^^^^^^

error[E0692]: transparent struct cannot have other repr hints
--> tests/ui-nightly/struct.rs:75:8
--> tests/ui-nightly/struct.rs:84:8
|
75 | #[repr(transparent, align(2))]
84 | #[repr(transparent, align(2))]
| ^^^^^^^^^^^ ^^^^^^^^

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
Expand Down Expand Up @@ -125,8 +125,19 @@ error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is n
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
--> tests/ui-nightly/struct.rs:66:10
|
66 | #[derive(AsBytes)]
| ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
|
= help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes3, true>`
= help: see issue #48214
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0587]: type has conflicting packed and align representation hints
--> tests/ui-nightly/struct.rs:82:1
--> tests/ui-nightly/struct.rs:91:1
|
82 | struct Unaligned3;
91 | struct Unaligned3;
| ^^^^^^^^^^^^^^^^^
34 changes: 22 additions & 12 deletions zerocopy-derive/tests/ui-stable/struct.stderr
Expand Up @@ -7,39 +7,39 @@ error: unsupported on generic structs that are not repr(transparent) or repr(pac
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-stable/struct.rs:71:11
--> tests/ui-stable/struct.rs:80:11
|
71 | #[repr(C, align(2))]
80 | #[repr(C, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-stable/struct.rs:75:21
--> tests/ui-stable/struct.rs:84:21
|
75 | #[repr(transparent, align(2))]
84 | #[repr(transparent, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-stable/struct.rs:81:16
--> tests/ui-stable/struct.rs:90:16
|
81 | #[repr(packed, align(2))]
90 | #[repr(packed, align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-stable/struct.rs:85:18
--> tests/ui-stable/struct.rs:94:18
|
85 | #[repr(align(1), align(2))]
94 | #[repr(align(1), align(2))]
| ^^^^^^^^

error: cannot derive Unaligned with repr(align(N > 1))
--> tests/ui-stable/struct.rs:89:8
--> tests/ui-stable/struct.rs:98:8
|
89 | #[repr(align(2), align(4))]
98 | #[repr(align(2), align(4))]
| ^^^^^^^^

error[E0692]: transparent struct cannot have other repr hints
--> tests/ui-stable/struct.rs:75:8
--> tests/ui-stable/struct.rs:84:8
|
75 | #[repr(transparent, align(2))]
84 | #[repr(transparent, align(2))]
| ^^^^^^^^^^^ ^^^^^^^^

error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
Expand Down Expand Up @@ -119,3 +119,13 @@ error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is n
= help: the trait `ShouldBe<VALUE>` is implemented for `HasPadding<T, VALUE>`
= help: see issue #48214
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
--> tests/ui-stable/struct.rs:66:10
|
66 | #[derive(AsBytes)]
| ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
|
= help: the trait `ShouldBe<VALUE>` is implemented for `HasPadding<T, VALUE>`
= help: see issue #48214
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)