Skip to content

Commit

Permalink
Support derive(KnownLayout) on DSTs (#643)
Browse files Browse the repository at this point in the history
DSTs must be marked with `repr(C)`. The expansion requires the final
field implement `KnownLayout`.

Makes progress towards #29.
  • Loading branch information
jswrenn authored Nov 29, 2023
1 parent 7b98c7f commit 40202e4
Show file tree
Hide file tree
Showing 18 changed files with 1,402 additions and 189 deletions.
426 changes: 421 additions & 5 deletions src/lib.rs

Large diffs are not rendered by default.

286 changes: 228 additions & 58 deletions zerocopy-derive/src/lib.rs

Large diffs are not rendered by default.

77 changes: 49 additions & 28 deletions zerocopy-derive/src/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ define_kind_specific_repr!(
);

// All representations known to Rust.
#[derive(Copy, Clone, Eq, PartialEq)]
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub enum Repr {
U8,
U16,
Expand All @@ -183,40 +183,58 @@ pub enum Repr {
C,
Transparent,
Packed,
PackedN(u64),
Align(u64),
}

impl Repr {
fn from_meta(meta: &Meta) -> Result<Repr, Error> {
match meta {
Meta::Path(path) => {
let ident = path
.get_ident()
.ok_or_else(|| Error::new_spanned(meta, "unrecognized representation hint"))?;
match format!("{}", ident).as_str() {
"u8" => return Ok(Repr::U8),
"u16" => return Ok(Repr::U16),
"u32" => return Ok(Repr::U32),
"u64" => return Ok(Repr::U64),
"usize" => return Ok(Repr::Usize),
"i8" => return Ok(Repr::I8),
"i16" => return Ok(Repr::I16),
"i32" => return Ok(Repr::I32),
"i64" => return Ok(Repr::I64),
"isize" => return Ok(Repr::Isize),
"C" => return Ok(Repr::C),
"transparent" => return Ok(Repr::Transparent),
"packed" => return Ok(Repr::Packed),
_ => {}
}
let (path, list) = match meta {
Meta::Path(path) => (path, None),
Meta::List(list) => (&list.path, Some(list)),
_ => return Err(Error::new_spanned(meta, "unrecognized representation hint")),
};

let ident = path
.get_ident()
.ok_or_else(|| Error::new_spanned(meta, "unrecognized representation hint"))?;

Ok(match (ident.to_string().as_str(), list) {
("u8", None) => Repr::U8,
("u16", None) => Repr::U16,
("u32", None) => Repr::U32,
("u64", None) => Repr::U64,
("usize", None) => Repr::Usize,
("i8", None) => Repr::I8,
("i16", None) => Repr::I16,
("i32", None) => Repr::I32,
("i64", None) => Repr::I64,
("isize", None) => Repr::Isize,
("C", None) => Repr::C,
("transparent", None) => Repr::Transparent,
("packed", None) => Repr::Packed,
("packed", Some(list)) => {
Repr::PackedN(list.parse_args::<LitInt>()?.base10_parse::<u64>()?)
}
Meta::List(list) => {
return Ok(Repr::Align(list.parse_args::<LitInt>()?.base10_parse::<u64>()?))
("align", Some(list)) => {
Repr::Align(list.parse_args::<LitInt>()?.base10_parse::<u64>()?)
}
_ => {}
}
_ => return Err(Error::new_spanned(meta, "unrecognized representation hint")),
})
}
}

Err(Error::new_spanned(meta, "unrecognized representation hint"))
impl KindRepr for Repr {
fn is_align(&self) -> bool {
false
}

fn is_align_gt_one(&self) -> bool {
false
}

fn parse(meta: &Meta) -> syn::Result<Self> {
Self::from_meta(meta)
}
}

Expand All @@ -225,6 +243,9 @@ impl Display for Repr {
if let Repr::Align(n) = self {
return write!(f, "repr(align({}))", n);
}
if let Repr::PackedN(n) = self {
return write!(f, "repr(packed({}))", n);
}
write!(
f,
"repr({})",
Expand All @@ -248,7 +269,7 @@ impl Display for Repr {
}
}

fn reprs<R: KindRepr>(attrs: &[Attribute]) -> Result<Vec<(Meta, R)>, Vec<Error>> {
pub(crate) fn reprs<R: KindRepr>(attrs: &[Attribute]) -> Result<Vec<(Meta, R)>, Vec<Error>> {
let mut reprs = Vec::new();
let mut errors = Vec::new();
for attr in attrs {
Expand Down
5 changes: 4 additions & 1 deletion zerocopy-derive/tests/struct_known_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ mod util;

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

use {static_assertions::assert_impl_all, zerocopy::KnownLayout};
use {
static_assertions::assert_impl_all,
zerocopy::{DstLayout, KnownLayout},
};

use crate::util::AU16;

Expand Down
36 changes: 22 additions & 14 deletions zerocopy-derive/tests/ui-msrv/late_compile_pass.stderr
Original file line number Diff line number Diff line change
@@ -1,25 +1,33 @@
warning: unused import: `zerocopy::KnownLayout`
--> tests/ui-msrv/late_compile_pass.rs:16:5
|
16 | use zerocopy::KnownLayout;
| ^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default

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

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

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

error[E0277]: the trait bound `NotZerocopy: AsBytes` is not satisfied
--> tests/ui-msrv/late_compile_pass.rs:45:10
--> tests/ui-msrv/late_compile_pass.rs:46:10
|
45 | #[derive(AsBytes)]
46 | #[derive(AsBytes)]
| ^^^^^^^ the trait `AsBytes` is not implemented for `NotZerocopy`
|
= 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 `AU16: Unaligned` is not satisfied
--> tests/ui-msrv/late_compile_pass.rs:55:10
--> tests/ui-msrv/late_compile_pass.rs:56:10
|
55 | #[derive(Unaligned)]
56 | #[derive(Unaligned)]
| ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
|
= help: see issue #48214
= note: this error originates in the derive macro `Unaligned` (in Nightly builds, run with -Z macro-backtrace for more info)

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

error[E0277]: the trait bound `AU16: Unaligned` is not satisfied
--> tests/ui-msrv/late_compile_pass.rs:70:10
--> tests/ui-msrv/late_compile_pass.rs:71:10
|
70 | #[derive(Unaligned)]
71 | #[derive(Unaligned)]
| ^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16`
|
= help: see issue #48214
Expand Down
1 change: 1 addition & 0 deletions zerocopy-derive/tests/ui-msrv/mid_compile_pass.rs
104 changes: 104 additions & 0 deletions zerocopy-derive/tests/ui-msrv/mid_compile_pass.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
error[E0277]: the trait bound `T: KnownLayout` is not satisfied
--> tests/ui-msrv/mid_compile_pass.rs:59:26
|
59 | fn test_kl13<T>(t: T) -> impl KnownLayout {
| ^^^^^^^^^^^^^^^^ the trait `KnownLayout` is not implemented for `T`
|
note: required because of the requirements on the impl of `KnownLayout` for `KL13<T>`
--> tests/ui-msrv/mid_compile_pass.rs:55:10
|
55 | #[derive(KnownLayout)]
| ^^^^^^^^^^^
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider restricting type parameter `T`
|
59 | fn test_kl13<T: zerocopy::KnownLayout>(t: T) -> impl KnownLayout {
| +++++++++++++++++++++++

error[E0277]: the size for values of type `T` cannot be known at compilation time
--> tests/ui-msrv/mid_compile_pass.rs:31:15
|
30 | fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
| - this type parameter needs to be `std::marker::Sized`
31 | assert_kl(kl);
| --------- ^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
note: required because it appears within the type `KL04<T>`
--> tests/ui-msrv/mid_compile_pass.rs:28:8
|
28 | struct KL04<T: ?Sized>(u8, T);
| ^^^^
note: required because of the requirements on the impl of `KnownLayout` for `KL04<T>`
--> tests/ui-msrv/mid_compile_pass.rs:27:10
|
27 | #[derive(KnownLayout)]
| ^^^^^^^^^^^
note: required by a bound in `assert_kl`
--> tests/ui-msrv/mid_compile_pass.rs:23:26
|
23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
| ^^^^^^^^^^^ required by this bound in `assert_kl`
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
30 - fn test_kl04<T: ?Sized>(kl: &KL04<T>) {
30 + fn test_kl04<T>(kl: &KL04<T>) {
|

error[E0277]: the size for values of type `T` cannot be known at compilation time
--> tests/ui-msrv/mid_compile_pass.rs:40:15
|
39 | fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
| - this type parameter needs to be `std::marker::Sized`
40 | assert_kl(kl);
| --------- ^^ doesn't have a size known at compile-time
| |
| required by a bound introduced by this call
|
note: required because it appears within the type `KL06<T>`
--> tests/ui-msrv/mid_compile_pass.rs:37:8
|
37 | struct KL06<T: ?Sized + KnownLayout>(u8, T);
| ^^^^
note: required because of the requirements on the impl of `KnownLayout` for `KL06<T>`
--> tests/ui-msrv/mid_compile_pass.rs:36:10
|
36 | #[derive(KnownLayout)]
| ^^^^^^^^^^^
note: required by a bound in `assert_kl`
--> tests/ui-msrv/mid_compile_pass.rs:23:26
|
23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
| ^^^^^^^^^^^ required by this bound in `assert_kl`
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
39 - fn test_kl06<T: ?Sized + KnownLayout>(kl: &KL06<T>) {
39 + fn test_kl06<T: KnownLayout>(kl: &KL06<T>) {
|

error[E0277]: the trait bound `T: KnownLayout` is not satisfied
--> tests/ui-msrv/mid_compile_pass.rs:50:15
|
50 | assert_kl(kl)
| --------- ^^ the trait `KnownLayout` is not implemented for `T`
| |
| required by a bound introduced by this call
|
note: required because of the requirements on the impl of `KnownLayout` for `KL12<T>`
--> tests/ui-msrv/mid_compile_pass.rs:45:10
|
45 | #[derive(KnownLayout)]
| ^^^^^^^^^^^
note: required by a bound in `assert_kl`
--> tests/ui-msrv/mid_compile_pass.rs:23:26
|
23 | fn assert_kl<T: ?Sized + KnownLayout>(_: &T) {}
| ^^^^^^^^^^^ required by this bound in `assert_kl`
= note: this error originates in the derive macro `KnownLayout` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider further restricting this bound
|
49 | fn test_kl12<T: ?Sized + zerocopy::KnownLayout>(kl: &KL12<T>) {
| +++++++++++++++++++++++
Loading

0 comments on commit 40202e4

Please sign in to comment.