From 553996e661d49370e4ee73a992602b6f856b64a8 Mon Sep 17 00:00:00 2001 From: Joshua Liebow-Feeser Date: Sat, 21 Sep 2024 06:38:08 -0700 Subject: [PATCH] Improve IntoBytes derive error message (#1713) Closes #1708 --- src/util/macro_util.rs | 36 +++++++++-- zerocopy-derive/tests/ui-msrv/struct.stderr | 56 +++++++++++++---- zerocopy-derive/tests/ui-nightly/struct.rs | 9 +++ .../tests/ui-nightly/struct.stderr | 63 ++++++++++++++----- zerocopy-derive/tests/ui-stable/struct.stderr | 63 ++++++++++++++----- 5 files changed, 182 insertions(+), 45 deletions(-) diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 26257ea718..10d98affe0 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -285,6 +285,32 @@ mod size_to_tag { #[doc(hidden)] pub type SizeToTag = <() as size_to_tag::SizeToTag>::Tag; +// We put `Sized` in its own module so it can have the same name as the standard +// library `Sized` without shadowing it in the parent module. +#[cfg(zerocopy_diagnostic_on_unimplemented)] +mod __size_of { + #[diagnostic::on_unimplemented( + message = "`{Self}` is unsized", + label = "`IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding", + note = "consider using `#[repr(packed)]` to remove inter-field padding", + note = "`IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized`" + )] + pub trait Sized: core::marker::Sized {} + impl Sized for T {} + + #[inline(always)] + #[must_use] + #[allow(clippy::needless_maybe_sized)] + pub const fn size_of() -> usize { + core::mem::size_of::() + } +} + +#[cfg(zerocopy_diagnostic_on_unimplemented)] +pub use __size_of::size_of; +#[cfg(not(zerocopy_diagnostic_on_unimplemented))] +pub use core::mem::size_of; + /// Does the struct type `$t` have padding? /// /// `$ts` is the list of the type of every field in `$t`. `$t` must be a @@ -301,7 +327,7 @@ pub type SizeToTag = <() as size_to_tag::SizeToTag>::Ta #[macro_export] macro_rules! struct_has_padding { ($t:ty, [$($ts:ty),*]) => { - ::zerocopy::util::macro_util::core_reexport::mem::size_of::<$t>() > 0 $(+ ::zerocopy::util::macro_util::core_reexport::mem::size_of::<$ts>())* + ::zerocopy::util::macro_util::size_of::<$t>() > 0 $(+ ::zerocopy::util::macro_util::size_of::<$ts>())* }; } @@ -321,7 +347,7 @@ macro_rules! struct_has_padding { #[macro_export] macro_rules! union_has_padding { ($t:ty, [$($ts:ty),*]) => { - false $(|| ::zerocopy::util::macro_util::core_reexport::mem::size_of::<$t>() != ::zerocopy::util::macro_util::core_reexport::mem::size_of::<$ts>())* + false $(|| ::zerocopy::util::macro_util::size_of::<$t>() != ::zerocopy::util::macro_util::size_of::<$ts>())* }; } @@ -346,10 +372,10 @@ macro_rules! union_has_padding { macro_rules! enum_has_padding { ($t:ty, $disc:ty, $([$($ts:ty),*]),*) => { false $( - || ::zerocopy::util::macro_util::core_reexport::mem::size_of::<$t>() + || ::zerocopy::util::macro_util::size_of::<$t>() != ( - ::zerocopy::util::macro_util::core_reexport::mem::size_of::<$disc>() - $(+ ::zerocopy::util::macro_util::core_reexport::mem::size_of::<$ts>())* + ::zerocopy::util::macro_util::size_of::<$disc>() + $(+ ::zerocopy::util::macro_util::size_of::<$ts>())* ) )* } diff --git a/zerocopy-derive/tests/ui-msrv/struct.stderr b/zerocopy-derive/tests/ui-msrv/struct.stderr index cea80844e0..60eb7e7168 100644 --- a/zerocopy-derive/tests/ui-msrv/struct.stderr +++ b/zerocopy-derive/tests/ui-msrv/struct.stderr @@ -1,37 +1,37 @@ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/struct.rs:128:11 + --> tests/ui-msrv/struct.rs:137:11 | -128 | #[repr(C, align(2))] +137 | #[repr(C, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/struct.rs:132:21 + --> tests/ui-msrv/struct.rs:141:21 | -132 | #[repr(transparent, align(2))] +141 | #[repr(transparent, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/struct.rs:138:16 + --> tests/ui-msrv/struct.rs:147:16 | -138 | #[repr(packed, align(2))] +147 | #[repr(packed, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/struct.rs:142:18 + --> tests/ui-msrv/struct.rs:151:18 | -142 | #[repr(align(1), align(2))] +151 | #[repr(align(1), align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-msrv/struct.rs:146:8 + --> tests/ui-msrv/struct.rs:155:8 | -146 | #[repr(align(2), align(4))] +155 | #[repr(align(2), align(4))] | ^^^^^^^^ error[E0692]: transparent struct cannot have other repr hints - --> tests/ui-msrv/struct.rs:132:8 + --> tests/ui-msrv/struct.rs:141:8 | -132 | #[repr(transparent, align(2))] +141 | #[repr(transparent, align(2))] | ^^^^^^^^^^^ ^^^^^^^^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -131,3 +131,35 @@ error[E0277]: the trait bound `HasPadding: ShouldBe` is as ShouldBe> = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/struct.rs:125:10 + | +125 | #[derive(IntoBytes)] + | ^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `IntoBytes4` + --> tests/ui-msrv/struct.rs:127:8 + | +127 | struct IntoBytes4 { + | ^^^^^^^^^^ +note: required by a bound in `std::mem::size_of` + --> $RUST/core/src/mem/mod.rs + | + | pub const fn size_of() -> usize { + | ^ required by this bound in `std::mem::size_of` + = note: this error originates in the macro `::zerocopy::struct_has_padding` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-msrv/struct.rs:129:8 + | +129 | b: [u8], + | ^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `[u8]` +note: required by a bound in `std::mem::size_of` + --> $RUST/core/src/mem/mod.rs + | + | pub const fn size_of() -> usize { + | ^ required by this bound in `std::mem::size_of` diff --git a/zerocopy-derive/tests/ui-nightly/struct.rs b/zerocopy-derive/tests/ui-nightly/struct.rs index 0c0b9a0313..e75fd59310 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.rs +++ b/zerocopy-derive/tests/ui-nightly/struct.rs @@ -120,6 +120,15 @@ struct IntoBytes3 { bar: u64, } +// NOTE(#1708): This exists to ensure that our error messages are good when a +// field is unsized. +#[derive(IntoBytes)] +#[repr(C)] +struct IntoBytes4 { + a: u8, + b: [u8], +} + // // Unaligned errors // diff --git a/zerocopy-derive/tests/ui-nightly/struct.stderr b/zerocopy-derive/tests/ui-nightly/struct.stderr index aec3d5d543..7ecabd3d3c 100644 --- a/zerocopy-derive/tests/ui-nightly/struct.stderr +++ b/zerocopy-derive/tests/ui-nightly/struct.stderr @@ -1,37 +1,37 @@ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-nightly/struct.rs:128:11 + --> tests/ui-nightly/struct.rs:137:11 | -128 | #[repr(C, align(2))] +137 | #[repr(C, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-nightly/struct.rs:132:21 + --> tests/ui-nightly/struct.rs:141:21 | -132 | #[repr(transparent, align(2))] +141 | #[repr(transparent, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-nightly/struct.rs:138:16 + --> tests/ui-nightly/struct.rs:147:16 | -138 | #[repr(packed, align(2))] +147 | #[repr(packed, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-nightly/struct.rs:142:18 + --> tests/ui-nightly/struct.rs:151:18 | -142 | #[repr(align(1), align(2))] +151 | #[repr(align(1), align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-nightly/struct.rs:146:8 + --> tests/ui-nightly/struct.rs:155:8 | -146 | #[repr(align(2), align(4))] +155 | #[repr(align(2), align(4))] | ^^^^^^^^ error[E0692]: transparent struct cannot have other repr hints - --> tests/ui-nightly/struct.rs:132:8 + --> tests/ui-nightly/struct.rs:141:8 | -132 | #[repr(transparent, align(2))] +141 | #[repr(transparent, align(2))] | ^^^^^^^^^^^ ^^^^^^^^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -269,8 +269,43 @@ help: add `#![feature(trivial_bounds)]` to the crate attributes to enable 9 + #![feature(trivial_bounds)] | +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-nightly/struct.rs:127:8 + | +127 | struct IntoBytes4 { + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]`, which is required by `IntoBytes4: macro_util::__size_of::Sized` +note: required because it appears within the type `IntoBytes4` + --> tests/ui-nightly/struct.rs:127:8 + | +127 | struct IntoBytes4 { + | ^^^^^^^^^^ + = note: required for `IntoBytes4` to implement `macro_util::__size_of::Sized` +note: required by a bound in `macro_util::__size_of::size_of` + --> $WORKSPACE/src/util/macro_util.rs + | + | pub const fn size_of() -> usize { + | ^^^^^ required by this bound in `size_of` + +error[E0277]: `[u8]` is unsized + --> tests/ui-nightly/struct.rs:129:8 + | +129 | b: [u8], + | ^^^^ `IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding + | + = help: the trait `Sized` is not implemented for `[u8]`, which is required by `[u8]: macro_util::__size_of::Sized` + = note: consider using `#[repr(packed)]` to remove inter-field padding + = note: `IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized` + = note: required for `[u8]` to implement `macro_util::__size_of::Sized` +note: required by a bound in `macro_util::__size_of::size_of` + --> $WORKSPACE/src/util/macro_util.rs + | + | pub const fn size_of() -> usize { + | ^^^^^ required by this bound in `size_of` + error[E0587]: type has conflicting packed and align representation hints - --> tests/ui-nightly/struct.rs:139:1 + --> tests/ui-nightly/struct.rs:148:1 | -139 | struct Unaligned3; +148 | struct Unaligned3; | ^^^^^^^^^^^^^^^^^ diff --git a/zerocopy-derive/tests/ui-stable/struct.stderr b/zerocopy-derive/tests/ui-stable/struct.stderr index b02a6859ec..c3ba2b7d39 100644 --- a/zerocopy-derive/tests/ui-stable/struct.stderr +++ b/zerocopy-derive/tests/ui-stable/struct.stderr @@ -1,37 +1,37 @@ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/struct.rs:128:11 + --> tests/ui-stable/struct.rs:137:11 | -128 | #[repr(C, align(2))] +137 | #[repr(C, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/struct.rs:132:21 + --> tests/ui-stable/struct.rs:141:21 | -132 | #[repr(transparent, align(2))] +141 | #[repr(transparent, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/struct.rs:138:16 + --> tests/ui-stable/struct.rs:147:16 | -138 | #[repr(packed, align(2))] +147 | #[repr(packed, align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/struct.rs:142:18 + --> tests/ui-stable/struct.rs:151:18 | -142 | #[repr(align(1), align(2))] +151 | #[repr(align(1), align(2))] | ^^^^^^^^ error: cannot derive Unaligned with repr(align(N > 1)) - --> tests/ui-stable/struct.rs:146:8 + --> tests/ui-stable/struct.rs:155:8 | -146 | #[repr(align(2), align(4))] +155 | #[repr(align(2), align(4))] | ^^^^^^^^ error[E0692]: transparent struct cannot have other repr hints - --> tests/ui-stable/struct.rs:132:8 + --> tests/ui-stable/struct.rs:141:8 | -132 | #[repr(transparent, align(2))] +141 | #[repr(transparent, align(2))] | ^^^^^^^^^^^ ^^^^^^^^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -233,8 +233,43 @@ error[E0277]: the trait bound `HasPadding: ShouldBe` is = help: see issue #48214 = note: this error originates in the derive macro `IntoBytes` (in Nightly builds, run with -Z macro-backtrace for more info) +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> tests/ui-stable/struct.rs:127:8 + | +127 | struct IntoBytes4 { + | ^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `IntoBytes4`, the trait `Sized` is not implemented for `[u8]`, which is required by `IntoBytes4: macro_util::__size_of::Sized` +note: required because it appears within the type `IntoBytes4` + --> tests/ui-stable/struct.rs:127:8 + | +127 | struct IntoBytes4 { + | ^^^^^^^^^^ + = note: required for `IntoBytes4` to implement `macro_util::__size_of::Sized` +note: required by a bound in `macro_util::__size_of::size_of` + --> $WORKSPACE/src/util/macro_util.rs + | + | pub const fn size_of() -> usize { + | ^^^^^ required by this bound in `size_of` + +error[E0277]: `[u8]` is unsized + --> tests/ui-stable/struct.rs:129:8 + | +129 | b: [u8], + | ^^^^ `IntoBytes` needs all field types to be `Sized` in order to determine whether there is inter-field padding + | + = help: the trait `Sized` is not implemented for `[u8]`, which is required by `[u8]: macro_util::__size_of::Sized` + = note: consider using `#[repr(packed)]` to remove inter-field padding + = note: `IntoBytes` does not require the fields of `#[repr(packed)]` types to be `Sized` + = note: required for `[u8]` to implement `macro_util::__size_of::Sized` +note: required by a bound in `macro_util::__size_of::size_of` + --> $WORKSPACE/src/util/macro_util.rs + | + | pub const fn size_of() -> usize { + | ^^^^^ required by this bound in `size_of` + error[E0587]: type has conflicting packed and align representation hints - --> tests/ui-stable/struct.rs:139:1 + --> tests/ui-stable/struct.rs:148:1 | -139 | struct Unaligned3; +148 | struct Unaligned3; | ^^^^^^^^^^^^^^^^^