Use the FnPtr trait to avoid implementing common traits via macros
This commit is contained in:
parent
9e27c6c133
commit
5ae6caa0f0
@ -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 ();
|
||||||
|
@ -1891,150 +1891,205 @@ 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::*;
|
||||||
(@ #[$meta:meta] $item:item) => {
|
// If this is a unary fn pointer, it adds a doc comment.
|
||||||
#[doc(hidden)]
|
// Otherwise, it hides the docs entirely.
|
||||||
#[$meta]
|
macro_rules! maybe_fnptr_doc {
|
||||||
$item
|
(@ #[$meta:meta] $item:item) => {
|
||||||
};
|
#[doc(hidden)]
|
||||||
($a:ident @ #[$meta:meta] $item:item) => {
|
#[$meta]
|
||||||
#[doc(fake_variadic)]
|
$item
|
||||||
#[doc = "This trait is implemented for function pointers with up to twelve arguments."]
|
};
|
||||||
#[$meta]
|
($a:ident @ #[$meta:meta] $item:item) => {
|
||||||
$item
|
#[doc(fake_variadic)]
|
||||||
};
|
#[doc = "This trait is implemented for function pointers with up to twelve arguments."]
|
||||||
($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
|
#[$meta]
|
||||||
#[doc(hidden)]
|
$item
|
||||||
#[$meta]
|
};
|
||||||
$item
|
($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
|
||||||
};
|
#[doc(hidden)]
|
||||||
}
|
#[$meta]
|
||||||
|
$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),* }
|
||||||
};
|
};
|
||||||
(@c_unwind $FnTy: ty, $($Arg: ident),*) => {
|
(@c_unwind $FnTy: ty, $($Arg: ident),*) => {
|
||||||
fnptr_impls_safety_abi! { #[unstable(feature = "c_unwind", issue = "74990")] $FnTy, $($Arg),* }
|
fnptr_impls_safety_abi! { #[unstable(feature = "c_unwind", issue = "74990")] $FnTy, $($Arg),* }
|
||||||
};
|
};
|
||||||
(#[$meta:meta] $FnTy: ty, $($Arg: ident),*) => {
|
(#[$meta:meta] $FnTy: ty, $($Arg: ident),*) => {
|
||||||
maybe_fnptr_doc! {
|
maybe_fnptr_doc! {
|
||||||
$($Arg)* @
|
$($Arg)* @
|
||||||
#[$meta]
|
#[$meta]
|
||||||
impl<Ret, $($Arg),*> PartialEq for $FnTy {
|
impl<Ret, $($Arg),*> PartialEq for $FnTy {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
*self as usize == *other as usize
|
*self as usize == *other as usize
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
maybe_fnptr_doc! {
|
maybe_fnptr_doc! {
|
||||||
$($Arg)* @
|
$($Arg)* @
|
||||||
#[$meta]
|
#[$meta]
|
||||||
impl<Ret, $($Arg),*> Eq for $FnTy {}
|
impl<Ret, $($Arg),*> Eq for $FnTy {}
|
||||||
}
|
}
|
||||||
|
|
||||||
maybe_fnptr_doc! {
|
maybe_fnptr_doc! {
|
||||||
$($Arg)* @
|
$($Arg)* @
|
||||||
#[$meta]
|
#[$meta]
|
||||||
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
|
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
(*self as usize).partial_cmp(&(*other as usize))
|
(*self as usize).partial_cmp(&(*other as usize))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
maybe_fnptr_doc! {
|
maybe_fnptr_doc! {
|
||||||
$($Arg)* @
|
$($Arg)* @
|
||||||
#[$meta]
|
#[$meta]
|
||||||
impl<Ret, $($Arg),*> Ord for $FnTy {
|
impl<Ret, $($Arg),*> Ord for $FnTy {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
(*self as usize).cmp(&(*other as usize))
|
(*self as usize).cmp(&(*other as usize))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
maybe_fnptr_doc! {
|
maybe_fnptr_doc! {
|
||||||
$($Arg)* @
|
$($Arg)* @
|
||||||
#[$meta]
|
#[$meta]
|
||||||
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
|
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
|
||||||
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
|
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
|
||||||
state.write_usize(*self as usize)
|
state.write_usize(*self as usize)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
maybe_fnptr_doc! {
|
maybe_fnptr_doc! {
|
||||||
$($Arg)* @
|
$($Arg)* @
|
||||||
#[$meta]
|
#[$meta]
|
||||||
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
|
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::pointer_fmt_inner(*self as usize, f)
|
fmt::pointer_fmt_inner(*self as usize, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
maybe_fnptr_doc! {
|
maybe_fnptr_doc! {
|
||||||
$($Arg)* @
|
$($Arg)* @
|
||||||
#[$meta]
|
#[$meta]
|
||||||
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
|
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::pointer_fmt_inner(*self as usize, f)
|
fmt::pointer_fmt_inner(*self as usize, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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),+ }
|
||||||
fnptr_impls_safety_abi! { extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
||||||
fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
|
||||||
fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
||||||
fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { unsafe extern "Rust" fn($($Arg),+) -> Ret, $($Arg),+ }
|
||||||
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+) -> Ret, $($Arg),+ }
|
||||||
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { unsafe extern "C" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
||||||
fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+) -> Ret, $($Arg),+ }
|
||||||
fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
fnptr_impls_safety_abi! { @c_unwind unsafe extern "C-unwind" fn($($Arg),+ , ...) -> Ret, $($Arg),+ }
|
||||||
};
|
};
|
||||||
() => {
|
() => {
|
||||||
// No variadic functions with 0 parameters
|
// No variadic functions with 0 parameters
|
||||||
fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
|
fnptr_impls_safety_abi! { extern "Rust" fn() -> Ret, }
|
||||||
fnptr_impls_safety_abi! { extern "C" fn() -> Ret, }
|
fnptr_impls_safety_abi! { extern "C" fn() -> Ret, }
|
||||||
fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn() -> Ret, }
|
fnptr_impls_safety_abi! { @c_unwind extern "C-unwind" fn() -> Ret, }
|
||||||
fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, }
|
fnptr_impls_safety_abi! { unsafe extern "Rust" fn() -> Ret, }
|
||||||
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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user