Skip to content

Commit

Permalink
Improve IntoBytes derive error message (#1713)
Browse files Browse the repository at this point in the history
Closes #1708
  • Loading branch information
joshlf authored Sep 21, 2024
1 parent 0c4929d commit 553996e
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 45 deletions.
36 changes: 31 additions & 5 deletions src/util/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,32 @@ mod size_to_tag {
#[doc(hidden)]
pub type SizeToTag<const SIZE: usize> = <() as size_to_tag::SizeToTag<SIZE>>::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<T: core::marker::Sized> Sized for T {}

#[inline(always)]
#[must_use]
#[allow(clippy::needless_maybe_sized)]
pub const fn size_of<T: Sized + ?core::marker::Sized>() -> usize {
core::mem::size_of::<T>()
}
}

#[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
Expand All @@ -301,7 +327,7 @@ pub type SizeToTag<const SIZE: usize> = <() as size_to_tag::SizeToTag<SIZE>>::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>())*
};
}

Expand All @@ -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>())*
};
}

Expand All @@ -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>())*
)
)*
}
Expand Down
56 changes: 44 additions & 12 deletions zerocopy-derive/tests/ui-msrv/struct.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -131,3 +131,35 @@ error[E0277]: the trait bound `HasPadding<IntoBytes3, true>: ShouldBe<false>` is
<HasPadding<T, VALUE> as ShouldBe<VALUE>>
= 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<T>() -> 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<T>() -> usize {
| ^ required by this bound in `std::mem::size_of`
9 changes: 9 additions & 0 deletions zerocopy-derive/tests/ui-nightly/struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
//
Expand Down
63 changes: 49 additions & 14 deletions zerocopy-derive/tests/ui-nightly/struct.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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<T: Sized + ?core::marker::Sized>() -> 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<T: Sized + ?core::marker::Sized>() -> 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;
| ^^^^^^^^^^^^^^^^^
63 changes: 49 additions & 14 deletions zerocopy-derive/tests/ui-stable/struct.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -233,8 +233,43 @@ error[E0277]: the trait bound `HasPadding<IntoBytes3, true>: ShouldBe<false>` 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<T: Sized + ?core::marker::Sized>() -> 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<T: Sized + ?core::marker::Sized>() -> 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;
| ^^^^^^^^^^^^^^^^^

0 comments on commit 553996e

Please sign in to comment.