Skip to content

Commit 941c83f

Browse files
maurerjoshlf
andauthored
[derive] Fix AsBytes for #[repr(C, packed(N))] (#672)
`packed(N)` does not gaurantee no padding, but it doesn't prevent it either. This was previously supported. Co-authored-by: Joshua Liebow-Feeser <[email protected]>
1 parent d18d233 commit 941c83f

File tree

6 files changed

+102
-45
lines changed

6 files changed

+102
-45
lines changed

zerocopy-derive/src/repr.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -106,23 +106,24 @@ pub trait KindRepr: 'static + Sized + Ord {
106106
// etc), and provide implementations of `KindRepr`, `Ord`, and `Display`, and
107107
// those traits' super-traits.
108108
macro_rules! define_kind_specific_repr {
109-
($type_name:expr, $repr_name:ident, $($repr_variant:ident),*) => {
109+
($type_name:expr, $repr_name:ident, [ $($repr_variant:ident),* ] , [ $($repr_variant_aligned:ident),* ]) => {
110110
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
111111
pub enum $repr_name {
112112
$($repr_variant,)*
113-
Align(u64),
113+
$($repr_variant_aligned(u64),)*
114114
}
115115

116116
impl KindRepr for $repr_name {
117117
fn is_align(&self) -> bool {
118118
match self {
119-
$repr_name::Align(_) => true,
119+
$($repr_name::$repr_variant_aligned(_) => true,)*
120120
_ => false,
121121
}
122122
}
123123

124124
fn is_align_gt_one(&self) -> bool {
125125
match self {
126+
// `packed(n)` only lowers alignment
126127
$repr_name::Align(n) => n > &1,
127128
_ => false,
128129
}
@@ -131,7 +132,7 @@ macro_rules! define_kind_specific_repr {
131132
fn parse(meta: &Meta) -> syn::Result<$repr_name> {
132133
match Repr::from_meta(meta)? {
133134
$(Repr::$repr_variant => Ok($repr_name::$repr_variant),)*
134-
Repr::Align(u) => Ok($repr_name::Align(u)),
135+
$(Repr::$repr_variant_aligned(u) => Ok($repr_name::$repr_variant_aligned(u)),)*
135136
_ => Err(Error::new_spanned(meta, concat!("unsupported representation for deriving FromBytes, AsBytes, or Unaligned on ", $type_name)))
136137
}
137138
}
@@ -155,16 +156,19 @@ macro_rules! define_kind_specific_repr {
155156
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
156157
match self {
157158
$($repr_name::$repr_variant => Repr::$repr_variant,)*
158-
$repr_name::Align(u) => Repr::Align(*u),
159+
$($repr_name::$repr_variant_aligned(u) => Repr::$repr_variant_aligned(*u),)*
159160
}.fmt(f)
160161
}
161162
}
162163
}
163164
}
164165

165-
define_kind_specific_repr!("a struct", StructRepr, C, Transparent, Packed);
166+
define_kind_specific_repr!("a struct", StructRepr, [C, Transparent, Packed], [Align, PackedN]);
166167
define_kind_specific_repr!(
167-
"an enum", EnumRepr, C, U8, U16, U32, U64, Usize, I8, I16, I32, I64, Isize
168+
"an enum",
169+
EnumRepr,
170+
[C, U8, U16, U32, U64, Usize, I8, I16, I32, I64, Isize],
171+
[Align]
168172
);
169173

170174
// All representations known to Rust.

zerocopy-derive/tests/struct_as_bytes.rs

+12
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,18 @@ struct CPacked {
7979

8080
assert_impl_all!(CPacked: AsBytes);
8181

82+
#[derive(AsBytes)]
83+
#[repr(C, packed(2))]
84+
// The same caveats as for CPacked apply - we're assuming u64 is at least
85+
// 4-byte aligned by default. Without packed(2), this should fail, as there
86+
// would be padding between a/b assuming u64 is 4+ byte aligned.
87+
struct CPacked2 {
88+
a: u16,
89+
b: u64,
90+
}
91+
92+
assert_impl_all!(CPacked2: AsBytes);
93+
8294
#[derive(AsBytes)]
8395
#[repr(C, packed)]
8496
struct CPackedGeneric<T, U: ?Sized> {

zerocopy-derive/tests/ui-msrv/struct.stderr

+23-12
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,39 @@ error: unsupported on generic structs that are not repr(transparent) or repr(pac
77
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
88

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

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

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

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

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

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

4545
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
@@ -100,3 +100,14 @@ error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is n
100100
<HasPadding<T, VALUE> as ShouldBe<VALUE>>
101101
= help: see issue #48214
102102
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
103+
104+
error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
105+
--> tests/ui-msrv/struct.rs:66:10
106+
|
107+
66 | #[derive(AsBytes)]
108+
| ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
109+
|
110+
= help: the following implementations were found:
111+
<HasPadding<T, VALUE> as ShouldBe<VALUE>>
112+
= help: see issue #48214
113+
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

zerocopy-derive/tests/ui-nightly/struct.rs

+9
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,15 @@ struct AsBytes2 {
6363
bar: AU16,
6464
}
6565

66+
#[derive(AsBytes)]
67+
#[repr(C, packed(2))]
68+
struct AsBytes3 {
69+
foo: u8,
70+
// We'd prefer to use AU64 here, but you can't use aligned types in
71+
// packed structs.
72+
bar: u64,
73+
}
74+
6675
//
6776
// Unaligned errors
6877
//

zerocopy-derive/tests/ui-nightly/struct.stderr

+25-14
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,39 @@ error: unsupported on generic structs that are not repr(transparent) or repr(pac
77
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
88

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

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

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

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

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

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

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

128+
error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
129+
--> tests/ui-nightly/struct.rs:66:10
130+
|
131+
66 | #[derive(AsBytes)]
132+
| ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
133+
|
134+
= help: the trait `ShouldBe<true>` is implemented for `HasPadding<AsBytes3, true>`
135+
= help: see issue #48214
136+
= help: add `#![feature(trivial_bounds)]` to the crate attributes to enable
137+
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
138+
128139
error[E0587]: type has conflicting packed and align representation hints
129-
--> tests/ui-nightly/struct.rs:82:1
140+
--> tests/ui-nightly/struct.rs:91:1
130141
|
131-
82 | struct Unaligned3;
142+
91 | struct Unaligned3;
132143
| ^^^^^^^^^^^^^^^^^

zerocopy-derive/tests/ui-stable/struct.stderr

+22-12
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,39 @@ error: unsupported on generic structs that are not repr(transparent) or repr(pac
77
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
88

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

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

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

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

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

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

4545
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
@@ -119,3 +119,13 @@ error[E0277]: the trait bound `HasPadding<AsBytes2, true>: ShouldBe<false>` is n
119119
= help: the trait `ShouldBe<VALUE>` is implemented for `HasPadding<T, VALUE>`
120120
= help: see issue #48214
121121
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
122+
123+
error[E0277]: the trait bound `HasPadding<AsBytes3, true>: ShouldBe<false>` is not satisfied
124+
--> tests/ui-stable/struct.rs:66:10
125+
|
126+
66 | #[derive(AsBytes)]
127+
| ^^^^^^^ the trait `ShouldBe<false>` is not implemented for `HasPadding<AsBytes3, true>`
128+
|
129+
= help: the trait `ShouldBe<VALUE>` is implemented for `HasPadding<T, VALUE>`
130+
= help: see issue #48214
131+
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)

0 commit comments

Comments
 (0)