Skip to content

Commit 40202e4

Browse files
authored
Support derive(KnownLayout) on DSTs (#643)
DSTs must be marked with `repr(C)`. The expansion requires the final field implement `KnownLayout`. Makes progress towards #29.
1 parent 7b98c7f commit 40202e4

18 files changed

+1402
-189
lines changed

src/lib.rs

Lines changed: 421 additions & 5 deletions
Large diffs are not rendered by default.

zerocopy-derive/src/lib.rs

Lines changed: 228 additions & 58 deletions
Large diffs are not rendered by default.

zerocopy-derive/src/repr.rs

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ define_kind_specific_repr!(
168168
);
169169

170170
// All representations known to Rust.
171-
#[derive(Copy, Clone, Eq, PartialEq)]
171+
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
172172
pub enum Repr {
173173
U8,
174174
U16,
@@ -183,40 +183,58 @@ pub enum Repr {
183183
C,
184184
Transparent,
185185
Packed,
186+
PackedN(u64),
186187
Align(u64),
187188
}
188189

189190
impl Repr {
190191
fn from_meta(meta: &Meta) -> Result<Repr, Error> {
191-
match meta {
192-
Meta::Path(path) => {
193-
let ident = path
194-
.get_ident()
195-
.ok_or_else(|| Error::new_spanned(meta, "unrecognized representation hint"))?;
196-
match format!("{}", ident).as_str() {
197-
"u8" => return Ok(Repr::U8),
198-
"u16" => return Ok(Repr::U16),
199-
"u32" => return Ok(Repr::U32),
200-
"u64" => return Ok(Repr::U64),
201-
"usize" => return Ok(Repr::Usize),
202-
"i8" => return Ok(Repr::I8),
203-
"i16" => return Ok(Repr::I16),
204-
"i32" => return Ok(Repr::I32),
205-
"i64" => return Ok(Repr::I64),
206-
"isize" => return Ok(Repr::Isize),
207-
"C" => return Ok(Repr::C),
208-
"transparent" => return Ok(Repr::Transparent),
209-
"packed" => return Ok(Repr::Packed),
210-
_ => {}
211-
}
192+
let (path, list) = match meta {
193+
Meta::Path(path) => (path, None),
194+
Meta::List(list) => (&list.path, Some(list)),
195+
_ => return Err(Error::new_spanned(meta, "unrecognized representation hint")),
196+
};
197+
198+
let ident = path
199+
.get_ident()
200+
.ok_or_else(|| Error::new_spanned(meta, "unrecognized representation hint"))?;
201+
202+
Ok(match (ident.to_string().as_str(), list) {
203+
("u8", None) => Repr::U8,
204+
("u16", None) => Repr::U16,
205+
("u32", None) => Repr::U32,
206+
("u64", None) => Repr::U64,
207+
("usize", None) => Repr::Usize,
208+
("i8", None) => Repr::I8,
209+
("i16", None) => Repr::I16,
210+
("i32", None) => Repr::I32,
211+
("i64", None) => Repr::I64,
212+
("isize", None) => Repr::Isize,
213+
("C", None) => Repr::C,
214+
("transparent", None) => Repr::Transparent,
215+
("packed", None) => Repr::Packed,
216+
("packed", Some(list)) => {
217+
Repr::PackedN(list.parse_args::<LitInt>()?.base10_parse::<u64>()?)
212218
}
213-
Meta::List(list) => {
214-
return Ok(Repr::Align(list.parse_args::<LitInt>()?.base10_parse::<u64>()?))
219+
("align", Some(list)) => {
220+
Repr::Align(list.parse_args::<LitInt>()?.base10_parse::<u64>()?)
215221
}
216-
_ => {}
217-
}
222+
_ => return Err(Error::new_spanned(meta, "unrecognized representation hint")),
223+
})
224+
}
225+
}
218226

219-
Err(Error::new_spanned(meta, "unrecognized representation hint"))
227+
impl KindRepr for Repr {
228+
fn is_align(&self) -> bool {
229+
false
230+
}
231+
232+
fn is_align_gt_one(&self) -> bool {
233+
false
234+
}
235+
236+
fn parse(meta: &Meta) -> syn::Result<Self> {
237+
Self::from_meta(meta)
220238
}
221239
}
222240

@@ -225,6 +243,9 @@ impl Display for Repr {
225243
if let Repr::Align(n) = self {
226244
return write!(f, "repr(align({}))", n);
227245
}
246+
if let Repr::PackedN(n) = self {
247+
return write!(f, "repr(packed({}))", n);
248+
}
228249
write!(
229250
f,
230251
"repr({})",
@@ -248,7 +269,7 @@ impl Display for Repr {
248269
}
249270
}
250271

251-
fn reprs<R: KindRepr>(attrs: &[Attribute]) -> Result<Vec<(Meta, R)>, Vec<Error>> {
272+
pub(crate) fn reprs<R: KindRepr>(attrs: &[Attribute]) -> Result<Vec<(Meta, R)>, Vec<Error>> {
252273
let mut reprs = Vec::new();
253274
let mut errors = Vec::new();
254275
for attr in attrs {

zerocopy-derive/tests/struct_known_layout.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ mod util;
99

1010
use std::{marker::PhantomData, option::IntoIter};
1111

12-
use {static_assertions::assert_impl_all, zerocopy::KnownLayout};
12+
use {
13+
static_assertions::assert_impl_all,
14+
zerocopy::{DstLayout, KnownLayout},
15+
};
1316

1417
use crate::util::AU16;
1518

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

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,33 @@
1+
warning: unused import: `zerocopy::KnownLayout`
2+
--> tests/ui-msrv/late_compile_pass.rs:16:5
3+
|
4+
16 | use zerocopy::KnownLayout;
5+
| ^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: `#[warn(unused_imports)]` on by default
8+
19
error[E0277]: the trait bound `NotZerocopy: FromZeroes` is not satisfied
2-
--> tests/ui-msrv/late_compile_pass.rs:27:10
10+
--> tests/ui-msrv/late_compile_pass.rs:28:10
311
|
4-
27 | #[derive(FromZeroes)]
12+
28 | #[derive(FromZeroes)]
513
| ^^^^^^^^^^ the trait `FromZeroes` is not implemented for `NotZerocopy`
614
|
715
= help: see issue #48214
816
= note: this error originates in the derive macro `FromZeroes` (in Nightly builds, run with -Z macro-backtrace for more info)
917

1018
error[E0277]: the trait bound `NotZerocopy: FromBytes` is not satisfied
11-
--> tests/ui-msrv/late_compile_pass.rs:36:10
19+
--> tests/ui-msrv/late_compile_pass.rs:37:10
1220
|
13-
36 | #[derive(FromBytes)]
21+
37 | #[derive(FromBytes)]
1422
| ^^^^^^^^^ the trait `FromBytes` is not implemented for `NotZerocopy`
1523
|
1624
= help: see issue #48214
1725
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
1826

1927
error[E0277]: the trait bound `FromBytes1: FromZeroes` is not satisfied
20-
--> tests/ui-msrv/late_compile_pass.rs:36:10
28+
--> tests/ui-msrv/late_compile_pass.rs:37:10
2129
|
22-
36 | #[derive(FromBytes)]
30+
37 | #[derive(FromBytes)]
2331
| ^^^^^^^^^ the trait `FromZeroes` is not implemented for `FromBytes1`
2432
|
2533
note: required by a bound in `FromBytes`
@@ -30,36 +38,36 @@ note: required by a bound in `FromBytes`
3038
= note: this error originates in the derive macro `FromBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
3139

3240
error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
33-
--> tests/ui-msrv/late_compile_pass.rs:45:10
41+
--> tests/ui-msrv/late_compile_pass.rs:46:10
3442
|
35-
45 | #[derive(AsBytes)]
43+
46 | #[derive(AsBytes)]
3644
| ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`
3745
|
3846
= help: see issue #48214
3947
= note: this error originates in the derive macro `AsBytes` (in Nightly builds, run with -Z macro-backtrace for more info)
4048

4149
error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
42-
--> tests/ui-msrv/late_compile_pass.rs:55:10
50+
--> tests/ui-msrv/late_compile_pass.rs:56:10
4351
|
44-
55 | #[derive(Unaligned)]
52+
56 | #[derive(Unaligned)]
4553
| ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
4654
|
4755
= help: see issue #48214
4856
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
4957

5058
error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
51-
--> tests/ui-msrv/late_compile_pass.rs:63:10
59+
--> tests/ui-msrv/late_compile_pass.rs:64:10
5260
|
53-
63 | #[derive(Unaligned)]
61+
64 | #[derive(Unaligned)]
5462
| ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
5563
|
5664
= help: see issue #48214
5765
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)
5866

5967
error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
60-
--> tests/ui-msrv/late_compile_pass.rs:70:10
68+
--> tests/ui-msrv/late_compile_pass.rs:71:10
6169
|
62-
70 | #[derive(Unaligned)]
70+
71 | #[derive(Unaligned)]
6371
| ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
6472
|
6573
= help: see issue #48214
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../ui-nightly/mid_compile_pass.rs
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
error[E0277]: the trait bound `T: KnownLayout` is not satisfied
2+
--> tests/ui-msrv/mid_compile_pass.rs:59:26
3+
|
4+
59 | fn test_kl13<T>(t: T) -> impl KnownLayout {
5+
| ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`
6+
|
7+
note: required because of the requirements on the impl of `KnownLayout` for `KL13<T>`
8+
--> tests/ui-msrv/mid_compile_pass.rs:55:10
9+
|
10+
55 | #[derive(KnownLayout)]
11+
| ^^^^^^^^^^^
12+
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
13+
help: consider restricting type parameter `T`
14+
|
15+
59 | fn test_kl13<T: zerocopy::KnownLayout>(t: T) -> impl KnownLayout {
16+
| +++++++++++++++++++++++
17+
18+
error[E0277]: the size for values of type `T` cannot be known at compilation time
19+
--> tests/ui-msrv/mid_compile_pass.rs:31:15
20+
|
21+
30 | fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
22+
| - this type parameter needs to be `std::marker::Sized`
23+
31 | assert_kl(kl);
24+
| --------- ^^ doesn't have a size known at compile-time
25+
| |
26+
| required by a bound introduced by this call
27+
|
28+
note: required because it appears within the type `KL04<T>`
29+
--> tests/ui-msrv/mid_compile_pass.rs:28:8
30+
|
31+
28 | struct KL04<T: ?Sized>(u8, T);
32+
| ^^^^
33+
note: required because of the requirements on the impl of `KnownLayout` for `KL04<T>`
34+
--> tests/ui-msrv/mid_compile_pass.rs:27:10
35+
|
36+
27 | #[derive(KnownLayout)]
37+
| ^^^^^^^^^^^
38+
note: required by a bound in `assert_kl`
39+
--> tests/ui-msrv/mid_compile_pass.rs:23:26
40+
|
41+
23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
42+
| ^^^^^^^^^^^ required by this bound in `assert_kl`
43+
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
44+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
45+
|
46+
30 - fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
47+
30 + fn test_kl04<T>(kl: &KL04<T>) {
48+
|
49+
50+
error[E0277]: the size for values of type `T` cannot be known at compilation time
51+
--> tests/ui-msrv/mid_compile_pass.rs:40:15
52+
|
53+
39 | fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
54+
| - this type parameter needs to be `std::marker::Sized`
55+
40 | assert_kl(kl);
56+
| --------- ^^ doesn't have a size known at compile-time
57+
| |
58+
| required by a bound introduced by this call
59+
|
60+
note: required because it appears within the type `KL06<T>`
61+
--> tests/ui-msrv/mid_compile_pass.rs:37:8
62+
|
63+
37 | struct KL06<T: ?Sized + KnownLayout>(u8, T);
64+
| ^^^^
65+
note: required because of the requirements on the impl of `KnownLayout` for `KL06<T>`
66+
--> tests/ui-msrv/mid_compile_pass.rs:36:10
67+
|
68+
36 | #[derive(KnownLayout)]
69+
| ^^^^^^^^^^^
70+
note: required by a bound in `assert_kl`
71+
--> tests/ui-msrv/mid_compile_pass.rs:23:26
72+
|
73+
23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
74+
| ^^^^^^^^^^^ required by this bound in `assert_kl`
75+
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
76+
help: consider removing the `?Sized` bound to make the type parameter `Sized`
77+
|
78+
39 - fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
79+
39 + fn test_kl06<T: KnownLayout>(kl: &KL06<T>) {
80+
|
81+
82+
error[E0277]: the trait bound `T: KnownLayout` is not satisfied
83+
--> tests/ui-msrv/mid_compile_pass.rs:50:15
84+
|
85+
50 | assert_kl(kl)
86+
| --------- ^^ the trait `KnownLayout` is not implemented for `T`
87+
| |
88+
| required by a bound introduced by this call
89+
|
90+
note: required because of the requirements on the impl of `KnownLayout` for `KL12<T>`
91+
--> tests/ui-msrv/mid_compile_pass.rs:45:10
92+
|
93+
45 | #[derive(KnownLayout)]
94+
| ^^^^^^^^^^^
95+
note: required by a bound in `assert_kl`
96+
--> tests/ui-msrv/mid_compile_pass.rs:23:26
97+
|
98+
23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
99+
| ^^^^^^^^^^^ required by this bound in `assert_kl`
100+
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
101+
help: consider further restricting this bound
102+
|
103+
49 | fn test_kl12<T: ?Sized + zerocopy::KnownLayout>(kl: &KL12<T>) {
104+
| +++++++++++++++++++++++

0 commit comments

Comments
 (0)