Skip to content

Commit a34f7c1

Browse files
authored
Implement traits for unsafe function values (#2697)
Closes #2617
1 parent 57e8b93 commit a34f7c1

File tree

2 files changed

+38
-13
lines changed

2 files changed

+38
-13
lines changed

src/impls.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -299,24 +299,25 @@ const _: () = unsafe {
299299

300300
// SAFETY: The following types can be transmuted from `[0u8; size_of::<T>()]`. [1]
301301
//
302-
// [1] Per https://doc.rust-lang.org/nightly/core/option/index.html#representation:
302+
// [1] Per https://doc.rust-lang.org/1.89.0/core/option/index.html#representation:
303303
//
304304
// Rust guarantees to optimize the following types `T` such that [`Option<T>`]
305305
// has the same size and alignment as `T`. In some of these cases, Rust
306306
// further guarantees that `transmute::<_, Option<T>>([0u8; size_of::<T>()])`
307307
// is sound and produces `Option::<T>::None`. These cases are identified by
308308
// the second column:
309309
//
310-
// | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
311-
// |-----------------------|-----------------------------------------------------------|
312-
// | [`Box<U>`] | when `U: Sized` |
313-
// | `&U` | when `U: Sized` |
314-
// | `&mut U` | when `U: Sized` |
315-
// | [`ptr::NonNull<U>`] | when `U: Sized` |
316-
// | `fn`, `extern "C" fn` | always |
317-
//
318-
// FIXME(#429), FIXME(https://github.com/rust-lang/rust/pull/115333): Cite the
319-
// Stable docs once they're available.
310+
// | `T` | `transmute::<_, Option<T>>([0u8; size_of::<T>()])` sound? |
311+
// |-----------------------------------|-----------------------------------------------------------|
312+
// | [`Box<U>`] | when `U: Sized` |
313+
// | `&U` | when `U: Sized` |
314+
// | `&mut U` | when `U: Sized` |
315+
// | [`ptr::NonNull<U>`] | when `U: Sized` |
316+
// | `fn`, `extern "C" fn`[^extern_fn] | always |
317+
//
318+
// [^extern_fn]: this remains true for `unsafe` variants, any argument/return
319+
// types, and any other ABI: `[unsafe] extern "abi" fn` (_e.g._, `extern
320+
// "system" fn`)
320321
const _: () = unsafe {
321322
#[cfg(feature = "alloc")]
322323
unsafe_impl!(
@@ -345,19 +346,31 @@ const _: () = unsafe {
345346
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...);
346347
|c| pointer::is_zeroed(c)
347348
);
349+
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_fn!(...));
350+
unsafe_impl_for_power_set!(
351+
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_fn!(...);
352+
|c| pointer::is_zeroed(c)
353+
);
348354
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...));
349355
unsafe_impl_for_power_set!(
350356
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...);
351357
|c| pointer::is_zeroed(c)
352358
);
359+
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_unsafe_extern_c_fn!(...));
360+
unsafe_impl_for_power_set!(
361+
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_unsafe_extern_c_fn!(...);
362+
|c| pointer::is_zeroed(c)
363+
);
353364
};
354365

355-
// SAFETY: `fn()` and `extern "C" fn()` self-evidently do not contain
366+
// SAFETY: `[unsafe] [extern "C"] fn()` self-evidently do not contain
356367
// `UnsafeCell`s. This is not a proof, but we are accepting this as a known risk
357368
// per #1358.
358369
const _: () = unsafe {
359370
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_fn!(...));
371+
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_fn!(...));
360372
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_extern_c_fn!(...));
373+
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => Immutable for opt_unsafe_extern_c_fn!(...));
361374
};
362375

363376
#[cfg(all(

src/util/macros.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,12 +307,24 @@ macro_rules! opt_extern_c_fn {
307307
($($args:ident),* -> $ret:ident) => { Option<extern "C" fn($($args),*) -> $ret> };
308308
}
309309

310-
/// Expands to a `Option<fn>` type with the given argument types and return
310+
/// Expands to an `Option<unsafe extern "C" fn>` type with the given argument
311+
/// types and return type. Designed for use with `unsafe_impl_for_power_set`.
312+
macro_rules! opt_unsafe_extern_c_fn {
313+
($($args:ident),* -> $ret:ident) => { Option<unsafe extern "C" fn($($args),*) -> $ret> };
314+
}
315+
316+
/// Expands to an `Option<fn>` type with the given argument types and return
311317
/// type. Designed for use with `unsafe_impl_for_power_set`.
312318
macro_rules! opt_fn {
313319
($($args:ident),* -> $ret:ident) => { Option<fn($($args),*) -> $ret> };
314320
}
315321

322+
/// Expands to an `Option<unsafe fn>` type with the given argument types and
323+
/// return type. Designed for use with `unsafe_impl_for_power_set`.
324+
macro_rules! opt_unsafe_fn {
325+
($($args:ident),* -> $ret:ident) => { Option<unsafe fn($($args),*) -> $ret> };
326+
}
327+
316328
/// Implements trait(s) for a type or verifies the given implementation by
317329
/// referencing an existing (derived) implementation.
318330
///

0 commit comments

Comments
 (0)