diff --git a/src/lib.rs b/src/lib.rs index 8053e0c51d..5ba4fa12da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3251,4 +3251,22 @@ mod tests { assert_eq!(<()>::new_zeroed(), ()); } } + + #[test] + fn test_transparent_generic_struct() { + #[derive(AsBytes, FromBytes, Unaligned)] + #[repr(transparent)] + struct Foo { + _bar: T, + _phantom: PhantomData<()>, + } + + fn assert_impls_asbytes() {} + fn assert_impls_frombytes() {} + fn assert_impls_unaligned() {} + + assert_impls_asbytes::>(); + assert_impls_frombytes::>(); + assert_impls_unaligned::>(); + } } diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 590008861c..198d06c211 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -195,16 +195,26 @@ fn derive_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro2::T // - `repr(packed)` fn derive_as_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_macro2::TokenStream { - // TODO(#10): Support type parameters. - if !ast.generics.params.is_empty() { - return Error::new(Span::call_site(), "unsupported on types with type parameters") - .to_compile_error(); - } - let reprs = try_or_print!(STRUCT_UNION_AS_BYTES_CFG.validate_reprs(ast)); - let padding_check = - if reprs.contains(&StructRepr::Packed) { PaddingCheck::None } else { PaddingCheck::Struct }; + let is_transparent = reprs.contains(&StructRepr::Transparent); + // TODO(#10): Support type parameters for non-transparent structs. + if !ast.generics.params.is_empty() && !is_transparent { + return Error::new( + Span::call_site(), + "unsupported on generic structs that are not repr(transparent)", + ) + .to_compile_error(); + } + + // We don't need a padding check if the struct is repr(transparent) since + // the layout and ABI of the whole struct is the same as its only non-ZST + // field, and we require that field to be `AsBytes`. + let padding_check = if is_transparent || reprs.contains(&StructRepr::Packed) { + PaddingCheck::None + } else { + PaddingCheck::Struct + }; impl_block(ast, strct, "AsBytes", true, padding_check) } diff --git a/zerocopy-derive/tests/enum_as_bytes.rs b/zerocopy-derive/tests/enum_as_bytes.rs index be5c53d0da..c4c395cee9 100644 --- a/zerocopy-derive/tests/enum_as_bytes.rs +++ b/zerocopy-derive/tests/enum_as_bytes.rs @@ -4,18 +4,10 @@ #![allow(warnings)] -use zerocopy::AsBytes; - -struct IsAsBytes(T); +#[macro_use] +mod util; -// Fail compilation if `$ty: !AsBytes`. -macro_rules! is_as_bytes { - ($ty:ty) => { - const _: () = { - let _: IsAsBytes<$ty>; - }; - }; -} +use zerocopy::AsBytes; // An enum is `AsBytes` if if has a defined repr. @@ -25,7 +17,7 @@ enum C { A, } -is_as_bytes!(C); +assert_is_as_bytes!(C); #[derive(AsBytes)] #[repr(u8)] @@ -33,7 +25,7 @@ enum U8 { A, } -is_as_bytes!(U8); +assert_is_as_bytes!(U8); #[derive(AsBytes)] #[repr(u16)] @@ -41,7 +33,7 @@ enum U16 { A, } -is_as_bytes!(U16); +assert_is_as_bytes!(U16); #[derive(AsBytes)] #[repr(u32)] @@ -49,7 +41,7 @@ enum U32 { A, } -is_as_bytes!(U32); +assert_is_as_bytes!(U32); #[derive(AsBytes)] #[repr(u64)] @@ -57,7 +49,7 @@ enum U64 { A, } -is_as_bytes!(U64); +assert_is_as_bytes!(U64); #[derive(AsBytes)] #[repr(usize)] @@ -65,7 +57,7 @@ enum Usize { A, } -is_as_bytes!(Usize); +assert_is_as_bytes!(Usize); #[derive(AsBytes)] #[repr(i8)] @@ -73,7 +65,7 @@ enum I8 { A, } -is_as_bytes!(I8); +assert_is_as_bytes!(I8); #[derive(AsBytes)] #[repr(i16)] @@ -81,7 +73,7 @@ enum I16 { A, } -is_as_bytes!(I16); +assert_is_as_bytes!(I16); #[derive(AsBytes)] #[repr(i32)] @@ -89,7 +81,7 @@ enum I32 { A, } -is_as_bytes!(I32); +assert_is_as_bytes!(I32); #[derive(AsBytes)] #[repr(i64)] @@ -97,7 +89,7 @@ enum I64 { A, } -is_as_bytes!(I64); +assert_is_as_bytes!(I64); #[derive(AsBytes)] #[repr(isize)] @@ -105,4 +97,4 @@ enum Isize { A, } -is_as_bytes!(Isize); +assert_is_as_bytes!(Isize); diff --git a/zerocopy-derive/tests/enum_from_bytes.rs b/zerocopy-derive/tests/enum_from_bytes.rs index 671878d1c0..6d34ec761b 100644 --- a/zerocopy-derive/tests/enum_from_bytes.rs +++ b/zerocopy-derive/tests/enum_from_bytes.rs @@ -4,6 +4,9 @@ #![allow(warnings)] +#[macro_use] +mod util; + use zerocopy::FromBytes; // An enum is `FromBytes` if: @@ -23,17 +26,6 @@ use zerocopy::FromBytes; // `Variant128` has a discriminant of -128) since Rust won't automatically wrap // a signed discriminant around without you explicitly telling it to. -struct IsFromBytes(T); - -// Fail compilation if `$ty: !FromBytes`. -macro_rules! is_from_bytes { - ($ty:ty) => { - const _: () = { - let _: IsFromBytes<$ty>; - }; - }; -} - #[derive(FromBytes)] #[repr(u8)] enum FooU8 { @@ -295,7 +287,7 @@ enum FooU8 { Variant255, } -is_from_bytes!(FooU8); +assert_is_from_bytes!(FooU8); #[derive(FromBytes)] #[repr(i8)] @@ -558,7 +550,7 @@ enum FooI8 { Variant255, } -is_from_bytes!(FooI8); +assert_is_from_bytes!(FooI8); #[derive(FromBytes)] #[repr(u8, align(2))] @@ -821,7 +813,7 @@ enum FooU8Align { Variant255, } -is_from_bytes!(FooU8Align); +assert_is_from_bytes!(FooU8Align); #[derive(FromBytes)] #[repr(i8, align(2))] @@ -1084,7 +1076,7 @@ enum FooI8Align { Variant255, } -is_from_bytes!(FooI8Align); +assert_is_from_bytes!(FooI8Align); #[derive(FromBytes)] #[repr(u16)] @@ -66627,7 +66619,7 @@ enum FooU16 { Variant65535, } -is_from_bytes!(FooU16); +assert_is_from_bytes!(FooU16); #[derive(FromBytes)] #[repr(i16)] @@ -132170,4 +132162,4 @@ enum FooI16 { Variant65535, } -is_from_bytes!(FooI16); +assert_is_from_bytes!(FooI16); diff --git a/zerocopy-derive/tests/enum_unaligned.rs b/zerocopy-derive/tests/enum_unaligned.rs index 54381357d9..2285878201 100644 --- a/zerocopy-derive/tests/enum_unaligned.rs +++ b/zerocopy-derive/tests/enum_unaligned.rs @@ -4,18 +4,10 @@ #![allow(warnings)] -use zerocopy::Unaligned; - -struct IsUnaligned(T); +#[macro_use] +mod util; -// Fail compilation if `$ty: !Unaligned`. -macro_rules! is_unaligned { - ($ty:ty) => { - const _: () = { - let _: IsUnaligned<$ty>; - }; - }; -} +use zerocopy::Unaligned; // An enum is `Unaligned` if: // - No `repr(align(N > 1))` @@ -27,7 +19,7 @@ enum Foo { A, } -is_unaligned!(Foo); +assert_is_unaligned!(Foo); #[derive(Unaligned)] #[repr(i8)] @@ -35,7 +27,7 @@ enum Bar { A, } -is_unaligned!(Bar); +assert_is_unaligned!(Bar); #[derive(Unaligned)] #[repr(u8, align(1))] @@ -43,7 +35,7 @@ enum Baz { A, } -is_unaligned!(Baz); +assert_is_unaligned!(Baz); #[derive(Unaligned)] #[repr(i8, align(1))] @@ -51,4 +43,4 @@ enum Blah { B, } -is_unaligned!(Blah); +assert_is_unaligned!(Blah); diff --git a/zerocopy-derive/tests/struct_as_bytes.rs b/zerocopy-derive/tests/struct_as_bytes.rs index d9dba8912f..49586a161a 100644 --- a/zerocopy-derive/tests/struct_as_bytes.rs +++ b/zerocopy-derive/tests/struct_as_bytes.rs @@ -4,25 +4,13 @@ #![allow(warnings)] +#[macro_use] mod util; +use self::util::AU16; use std::{marker::PhantomData, option::IntoIter}; - use zerocopy::AsBytes; -use crate::util::AU16; - -struct IsAsBytes(T); - -// Fail compilation if `$ty: !AsBytes`. -macro_rules! is_as_bytes { - ($ty:ty) => { - const _: () = { - let _: IsAsBytes<$ty>; - }; - }; -} - // A struct is `AsBytes` if: // - all fields are `AsBytes` // - `repr(C)` or `repr(transparent)` and @@ -33,7 +21,7 @@ macro_rules! is_as_bytes { #[repr(C)] struct CZst; -is_as_bytes!(CZst); +assert_is_as_bytes!(CZst); #[derive(AsBytes)] #[repr(C)] @@ -43,7 +31,7 @@ struct C { c: AU16, } -is_as_bytes!(C); +assert_is_as_bytes!(C); #[derive(AsBytes)] #[repr(transparent)] @@ -52,13 +40,13 @@ struct Transparent { b: CZst, } -is_as_bytes!(Transparent); +assert_is_as_bytes!(Transparent); #[derive(AsBytes)] #[repr(C, packed)] struct CZstPacked; -is_as_bytes!(CZstPacked); +assert_is_as_bytes!(CZstPacked); #[derive(AsBytes)] #[repr(C, packed)] @@ -74,4 +62,4 @@ struct CPacked { b: u16, } -is_as_bytes!(CPacked); +assert_is_as_bytes!(CPacked); diff --git a/zerocopy-derive/tests/struct_from_bytes.rs b/zerocopy-derive/tests/struct_from_bytes.rs index 7ebc300a40..3844d47186 100644 --- a/zerocopy-derive/tests/struct_from_bytes.rs +++ b/zerocopy-derive/tests/struct_from_bytes.rs @@ -4,35 +4,26 @@ #![allow(warnings)] -use std::{marker::PhantomData, option::IntoIter}; +#[macro_use] +mod util; +use std::{marker::PhantomData, option::IntoIter}; use zerocopy::FromBytes; -struct IsFromBytes(T); - -// Fail compilation if `$ty: !FromBytes`. -macro_rules! is_from_bytes { - ($ty:ty) => { - const _: () = { - let _: IsFromBytes<$ty>; - }; - }; -} - // A struct is `FromBytes` if: // - all fields are `FromBytes` #[derive(FromBytes)] struct Zst; -is_from_bytes!(Zst); +assert_is_from_bytes!(Zst); #[derive(FromBytes)] struct One { a: u8, } -is_from_bytes!(One); +assert_is_from_bytes!(One); #[derive(FromBytes)] struct Two { @@ -40,7 +31,7 @@ struct Two { b: Zst, } -is_from_bytes!(Two); +assert_is_from_bytes!(Two); #[derive(FromBytes)] struct TypeParams<'a, T, I: Iterator> { @@ -52,4 +43,4 @@ struct TypeParams<'a, T, I: Iterator> { g: PhantomData, } -is_from_bytes!(TypeParams<'static, (), IntoIter<()>>); +assert_is_from_bytes!(TypeParams<'static, (), IntoIter<()>>); diff --git a/zerocopy-derive/tests/struct_unaligned.rs b/zerocopy-derive/tests/struct_unaligned.rs index e1fc0e4b1b..c91dd4b6b0 100644 --- a/zerocopy-derive/tests/struct_unaligned.rs +++ b/zerocopy-derive/tests/struct_unaligned.rs @@ -4,21 +4,12 @@ #![allow(warnings)] -use std::{marker::PhantomData, option::IntoIter}; +#[macro_use] +mod util; +use std::{marker::PhantomData, option::IntoIter}; use zerocopy::Unaligned; -struct IsUnaligned(T); - -// Fail compilation if `$ty: !Unaligned`. -macro_rules! is_unaligned { - ($ty:ty) => { - const _: () = { - let _: IsUnaligned<$ty>; - }; - }; -} - // A struct is `Unaligned` if: // - `repr(align)` is no more than 1 and either // - `repr(C)` or `repr(transparent)` and @@ -31,7 +22,7 @@ struct Foo { a: u8, } -is_unaligned!(Foo); +assert_is_unaligned!(Foo); #[derive(Unaligned)] #[repr(transparent)] @@ -39,7 +30,7 @@ struct Bar { a: u8, } -is_unaligned!(Bar); +assert_is_unaligned!(Bar); #[derive(Unaligned)] #[repr(packed)] @@ -54,7 +45,7 @@ struct Baz { a: u16, } -is_unaligned!(Baz); +assert_is_unaligned!(Baz); #[derive(Unaligned)] #[repr(C, align(1))] @@ -62,7 +53,7 @@ struct FooAlign { a: u8, } -is_unaligned!(FooAlign); +assert_is_unaligned!(FooAlign); #[derive(Unaligned)] #[repr(C)] @@ -75,4 +66,4 @@ struct TypeParams<'a, T, I: Iterator> { g: PhantomData, } -is_unaligned!(TypeParams<'static, (), IntoIter<()>>); +assert_is_unaligned!(TypeParams<'static, (), IntoIter<()>>); diff --git a/zerocopy-derive/tests/ui-msrv/derive_transparent.rs b/zerocopy-derive/tests/ui-msrv/derive_transparent.rs new file mode 120000 index 0000000000..4fa942d967 --- /dev/null +++ b/zerocopy-derive/tests/ui-msrv/derive_transparent.rs @@ -0,0 +1 @@ +../ui/derive_transparent.rs \ No newline at end of file diff --git a/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr b/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr new file mode 100644 index 0000000000..a16723e834 --- /dev/null +++ b/zerocopy-derive/tests/ui-msrv/derive_transparent.stderr @@ -0,0 +1,92 @@ +error[E0432]: unresolved import `self::util::NotAsBytes` + --> tests/ui-msrv/derive_transparent.rs:11:18 + | +11 | use self::util::{NotAsBytes, AU16}; + | ^^^^^^^^^^ + | | + | no `NotAsBytes` in `util` + | help: a similar name exists in the module: `AsBytes` + +error[E0277]: the trait bound `NotAsBytes: AsBytes` is not satisfied + --> tests/ui-msrv/../util.rs + | + | const _: fn($ty) -> IsAsBytes<$ty> = IsAsBytes::<$ty>; + | ^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotAsBytes` + | + ::: tests/ui-msrv/derive_transparent.rs:33:1 + | +33 | assert_is_as_bytes!(TransparentStruct); + | -------------------------------------------------- in this macro invocation + | +note: required because of the requirements on the impl of `AsBytes` for `TransparentStruct` + --> tests/ui-msrv/derive_transparent.rs:20:10 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^ +note: required by a bound in `IsAsBytes` + --> tests/ui-msrv/../util.rs + | + | struct IsAsBytes(T); + | ^^^^^^^^^^^^^^^^^ required by this bound in `IsAsBytes` + | + ::: tests/ui-msrv/derive_transparent.rs:33:1 + | +33 | assert_is_as_bytes!(TransparentStruct); + | -------------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_as_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `char: FromBytes` is not satisfied + --> tests/ui-msrv/../util.rs + | + | const _: fn($ty) -> IsFromBytes<$ty> = IsFromBytes::<$ty>; + | ^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `char` + | + ::: tests/ui-msrv/derive_transparent.rs:34:1 + | +34 | assert_is_from_bytes!(TransparentStruct); + | ---------------------------------------------- in this macro invocation + | +note: required because of the requirements on the impl of `FromBytes` for `TransparentStruct` + --> tests/ui-msrv/derive_transparent.rs:20:19 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `IsFromBytes` + --> tests/ui-msrv/../util.rs + | + | struct IsFromBytes(T); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `IsFromBytes` + | + ::: tests/ui-msrv/derive_transparent.rs:34:1 + | +34 | assert_is_from_bytes!(TransparentStruct); + | ---------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_from_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-msrv/../util.rs + | + | const _: fn($ty) -> IsUnaligned<$ty> = IsUnaligned::<$ty>; + | ^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + ::: tests/ui-msrv/derive_transparent.rs:35:1 + | +35 | assert_is_unaligned!(TransparentStruct); + | --------------------------------------------- in this macro invocation + | +note: required because of the requirements on the impl of `Unaligned` for `TransparentStruct` + --> tests/ui-msrv/derive_transparent.rs:20:30 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `IsUnaligned` + --> tests/ui-msrv/../util.rs + | + | struct IsUnaligned(T); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `IsUnaligned` + | + ::: tests/ui-msrv/derive_transparent.rs:35:1 + | +35 | assert_is_unaligned!(TransparentStruct); + | --------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-msrv/struct.stderr b/zerocopy-derive/tests/ui-msrv/struct.stderr index 871e6ce1af..2cb2e832ef 100644 --- a/zerocopy-derive/tests/ui-msrv/struct.stderr +++ b/zerocopy-derive/tests/ui-msrv/struct.stderr @@ -1,4 +1,4 @@ -error: unsupported on types with type parameters +error: unsupported on generic structs that are not repr(transparent) --> tests/ui-msrv/struct.rs:19:10 | 19 | #[derive(AsBytes)] diff --git a/zerocopy-derive/tests/ui-msrv/union.stderr b/zerocopy-derive/tests/ui-msrv/union.stderr index 48bc71dc5b..711b8e26a9 100644 --- a/zerocopy-derive/tests/ui-msrv/union.stderr +++ b/zerocopy-derive/tests/ui-msrv/union.stderr @@ -1,39 +1,39 @@ error: unsupported on types with type parameters - --> tests/ui-msrv/union.rs:21:10 + --> tests/ui-msrv/union.rs:20:10 | -21 | #[derive(AsBytes)] +20 | #[derive(AsBytes)] | ^^^^^^^ | = 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/union.rs:39:11 + --> tests/ui-msrv/union.rs:38:11 | -39 | #[repr(C, align(2))] +38 | #[repr(C, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/union.rs:55:16 + --> tests/ui-msrv/union.rs:54:16 | -55 | #[repr(packed, align(2))] +54 | #[repr(packed, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/union.rs:61:18 + --> tests/ui-msrv/union.rs:60:18 | -61 | #[repr(align(1), align(2))] +60 | #[repr(align(1), align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/union.rs:67:8 + --> tests/ui-msrv/union.rs:66:8 | -67 | #[repr(align(2), align(4))] +66 | #[repr(align(2), align(4))] | ^^^^^^^^ error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied - --> tests/ui-msrv/union.rs:27:10 + --> tests/ui-msrv/union.rs:26:10 | -27 | #[derive(AsBytes)] +26 | #[derive(AsBytes)] | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` | = help: the following implementations were found: diff --git a/zerocopy-derive/tests/ui-stable/derive_transparent.rs b/zerocopy-derive/tests/ui-stable/derive_transparent.rs new file mode 120000 index 0000000000..4fa942d967 --- /dev/null +++ b/zerocopy-derive/tests/ui-stable/derive_transparent.rs @@ -0,0 +1 @@ +../ui/derive_transparent.rs \ No newline at end of file diff --git a/zerocopy-derive/tests/ui-stable/derive_transparent.stderr b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr new file mode 100644 index 0000000000..fd51211ccb --- /dev/null +++ b/zerocopy-derive/tests/ui-stable/derive_transparent.stderr @@ -0,0 +1,122 @@ +error[E0432]: unresolved import `self::util::NotAsBytes` + --> tests/ui-stable/derive_transparent.rs:11:18 + | +11 | use self::util::{NotAsBytes, AU16}; + | ^^^^^^^^^^ + | | + | no `NotAsBytes` in `util` + | help: a similar name exists in the module: `AsBytes` + +error[E0277]: the trait bound `NotAsBytes: AsBytes` is not satisfied + --> tests/ui-stable/../util.rs + | + | const _: fn($ty) -> IsAsBytes<$ty> = IsAsBytes::<$ty>; + | ^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotAsBytes` + | + ::: tests/ui-stable/derive_transparent.rs:33:1 + | +33 | assert_is_as_bytes!(TransparentStruct); + | -------------------------------------------------- in this macro invocation + | + = help: the following other types implement trait `AsBytes`: + () + AU16 + F32 + F64 + I128 + I16 + I32 + I64 + and $N others +note: required because of the requirements on the impl of `AsBytes` for `TransparentStruct` + --> tests/ui-stable/derive_transparent.rs:20:10 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^ +note: required by a bound in `IsAsBytes` + --> tests/ui-stable/../util.rs + | + | struct IsAsBytes(T); + | ^^^^^^^^^^^^^^^^^ required by this bound in `IsAsBytes` + | + ::: tests/ui-stable/derive_transparent.rs:33:1 + | +33 | assert_is_as_bytes!(TransparentStruct); + | -------------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_as_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `char: FromBytes` is not satisfied + --> tests/ui-stable/../util.rs + | + | const _: fn($ty) -> IsFromBytes<$ty> = IsFromBytes::<$ty>; + | ^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `char` + | + ::: tests/ui-stable/derive_transparent.rs:34:1 + | +34 | assert_is_from_bytes!(TransparentStruct); + | ---------------------------------------------- in this macro invocation + | + = help: the following other types implement trait `FromBytes`: + () + F32 + F64 + I128 + I16 + I32 + I64 + MaybeUninit + and $N others +note: required because of the requirements on the impl of `FromBytes` for `TransparentStruct` + --> tests/ui-stable/derive_transparent.rs:20:19 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `IsFromBytes` + --> tests/ui-stable/../util.rs + | + | struct IsFromBytes(T); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `IsFromBytes` + | + ::: tests/ui-stable/derive_transparent.rs:34:1 + | +34 | assert_is_from_bytes!(TransparentStruct); + | ---------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_from_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui-stable/../util.rs + | + | const _: fn($ty) -> IsUnaligned<$ty> = IsUnaligned::<$ty>; + | ^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + ::: tests/ui-stable/derive_transparent.rs:35:1 + | +35 | assert_is_unaligned!(TransparentStruct); + | --------------------------------------------- in this macro invocation + | + = help: the following other types implement trait `Unaligned`: + () + F32 + F64 + I128 + I16 + I32 + I64 + PhantomData + and $N others +note: required because of the requirements on the impl of `Unaligned` for `TransparentStruct` + --> tests/ui-stable/derive_transparent.rs:20:30 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `IsUnaligned` + --> tests/ui-stable/../util.rs + | + | struct IsUnaligned(T); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `IsUnaligned` + | + ::: tests/ui-stable/derive_transparent.rs:35:1 + | +35 | assert_is_unaligned!(TransparentStruct); + | --------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui-stable/struct.stderr b/zerocopy-derive/tests/ui-stable/struct.stderr index 16fa32807e..aeff48be85 100644 --- a/zerocopy-derive/tests/ui-stable/struct.stderr +++ b/zerocopy-derive/tests/ui-stable/struct.stderr @@ -1,4 +1,4 @@ -error: unsupported on types with type parameters +error: unsupported on generic structs that are not repr(transparent) --> tests/ui-stable/struct.rs:19:10 | 19 | #[derive(AsBytes)] diff --git a/zerocopy-derive/tests/ui-stable/union.stderr b/zerocopy-derive/tests/ui-stable/union.stderr index 544d93b0a0..6671271d98 100644 --- a/zerocopy-derive/tests/ui-stable/union.stderr +++ b/zerocopy-derive/tests/ui-stable/union.stderr @@ -1,39 +1,39 @@ error: unsupported on types with type parameters - --> tests/ui-stable/union.rs:21:10 + --> tests/ui-stable/union.rs:20:10 | -21 | #[derive(AsBytes)] +20 | #[derive(AsBytes)] | ^^^^^^^ | = 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/union.rs:39:11 + --> tests/ui-stable/union.rs:38:11 | -39 | #[repr(C, align(2))] +38 | #[repr(C, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/union.rs:55:16 + --> tests/ui-stable/union.rs:54:16 | -55 | #[repr(packed, align(2))] +54 | #[repr(packed, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/union.rs:61:18 + --> tests/ui-stable/union.rs:60:18 | -61 | #[repr(align(1), align(2))] +60 | #[repr(align(1), align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/union.rs:67:8 + --> tests/ui-stable/union.rs:66:8 | -67 | #[repr(align(2), align(4))] +66 | #[repr(align(2), align(4))] | ^^^^^^^^ error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied - --> tests/ui-stable/union.rs:27:10 + --> tests/ui-stable/union.rs:26:10 | -27 | #[derive(AsBytes)] +26 | #[derive(AsBytes)] | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` | = help: the trait `ShouldBe` is implemented for `HasPadding` diff --git a/zerocopy-derive/tests/ui/derive_transparent.rs b/zerocopy-derive/tests/ui/derive_transparent.rs new file mode 100644 index 0000000000..294072eb16 --- /dev/null +++ b/zerocopy-derive/tests/ui/derive_transparent.rs @@ -0,0 +1,35 @@ +// Copyright 2019 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +extern crate zerocopy; + +#[path = "../util.rs"] +#[macro_use] +mod util; + +use self::util::{NotAsBytes, AU16}; + +fn main() {} + +use core::marker::PhantomData; +use zerocopy::{AsBytes, FromBytes, Unaligned}; + +// Test generic transparent structs + +#[derive(AsBytes, FromBytes, Unaligned)] +#[repr(transparent)] +struct TransparentStruct { + inner: T, + _phantom: PhantomData<()>, +} + +// A type that does not implement `AsBytes`. +pub struct NotAsBytes; + +// It should be legal to derive these traits on a transparent struct, but it +// must also ensure the traits are only implemented when the inner type +// implements them. +assert_is_as_bytes!(TransparentStruct); +assert_is_from_bytes!(TransparentStruct); +assert_is_unaligned!(TransparentStruct); diff --git a/zerocopy-derive/tests/ui/derive_transparent.stderr b/zerocopy-derive/tests/ui/derive_transparent.stderr new file mode 100644 index 0000000000..d23896cd8e --- /dev/null +++ b/zerocopy-derive/tests/ui/derive_transparent.stderr @@ -0,0 +1,122 @@ +error[E0432]: unresolved import `self::util::NotAsBytes` + --> tests/ui/derive_transparent.rs:11:18 + | +11 | use self::util::{NotAsBytes, AU16}; + | ^^^^^^^^^^ + | | + | no `NotAsBytes` in `util` + | help: a similar name exists in the module: `AsBytes` + +error[E0277]: the trait bound `NotAsBytes: AsBytes` is not satisfied + --> tests/ui/../util.rs + | + | const _: fn($ty) -> IsAsBytes<$ty> = IsAsBytes::<$ty>; + | ^^^^^^^^^^^^^^ the trait `AsBytes` is not implemented for `NotAsBytes` + | + ::: tests/ui/derive_transparent.rs:33:1 + | +33 | assert_is_as_bytes!(TransparentStruct); + | -------------------------------------------------- in this macro invocation + | + = help: the following other types implement trait `AsBytes`: + () + AU16 + F32 + F64 + I128 + I16 + I32 + I64 + and $N others +note: required for `TransparentStruct` to implement `AsBytes` + --> tests/ui/derive_transparent.rs:20:10 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^ +note: required by a bound in `IsAsBytes` + --> tests/ui/../util.rs + | + | struct IsAsBytes(T); + | ^^^^^^^^^^^^^^^^^ required by this bound in `IsAsBytes` + | + ::: tests/ui/derive_transparent.rs:33:1 + | +33 | assert_is_as_bytes!(TransparentStruct); + | -------------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_as_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `char: FromBytes` is not satisfied + --> tests/ui/../util.rs + | + | const _: fn($ty) -> IsFromBytes<$ty> = IsFromBytes::<$ty>; + | ^^^^^^^^^^^^^^^^ the trait `FromBytes` is not implemented for `char` + | + ::: tests/ui/derive_transparent.rs:34:1 + | +34 | assert_is_from_bytes!(TransparentStruct); + | ---------------------------------------------- in this macro invocation + | + = help: the following other types implement trait `FromBytes`: + () + F32 + F64 + I128 + I16 + I32 + I64 + MaybeUninit + and $N others +note: required for `TransparentStruct` to implement `FromBytes` + --> tests/ui/derive_transparent.rs:20:19 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `IsFromBytes` + --> tests/ui/../util.rs + | + | struct IsFromBytes(T); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `IsFromBytes` + | + ::: tests/ui/derive_transparent.rs:34:1 + | +34 | assert_is_from_bytes!(TransparentStruct); + | ---------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_from_bytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the trait bound `AU16: Unaligned` is not satisfied + --> tests/ui/../util.rs + | + | const _: fn($ty) -> IsUnaligned<$ty> = IsUnaligned::<$ty>; + | ^^^^^^^^^^^^^^^^ the trait `Unaligned` is not implemented for `AU16` + | + ::: tests/ui/derive_transparent.rs:35:1 + | +35 | assert_is_unaligned!(TransparentStruct); + | --------------------------------------------- in this macro invocation + | + = help: the following other types implement trait `Unaligned`: + () + F32 + F64 + I128 + I16 + I32 + I64 + PhantomData + and $N others +note: required for `TransparentStruct` to implement `Unaligned` + --> tests/ui/derive_transparent.rs:20:30 + | +20 | #[derive(AsBytes, FromBytes, Unaligned)] + | ^^^^^^^^^ +note: required by a bound in `IsUnaligned` + --> tests/ui/../util.rs + | + | struct IsUnaligned(T); + | ^^^^^^^^^^^^^^^^^^^ required by this bound in `IsUnaligned` + | + ::: tests/ui/derive_transparent.rs:35:1 + | +35 | assert_is_unaligned!(TransparentStruct); + | --------------------------------------------- in this macro invocation + = note: this error originates in the macro `assert_is_unaligned` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/zerocopy-derive/tests/ui/late_compile_pass.rs b/zerocopy-derive/tests/ui/late_compile_pass.rs index 344c8c4080..bdd91e0a88 100644 --- a/zerocopy-derive/tests/ui/late_compile_pass.rs +++ b/zerocopy-derive/tests/ui/late_compile_pass.rs @@ -8,7 +8,7 @@ extern crate zerocopy; #[path = "../util.rs"] mod util; -use crate::util::AU16; +use self::util::AU16; fn main() {} diff --git a/zerocopy-derive/tests/ui/struct.rs b/zerocopy-derive/tests/ui/struct.rs index 0fcc15601a..29aa0e8665 100644 --- a/zerocopy-derive/tests/ui/struct.rs +++ b/zerocopy-derive/tests/ui/struct.rs @@ -8,7 +8,7 @@ extern crate zerocopy; #[path = "../util.rs"] mod util; -use crate::util::AU16; +use self::util::AU16; fn main() {} diff --git a/zerocopy-derive/tests/ui/struct.stderr b/zerocopy-derive/tests/ui/struct.stderr index e93a94540e..c856e8d6d6 100644 --- a/zerocopy-derive/tests/ui/struct.stderr +++ b/zerocopy-derive/tests/ui/struct.stderr @@ -1,4 +1,4 @@ -error: unsupported on types with type parameters +error: unsupported on generic structs that are not repr(transparent) --> tests/ui/struct.rs:19:10 | 19 | #[derive(AsBytes)] diff --git a/zerocopy-derive/tests/ui/union.rs b/zerocopy-derive/tests/ui/union.rs index d92ae50e2b..e7761e0e30 100644 --- a/zerocopy-derive/tests/ui/union.rs +++ b/zerocopy-derive/tests/ui/union.rs @@ -8,10 +8,9 @@ extern crate zerocopy; #[path = "../util.rs"] mod util; +use self::util::AU16; use std::mem::ManuallyDrop; -use crate::util::AU16; - fn main() {} // diff --git a/zerocopy-derive/tests/ui/union.stderr b/zerocopy-derive/tests/ui/union.stderr index 2f7de1b12e..81f64939fb 100644 --- a/zerocopy-derive/tests/ui/union.stderr +++ b/zerocopy-derive/tests/ui/union.stderr @@ -1,39 +1,39 @@ error: unsupported on types with type parameters - --> tests/ui/union.rs:21:10 + --> tests/ui/union.rs:20:10 | -21 | #[derive(AsBytes)] +20 | #[derive(AsBytes)] | ^^^^^^^ | = 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/union.rs:39:11 + --> tests/ui/union.rs:38:11 | -39 | #[repr(C, align(2))] +38 | #[repr(C, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui/union.rs:55:16 + --> tests/ui/union.rs:54:16 | -55 | #[repr(packed, align(2))] +54 | #[repr(packed, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui/union.rs:61:18 + --> tests/ui/union.rs:60:18 | -61 | #[repr(align(1), align(2))] +60 | #[repr(align(1), align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui/union.rs:67:8 + --> tests/ui/union.rs:66:8 | -67 | #[repr(align(2), align(4))] +66 | #[repr(align(2), align(4))] | ^^^^^^^^ error[E0277]: the trait bound `HasPadding: ShouldBe` is not satisfied - --> tests/ui/union.rs:27:10 + --> tests/ui/union.rs:26:10 | -27 | #[derive(AsBytes)] +26 | #[derive(AsBytes)] | ^^^^^^^ the trait `ShouldBe` is not implemented for `HasPadding` | = help: the trait `ShouldBe` is implemented for `HasPadding` diff --git a/zerocopy-derive/tests/union_as_bytes.rs b/zerocopy-derive/tests/union_as_bytes.rs index fd848cc0b5..7195133ed8 100644 --- a/zerocopy-derive/tests/union_as_bytes.rs +++ b/zerocopy-derive/tests/union_as_bytes.rs @@ -4,21 +4,12 @@ #![allow(warnings)] -use std::{marker::PhantomData, option::IntoIter}; +#[macro_use] +mod util; +use std::{marker::PhantomData, option::IntoIter}; use zerocopy::AsBytes; -struct IsAsBytes(T); - -// Fail compilation if `$ty: !AsBytes`. -macro_rules! is_as_bytes { - ($ty:ty) => { - const _: () = { - let _: IsAsBytes<$ty>; - }; - }; -} - // A union is `AsBytes` if: // - all fields are `AsBytes` // - `repr(C)` or `repr(transparent)` and @@ -31,7 +22,7 @@ union CZst { a: (), } -is_as_bytes!(CZst); +assert_is_as_bytes!(CZst); #[derive(AsBytes)] #[repr(C)] @@ -40,7 +31,7 @@ union C { b: u8, } -is_as_bytes!(C); +assert_is_as_bytes!(C); // Transparent unions are unstable; see issue #60405 // for more information. @@ -60,7 +51,7 @@ union CZstPacked { a: (), } -is_as_bytes!(CZstPacked); +assert_is_as_bytes!(CZstPacked); #[derive(AsBytes)] #[repr(C, packed)] @@ -69,7 +60,7 @@ union CPacked { b: i8, } -is_as_bytes!(CPacked); +assert_is_as_bytes!(CPacked); #[derive(AsBytes)] #[repr(C, packed)] @@ -79,4 +70,4 @@ union CMultibytePacked { c: f32, } -is_as_bytes!(CMultibytePacked); +assert_is_as_bytes!(CMultibytePacked); diff --git a/zerocopy-derive/tests/union_from_bytes.rs b/zerocopy-derive/tests/union_from_bytes.rs index ef6d403f75..22a3e3eb88 100644 --- a/zerocopy-derive/tests/union_from_bytes.rs +++ b/zerocopy-derive/tests/union_from_bytes.rs @@ -4,21 +4,12 @@ #![allow(warnings)] -use std::{marker::PhantomData, option::IntoIter}; +#[macro_use] +mod util; +use std::{marker::PhantomData, option::IntoIter}; use zerocopy::FromBytes; -struct IsFromBytes(T); - -// Fail compilation if `$ty: !FromBytes`. -macro_rules! is_from_bytes { - ($ty:ty) => { - const _: () = { - let _: IsFromBytes<$ty>; - }; - }; -} - // A union is `FromBytes` if: // - all fields are `FromBytes` @@ -27,14 +18,14 @@ union Zst { a: (), } -is_from_bytes!(Zst); +assert_is_from_bytes!(Zst); #[derive(FromBytes)] union One { a: u8, } -is_from_bytes!(One); +assert_is_from_bytes!(One); #[derive(FromBytes)] union Two { @@ -42,7 +33,7 @@ union Two { b: Zst, } -is_from_bytes!(Two); +assert_is_from_bytes!(Two); #[derive(FromBytes)] union TypeParams<'a, T: Copy, I: Iterator> @@ -57,4 +48,4 @@ where g: PhantomData, } -is_from_bytes!(TypeParams<'static, (), IntoIter<()>>); +assert_is_from_bytes!(TypeParams<'static, (), IntoIter<()>>); diff --git a/zerocopy-derive/tests/union_unaligned.rs b/zerocopy-derive/tests/union_unaligned.rs index d3474d22f3..1d552ac88a 100644 --- a/zerocopy-derive/tests/union_unaligned.rs +++ b/zerocopy-derive/tests/union_unaligned.rs @@ -4,21 +4,12 @@ #![allow(warnings)] -use std::{marker::PhantomData, option::IntoIter}; +#[macro_use] +mod util; +use std::{marker::PhantomData, option::IntoIter}; use zerocopy::Unaligned; -struct IsUnaligned(T); - -// Fail compilation if `$ty: !Unaligned`. -macro_rules! is_unaligned { - ($ty:ty) => { - const _: () = { - let _: IsUnaligned<$ty>; - }; - }; -} - // A union is `Unaligned` if: // - `repr(align)` is no more than 1 and either // - `repr(C)` or `repr(transparent)` and @@ -31,7 +22,7 @@ union Foo { a: u8, } -is_unaligned!(Foo); +assert_is_unaligned!(Foo); // Transparent unions are unstable; see issue #60405 // for more information. @@ -57,7 +48,7 @@ union Baz { a: u16, } -is_unaligned!(Baz); +assert_is_unaligned!(Baz); #[derive(Unaligned)] #[repr(C, align(1))] @@ -65,7 +56,7 @@ union FooAlign { a: u8, } -is_unaligned!(FooAlign); +assert_is_unaligned!(FooAlign); #[derive(Unaligned)] #[repr(C)] @@ -81,4 +72,4 @@ where g: PhantomData, } -is_unaligned!(TypeParams<'static, (), IntoIter<()>>); +assert_is_unaligned!(TypeParams<'static, (), IntoIter<()>>); diff --git a/zerocopy-derive/tests/util.rs b/zerocopy-derive/tests/util.rs index 6c588ea5d3..ce91d24b05 100644 --- a/zerocopy-derive/tests/util.rs +++ b/zerocopy-derive/tests/util.rs @@ -11,3 +11,33 @@ use zerocopy::AsBytes; #[derive(AsBytes, Copy, Clone)] #[repr(C, align(2))] pub struct AU16(u16); + +#[allow(unused_macros)] +macro_rules! assert_is_as_bytes { + ($ty:ty) => { + const _: () = { + struct IsAsBytes(T); + const _: fn($ty) -> IsAsBytes<$ty> = IsAsBytes::<$ty>; + }; + }; +} + +#[allow(unused_macros)] +macro_rules! assert_is_from_bytes { + ($ty:ty) => { + const _: () = { + struct IsFromBytes(T); + const _: fn($ty) -> IsFromBytes<$ty> = IsFromBytes::<$ty>; + }; + }; +} + +#[allow(unused_macros)] +macro_rules! assert_is_unaligned { + ($ty:ty) => { + const _: () = { + struct IsUnaligned(T); + const _: fn($ty) -> IsUnaligned<$ty> = IsUnaligned::<$ty>; + }; + }; +}