Skip to content

Commit 2182b96

Browse files
authored
Implement FromZeroes for Option<[extern "C"] fn()> (#600)
1 parent 0f95209 commit 2182b96

File tree

2 files changed

+71
-6
lines changed

2 files changed

+71
-6
lines changed

src/lib.rs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1915,12 +1915,13 @@ safety_comment! {
19151915
/// size_of::<T>()])` is sound and produces `Option::<T>::None`. These
19161916
/// cases are identified by the second column:
19171917
///
1918-
/// | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
1919-
/// |---------------------|-----------------------------------------------------------|
1920-
/// | [`Box<U>`] | when `U: Sized` |
1921-
/// | `&U` | when `U: Sized` |
1922-
/// | `&mut U` | when `U: Sized` |
1923-
/// | [`ptr::NonNull<U>`] | when `U: Sized` |
1918+
/// | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
1919+
/// |-----------------------|-----------------------------------------------------------|
1920+
/// | [`Box<U>`] | when `U: Sized` |
1921+
/// | `&U` | when `U: Sized` |
1922+
/// | `&mut U` | when `U: Sized` |
1923+
/// | [`ptr::NonNull<U>`] | when `U: Sized` |
1924+
/// | `fn`, `extern "C" fn` | always |
19241925
///
19251926
/// TODO(#429), TODO(https://github.com/rust-lang/rust/pull/115333): Cite
19261927
/// the Stable docs once they're available.
@@ -1929,6 +1930,8 @@ safety_comment! {
19291930
unsafe_impl!(T => FromZeroes for Option<&'_ T>);
19301931
unsafe_impl!(T => FromZeroes for Option<&'_ mut T>);
19311932
unsafe_impl!(T => FromZeroes for Option<NonNull<T>>);
1933+
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_fn!(...));
1934+
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeroes for opt_extern_c_fn!(...));
19321935
}
19331936

19341937
safety_comment! {
@@ -5575,6 +5578,18 @@ mod tests {
55755578
// Implements none of the ZC traits.
55765579
struct NotZerocopy;
55775580

5581+
#[rustfmt::skip]
5582+
type FnManyArgs = fn(
5583+
NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
5584+
) -> (NotZerocopy, NotZerocopy);
5585+
5586+
// Allowed, because we're not actually using this type for FFI.
5587+
#[allow(improper_ctypes_definitions)]
5588+
#[rustfmt::skip]
5589+
type ECFnManyArgs = extern "C" fn(
5590+
NotZerocopy, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8,
5591+
) -> (NotZerocopy, NotZerocopy);
5592+
55785593
#[cfg(feature = "alloc")]
55795594
assert_impls!(Option<Box<UnsafeCell<NotZerocopy>>>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned);
55805595
assert_impls!(Option<Box<[UnsafeCell<NotZerocopy>]>>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
@@ -5584,6 +5599,10 @@ mod tests {
55845599
assert_impls!(Option<&'static mut [UnsafeCell<NotZerocopy>]>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
55855600
assert_impls!(Option<NonNull<UnsafeCell<NotZerocopy>>>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned);
55865601
assert_impls!(Option<NonNull<[UnsafeCell<NotZerocopy>]>>: KnownLayout, !FromZeroes, !FromBytes, !AsBytes, !Unaligned);
5602+
assert_impls!(Option<fn()>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned);
5603+
assert_impls!(Option<FnManyArgs>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned);
5604+
assert_impls!(Option<extern "C" fn()>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned);
5605+
assert_impls!(Option<ECFnManyArgs>: KnownLayout, FromZeroes, !FromBytes, !AsBytes, !Unaligned);
55875606

55885607
assert_impls!(PhantomData<NotZerocopy>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);
55895608
assert_impls!(PhantomData<[u8]>: KnownLayout, FromZeroes, FromBytes, AsBytes, Unaligned);

src/macros.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,52 @@ macro_rules! unsafe_impl {
102102
};
103103
}
104104

105+
/// Implements a trait for a type, bounding on each memeber of the power set of
106+
/// a set of type variables. This is useful for implementing traits for tuples
107+
/// or `fn` types.
108+
///
109+
/// The last argument is the name of a macro which will be called in every
110+
/// `impl` block, and is expected to expand to the name of the type for which to
111+
/// implement the trait.
112+
///
113+
/// For example, the invocation:
114+
/// ```ignore
115+
/// unsafe_impl_for_power_set!(A, B => Foo for type!(...))
116+
/// ```
117+
/// ...expands to:
118+
/// ```ignore
119+
/// unsafe impl Foo for type!() { ... }
120+
/// unsafe impl<B> Foo for type!(B) { ... }
121+
/// unsafe impl<A, B> Foo for type!(A, B) { ... }
122+
/// ```
123+
macro_rules! unsafe_impl_for_power_set {
124+
($first:ident $(, $rest:ident)* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
125+
unsafe_impl_for_power_set!($($rest),* $(-> $ret)? => $trait for $macro!(...));
126+
unsafe_impl_for_power_set!(@impl $first $(, $rest)* $(-> $ret)? => $trait for $macro!(...));
127+
};
128+
($(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
129+
unsafe_impl_for_power_set!(@impl $(-> $ret)? => $trait for $macro!(...));
130+
};
131+
(@impl $($vars:ident),* $(-> $ret:ident)? => $trait:ident for $macro:ident!(...)) => {
132+
unsafe impl<$($vars,)* $($ret)?> $trait for $macro!($($vars),* $(-> $ret)?) {
133+
#[allow(clippy::missing_inline_in_public_items)]
134+
fn only_derive_is_allowed_to_implement_this_trait() {}
135+
}
136+
};
137+
}
138+
139+
/// Expands to an `Option<extern "C" fn>` type with the given argument types and
140+
/// return type. Designed for use with `unsafe_impl_for_power_set`.
141+
macro_rules! opt_extern_c_fn {
142+
($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
143+
}
144+
145+
/// Expands to a `Option<fn>` type with the given argument types and return
146+
/// type. Designed for use with `unsafe_impl_for_power_set`.
147+
macro_rules! opt_fn {
148+
($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
149+
}
150+
105151
/// Implements trait(s) for a type or verifies the given implementation by
106152
/// referencing an existing (derived) implementation.
107153
///

0 commit comments

Comments
 (0)