Use the FnPtr trait to avoid implementing common traits via macros

This commit is contained in:
Oli Scherer 2023-03-06 16:48:22 +00:00
parent 9e27c6c133
commit 5ae6caa0f0
3 changed files with 162 additions and 127 deletions

View File

@ -932,7 +932,7 @@ impl<T: ?Sized> Copy for &T {}
#[lang = "fn_ptr_trait"] #[lang = "fn_ptr_trait"]
#[cfg(not(bootstrap))] #[cfg(not(bootstrap))]
#[rustc_deny_explicit_impl] #[rustc_deny_explicit_impl]
pub trait FnPtr { pub trait FnPtr: Copy + Clone {
/// Returns the address of the function pointer. /// Returns the address of the function pointer.
#[lang = "fn_ptr_addr"] #[lang = "fn_ptr_addr"]
fn addr(self) -> *const (); fn addr(self) -> *const ();

View File

@ -1891,9 +1891,12 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
hashee.hash(into); hashee.hash(into);
} }
// If this is a unary fn pointer, it adds a doc comment. #[cfg(bootstrap)]
// Otherwise, it hides the docs entirely. mod old_fn_ptr_impl {
macro_rules! maybe_fnptr_doc { use super::*;
// If this is a unary fn pointer, it adds a doc comment.
// Otherwise, it hides the docs entirely.
macro_rules! maybe_fnptr_doc {
(@ #[$meta:meta] $item:item) => { (@ #[$meta:meta] $item:item) => {
#[doc(hidden)] #[doc(hidden)]
#[$meta] #[$meta]
@ -1910,15 +1913,15 @@ macro_rules! maybe_fnptr_doc {
#[$meta] #[$meta]
$item $item
}; };
} }
// FIXME(strict_provenance_magic): function pointers have buggy codegen that // FIXME(strict_provenance_magic): function pointers have buggy codegen that
// necessitates casting to a usize to get the backend to do the right thing. // necessitates casting to a usize to get the backend to do the right thing.
// for now I will break AVR to silence *a billion* lints. We should probably // for now I will break AVR to silence *a billion* lints. We should probably
// have a proper "opaque function pointer type" to handle this kind of thing. // have a proper "opaque function pointer type" to handle this kind of thing.
// Impls for function pointers // Impls for function pointers
macro_rules! fnptr_impls_safety_abi { macro_rules! fnptr_impls_safety_abi {
($FnTy: ty, $($Arg: ident),*) => { ($FnTy: ty, $($Arg: ident),*) => {
fnptr_impls_safety_abi! { #[stable(feature = "fnptr_impls", since = "1.4.0")] $FnTy, $($Arg),* } fnptr_impls_safety_abi! { #[stable(feature = "fnptr_impls", since = "1.4.0")] $FnTy, $($Arg),* }
}; };
@ -1995,9 +1998,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
} }
} }
} }
} }
macro_rules! fnptr_impls_args { macro_rules! fnptr_impls_args {
($($Arg: ident),+) => { ($($Arg: ident),+) => {
fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ } fnptr_impls_safety_abi! { extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
fnptr_impls_safety_abi! { extern "C" fn($($Arg),+) -> Ret, $($Arg),+ } fnptr_impls_safety_abi! { extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
@ -2019,22 +2022,74 @@ macro_rules! fnptr_impls_args {
fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, } fnptr_impls_safety_abi! { unsafe extern "C" fn() -> Ret, }
fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn() -> Ret, } fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn() -> Ret, }
}; };
}
fnptr_impls_args! {}
fnptr_impls_args! { T }
fnptr_impls_args! { A, B }
fnptr_impls_args! { A, B, C }
fnptr_impls_args! { A, B, C, D }
fnptr_impls_args! { A, B, C, D, E }
fnptr_impls_args! { A, B, C, D, E, F }
fnptr_impls_args! { A, B, C, D, E, F, G }
fnptr_impls_args! { A, B, C, D, E, F, G, H }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
} }
fnptr_impls_args! {} #[cfg(not(bootstrap))]
fnptr_impls_args! { T } mod new_fn_ptr_impl {
fnptr_impls_args! { A, B } use super::*;
fnptr_impls_args! { A, B, C } use crate::marker::FnPtr;
fnptr_impls_args! { A, B, C, D }
fnptr_impls_args! { A, B, C, D, E }
fnptr_impls_args! { A, B, C, D, E, F }
fnptr_impls_args! { A, B, C, D, E, F, G }
fnptr_impls_args! { A, B, C, D, E, F, G, H }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K }
fnptr_impls_args! { A, B, C, D, E, F, G, H, I, J, K, L }
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> PartialEq for F {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.addr() == other.addr()
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> Eq for F {}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> PartialOrd for F {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.addr().partial_cmp(&other.addr())
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> Ord for F {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.addr().cmp(&other.addr())
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> hash::Hash for F {
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
state.write_usize(self.addr() as _)
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> fmt::Pointer for F {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(self.addr() as _, f)
}
}
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<F: FnPtr> fmt::Debug for F {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(self.addr() as _, f)
}
}
}
/// Create a `const` raw pointer to a place, without creating an intermediate reference. /// Create a `const` raw pointer to a place, without creating an intermediate reference.
/// ///
/// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned /// Creating a reference with `&`/`&mut` is only allowed if the pointer is properly aligned

View File

@ -90,16 +90,6 @@ LL | assert_eq!(Foo::Bar, i);
| ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
| |
= help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}`
= help: the following other types implement trait `Debug`:
extern "C" fn() -> Ret
extern "C" fn(A, B) -> Ret
extern "C" fn(A, B, ...) -> Ret
extern "C" fn(A, B, C) -> Ret
extern "C" fn(A, B, C, ...) -> Ret
extern "C" fn(A, B, C, D) -> Ret
extern "C" fn(A, B, C, D, ...) -> Ret
extern "C" fn(A, B, C, D, E) -> Ret
and 118 others
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug`
@ -109,16 +99,6 @@ LL | assert_eq!(Foo::Bar, i);
| ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | ^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug`
| |
= help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}` = help: the trait `Debug` is not implemented for fn item `fn(usize) -> Foo {Foo::Bar}`
= help: the following other types implement trait `Debug`:
extern "C" fn() -> Ret
extern "C" fn(A, B) -> Ret
extern "C" fn(A, B, ...) -> Ret
extern "C" fn(A, B, C) -> Ret
extern "C" fn(A, B, C, ...) -> Ret
extern "C" fn(A, B, C, D) -> Ret
extern "C" fn(A, B, C, D, ...) -> Ret
extern "C" fn(A, B, C, D, E) -> Ret
and 118 others
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 10 previous errors error: aborting due to 10 previous errors