Skip to content

Commit

Permalink
[derive] Disable prelude when testing; fix bugs
Browse files Browse the repository at this point in the history
This has the effect of ensuring that derive-emitted code will fail to
compile if it spuriously relies on certain identifiers being in scope -
namely, identifiers which are part of the prelude.

Disabling the prelude surfaced a few bugs which are also fixed in this
commit.

Makes progress on #11
  • Loading branch information
joshlf committed Feb 16, 2024
1 parent d39a5d4 commit 952c674
Show file tree
Hide file tree
Showing 44 changed files with 981 additions and 945 deletions.
4 changes: 2 additions & 2 deletions src/macro_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ macro_rules! align_of {
#[macro_export]
macro_rules! struct_has_padding {
($t:ty, $($ts:ty),*) => {
core::mem::size_of::<$t>() > 0 $(+ core::mem::size_of::<$ts>())*
::zerocopy::macro_util::core_reexport::mem::size_of::<$t>() > 0 $(+ ::zerocopy::macro_util::core_reexport::mem::size_of::<$ts>())*
};
}

Expand All @@ -282,7 +282,7 @@ macro_rules! struct_has_padding {
#[macro_export]
macro_rules! union_has_padding {
($t:ty, $($ts:ty),*) => {
false $(|| core::mem::size_of::<$t>() != core::mem::size_of::<$ts>())*
false $(|| ::zerocopy::macro_util::core_reexport::mem::size_of::<$t>() != ::zerocopy::macro_util::core_reexport::mem::size_of::<$ts>())*
};
}

Expand Down
21 changes: 11 additions & 10 deletions zerocopy-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
let (_name, trailing_field_ty) = trailing_field;
let leading_fields_tys = leading_fields.iter().map(|(_name, ty)| ty);

let core_path = quote!(::zerocopy::macro_util::core_reexport);
let repr_align = reprs
.iter()
.find_map(
Expand All @@ -107,8 +108,8 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
}
},
)
.map(|repr_align| quote!(NonZeroUsize::new(#repr_align as usize)))
.unwrap_or(quote!(None));
.map(|repr_align| quote!(#core_path::num::NonZeroUsize::new(#repr_align as usize)))
.unwrap_or(quote!(#core_path::option::Option::None));

let repr_packed = reprs
.iter()
Expand All @@ -117,8 +118,8 @@ pub fn derive_known_layout(ts: proc_macro::TokenStream) -> proc_macro::TokenStre
Repr::PackedN(repr_packed) => Some(*repr_packed),
_ => None,
})
.map(|repr_packed| quote!(NonZeroUsize::new(#repr_packed as usize)))
.unwrap_or(quote!(None));
.map(|repr_packed| quote!(#core_path::num::NonZeroUsize::new(#repr_packed as usize)))
.unwrap_or(quote!(#core_path::option::Option::None));

(
SelfBounds::None,
Expand Down Expand Up @@ -358,18 +359,18 @@ fn derive_try_from_bytes_struct(ast: &DeriveInput, strct: &DataStruct) -> proc_m
// validity of a struct is just the composition of the bit
// validities of its fields, so this is a sound implementation of
// `is_bit_valid`.
fn is_bit_valid(candidate: zerocopy::Maybe<Self>) -> bool {
fn is_bit_valid(candidate: ::zerocopy::Maybe<Self>) -> bool {
true #(&& {
// SAFETY: `project` is a field projection of `candidate`,
// and `Self` is a struct type.
let field_candidate = unsafe {
let project = |slf: *mut Self|
::core::ptr::addr_of_mut!((*slf).#field_names);
::zerocopy::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names);

candidate.project(project)
};

<#field_tys as zerocopy::TryFromBytes>::is_bit_valid(field_candidate)
<#field_tys as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate)
})*
}
)
Expand Down Expand Up @@ -399,18 +400,18 @@ fn derive_try_from_bytes_union(ast: &DeriveInput, unn: &DataUnion) -> proc_macro
// bit validity of a union is not yet well defined in Rust, but it
// is guaranteed to be no more strict than this definition. See #696
// for a more in-depth discussion.
fn is_bit_valid(candidate: zerocopy::Maybe<Self>) -> bool {
fn is_bit_valid(candidate: ::zerocopy::Maybe<Self>) -> bool {
false #(|| {
// SAFETY: `project` is a field projection of `candidate`,
// and `Self` is a union type.
let field_candidate = unsafe {
let project = |slf: *mut Self|
::core::ptr::addr_of_mut!((*slf).#field_names);
::zerocopy::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names);

candidate.project(project)
};

<#field_tys as zerocopy::TryFromBytes>::is_bit_valid(field_candidate)
<#field_tys as ::zerocopy::TryFromBytes>::is_bit_valid(field_candidate)
})*
}
)
Expand Down
33 changes: 15 additions & 18 deletions zerocopy-derive/tests/enum_from_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,11 @@
// This file may not be copied, modified, or distributed except according to
// those terms.

// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]

mod util;

use {
static_assertions::assert_impl_all,
zerocopy::{FromBytes, FromZeros},
};
include!("include.rs");

// An enum is `FromBytes` if:
// - `repr(uN)` or `repr(iN)`
Expand All @@ -32,7 +29,7 @@ use {
// `Variant128` has a discriminant of -128) since Rust won't automatically wrap
// a signed discriminant around without you explicitly telling it to.

#[derive(FromZeros, FromBytes)]
#[derive(imp::FromZeros, imp::FromBytes)]
#[repr(u8)]
enum FooU8 {
Variant0,
Expand Down Expand Up @@ -293,9 +290,9 @@ enum FooU8 {
Variant255,
}

assert_impl_all!(FooU8: FromBytes);
util_assert_impl_all!(FooU8: imp::FromBytes);

#[derive(FromZeros, FromBytes)]
#[derive(imp::FromZeros, imp::FromBytes)]
#[repr(i8)]
enum FooI8 {
Variant0,
Expand Down Expand Up @@ -556,9 +553,9 @@ enum FooI8 {
Variant255,
}

assert_impl_all!(FooI8: FromBytes);
util_assert_impl_all!(FooI8: imp::FromBytes);

#[derive(FromZeros, FromBytes)]
#[derive(imp::FromZeros, imp::FromBytes)]
#[repr(u8, align(2))]
enum FooU8Align {
Variant0,
Expand Down Expand Up @@ -819,9 +816,9 @@ enum FooU8Align {
Variant255,
}

assert_impl_all!(FooU8Align: FromBytes);
util_assert_impl_all!(FooU8Align: imp::FromBytes);

#[derive(FromZeros, FromBytes)]
#[derive(imp::FromZeros, imp::FromBytes)]
#[repr(i8, align(2))]
enum FooI8Align {
Variant0,
Expand Down Expand Up @@ -1082,9 +1079,9 @@ enum FooI8Align {
Variant255,
}

assert_impl_all!(FooI8Align: FromBytes);
util_assert_impl_all!(FooI8Align: imp::FromBytes);

#[derive(FromZeros, FromBytes)]
#[derive(imp::FromZeros, imp::FromBytes)]
#[repr(u16)]
enum FooU16 {
Variant0,
Expand Down Expand Up @@ -66625,9 +66622,9 @@ enum FooU16 {
Variant65535,
}

assert_impl_all!(FooU16: FromBytes);
util_assert_impl_all!(FooU16: imp::FromBytes);

#[derive(FromZeros, FromBytes)]
#[derive(imp::FromZeros, imp::FromBytes)]
#[repr(i16)]
enum FooI16 {
Variant0,
Expand Down Expand Up @@ -132168,4 +132165,4 @@ enum FooI16 {
Variant65535,
}

assert_impl_all!(FooI16: FromBytes);
util_assert_impl_all!(FooI16: imp::FromBytes);
18 changes: 9 additions & 9 deletions zerocopy-derive/tests/enum_from_zeros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,33 @@
// This file may not be copied, modified, or distributed except according to
// those terms.

// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]

mod util;
include!("include.rs");

use {static_assertions::assert_impl_all, zerocopy::FromZeros};

#[derive(FromZeros)]
#[derive(imp::FromZeros)]
#[repr(C)]
enum Foo {
A,
}

assert_impl_all!(Foo: FromZeros);
util_assert_impl_all!(Foo: imp::FromZeros);

#[derive(FromZeros)]
#[derive(imp::FromZeros)]
#[repr(C)]
enum Bar {
A = 0,
}

assert_impl_all!(Bar: FromZeros);
util_assert_impl_all!(Bar: imp::FromZeros);

#[derive(FromZeros)]
#[derive(imp::FromZeros)]
#[repr(C)]
enum Baz {
A = 1,
B = 0,
}

assert_impl_all!(Baz: FromZeros);
util_assert_impl_all!(Baz: imp::FromZeros);
28 changes: 14 additions & 14 deletions zerocopy-derive/tests/enum_known_layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,45 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]

mod util;
include!("include.rs");

use {core::marker::PhantomData, static_assertions::assert_impl_all, zerocopy::KnownLayout};

#[derive(KnownLayout)]
#[derive(imp::KnownLayout)]
enum Foo {
A,
}

assert_impl_all!(Foo: KnownLayout);
util_assert_impl_all!(Foo: imp::KnownLayout);

#[derive(KnownLayout)]
#[derive(imp::KnownLayout)]
enum Bar {
A = 0,
}

assert_impl_all!(Bar: KnownLayout);
util_assert_impl_all!(Bar: imp::KnownLayout);

#[derive(KnownLayout)]
#[derive(imp::KnownLayout)]
enum Baz {
A = 1,
B = 0,
}

assert_impl_all!(Baz: KnownLayout);
util_assert_impl_all!(Baz: imp::KnownLayout);

// Deriving `KnownLayout` should work if the enum has bounded parameters.

#[derive(KnownLayout)]
#[derive(imp::KnownLayout)]
#[repr(C)]
enum WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + KnownLayout, const N: usize>
enum WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::KnownLayout, const N: usize>
where
'a: 'b,
'b: 'a,
T: 'a + 'b + KnownLayout,
T: 'a + 'b + imp::KnownLayout,
{
Variant([T; N], PhantomData<&'a &'b ()>),
Variant([T; N], imp::PhantomData<&'a &'b ()>),
}

assert_impl_all!(WithParams<'static, 'static, u8, 42>: KnownLayout);
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::KnownLayout);
33 changes: 15 additions & 18 deletions zerocopy-derive/tests/enum_no_cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,46 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// See comment in `include.rs` for why we disable the prelude.
#![no_implicit_prelude]
#![allow(warnings)]

mod util;
include!("include.rs");

use {
core::cell::UnsafeCell, core::marker::PhantomData, static_assertions::assert_impl_all,
zerocopy::NoCell,
};

#[derive(NoCell)]
#[derive(imp::NoCell)]
enum Foo {
A,
}

assert_impl_all!(Foo: NoCell);
util_assert_impl_all!(Foo: imp::NoCell);

#[derive(NoCell)]
#[derive(imp::NoCell)]
enum Bar {
A = 0,
}

assert_impl_all!(Bar: NoCell);
util_assert_impl_all!(Bar: imp::NoCell);

#[derive(NoCell)]
#[derive(imp::NoCell)]
enum Baz {
A = 1,
B = 0,
}

assert_impl_all!(Baz: NoCell);
util_assert_impl_all!(Baz: imp::NoCell);

// Deriving `NoCell` should work if the enum has bounded parameters.

#[derive(NoCell)]
#[derive(imp::NoCell)]
#[repr(C)]
enum WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + NoCell, const N: usize>
enum WithParams<'a: 'b, 'b: 'a, T: 'a + 'b + imp::NoCell, const N: ::core::primitive::usize>
where
'a: 'b,
'b: 'a,
T: 'a + 'b + NoCell,
T: 'a + 'b + imp::NoCell,
{
Variant([T; N], PhantomData<&'a &'b ()>),
UnsafeCell(PhantomData<UnsafeCell<()>>, &'a UnsafeCell<()>),
Variant([T; N], imp::PhantomData<&'a &'b ()>),
UnsafeCell(imp::PhantomData<imp::UnsafeCell<()>>, &'a imp::UnsafeCell<()>),
}

assert_impl_all!(WithParams<'static, 'static, u8, 42>: NoCell);
util_assert_impl_all!(WithParams<'static, 'static, u8, 42>: imp::NoCell);
Loading

0 comments on commit 952c674

Please sign in to comment.