Skip to content

Commit 5271e32

Browse files
committed
Improve the function pointer docs
* Reduce duplicate impls; show only the `fn (T)` and include a sentence saying that there exists up to twelve of them. * Show `Copy` and `Clone`. * Show auto traits like `Send` and `Sync`, and blanket impls like `Any`.
1 parent 1169832 commit 5271e32

File tree

12 files changed

+222
-69
lines changed

12 files changed

+222
-69
lines changed

compiler/rustc_error_codes/src/error_codes/E0118.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ enum, union, or trait object.
44
Erroneous code example:
55

66
```compile_fail,E0118
7-
impl fn(u8) { // error: no nominal type found for inherent implementation
7+
impl<T> T { // error: no nominal type found for inherent implementation
88
fn get_state(&self) -> String {
99
// ...
1010
}
@@ -20,8 +20,8 @@ trait LiveLongAndProsper {
2020
fn get_state(&self) -> String;
2121
}
2222
23-
// and now you can implement it on fn(u8)
24-
impl LiveLongAndProsper for fn(u8) {
23+
// and now you can implement it on T
24+
impl<T> LiveLongAndProsper for T {
2525
fn get_state(&self) -> String {
2626
"He's dead, Jim!".to_owned()
2727
}
@@ -33,9 +33,9 @@ For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`.
3333
Example:
3434

3535
```
36-
struct TypeWrapper(fn(u8));
36+
struct TypeWrapper<T>(T);
3737
38-
impl TypeWrapper {
38+
impl<T> TypeWrapper<T> {
3939
fn get_state(&self) -> String {
4040
"Fascinating!".to_owned()
4141
}

compiler/rustc_typeck/src/coherence/inherent_impls.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,9 @@ impl<'tcx> InherentCollect<'tcx> {
219219
| ty::RawPtr(_)
220220
| ty::Ref(..)
221221
| ty::Never
222+
| ty::FnPtr(_)
222223
| ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
223-
ty::FnPtr(_) | ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
224+
ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
224225
let mut err = struct_span_err!(
225226
self.tcx.sess,
226227
ty.span,

library/core/src/primitive_docs.rs

+50-10
Original file line numberDiff line numberDiff line change
@@ -1441,11 +1441,16 @@ mod prim_ref {}
14411441
/// Note that all of this is not portable to platforms where function pointers and data pointers
14421442
/// have different sizes.
14431443
///
1444-
/// ### Traits
1444+
/// ### Trait implementations
14451445
///
1446-
/// Function pointers implement the following traits:
1446+
/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
1447+
/// function pointers of varying length. Note that this is a convenience notation to avoid
1448+
/// repetitive documentation, not valid Rust syntax.
1449+
///
1450+
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
1451+
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
1452+
/// may change:
14471453
///
1448-
/// * [`Clone`]
14491454
/// * [`PartialEq`]
14501455
/// * [`Eq`]
14511456
/// * [`PartialOrd`]
@@ -1454,15 +1459,50 @@ mod prim_ref {}
14541459
/// * [`Pointer`]
14551460
/// * [`Debug`]
14561461
///
1462+
/// The following traits are implemented for function pointers with any number of arguments and
1463+
/// any ABI. These traits have implementations that are automatically generated by the compiler,
1464+
/// so are not limited by missing language features:
1465+
///
1466+
/// * [`Clone`]
1467+
/// * [`Copy`]
1468+
/// * [`Send`]
1469+
/// * [`Sync`]
1470+
/// * [`Unpin`]
1471+
/// * [`UnwindSafe`]
1472+
/// * [`RefUnwindSafe`]
1473+
///
14571474
/// [`Hash`]: hash::Hash
14581475
/// [`Pointer`]: fmt::Pointer
1476+
/// [`UnwindSafe`]: panic::UnwindSafe
1477+
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
14591478
///
1460-
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
1461-
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
1462-
/// may change.
1463-
///
1464-
/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
1465-
/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
1466-
/// are specially known to the compiler.
1479+
/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
1480+
/// these traits are specially known to the compiler.
14671481
#[stable(feature = "rust1", since = "1.0.0")]
14681482
mod prim_fn {}
1483+
1484+
// Required to make auto trait impls render.
1485+
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
1486+
#[doc(hidden)]
1487+
#[cfg(not(bootstrap))]
1488+
impl<Ret, T> fn(T) -> Ret {}
1489+
1490+
// Fake impl that's only really used for docs.
1491+
#[cfg(doc)]
1492+
#[stable(feature = "rust1", since = "1.0.0")]
1493+
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
1494+
/// This trait is implemented on function pointers with any number of arguments.
1495+
impl<Ret, T> Clone for fn(T) -> Ret {
1496+
fn clone(&self) -> Self {
1497+
loop {}
1498+
}
1499+
}
1500+
1501+
// Fake impl that's only really used for docs.
1502+
#[cfg(doc)]
1503+
#[stable(feature = "rust1", since = "1.0.0")]
1504+
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
1505+
/// This trait is implemented on function pointers with any number of arguments.
1506+
impl<Ret, T> Copy for fn(T) -> Ret {
1507+
// empty
1508+
}

library/core/src/ptr/mod.rs

+71-29
Original file line numberDiff line numberDiff line change
@@ -1819,6 +1819,27 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
18191819
hashee.hash(into);
18201820
}
18211821

1822+
// If this is a unary fn pointer, it adds a doc comment.
1823+
// Otherwise, it hides the docs entirely.
1824+
macro_rules! maybe_fnptr_doc {
1825+
(@ #[$meta:meta] $item:item) => {
1826+
#[doc(hidden)]
1827+
#[$meta]
1828+
$item
1829+
};
1830+
($a:ident @ #[$meta:meta] $item:item) => {
1831+
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
1832+
#[doc = "This trait is implemented for function pointers with up to twelve arguments."]
1833+
#[$meta]
1834+
$item
1835+
};
1836+
($a:ident $($rest_a:ident)+ @ #[$meta:meta] $item:item) => {
1837+
#[doc(hidden)]
1838+
#[$meta]
1839+
$item
1840+
};
1841+
}
1842+
18221843
// FIXME(strict_provenance_magic): function pointers have buggy codegen that
18231844
// necessitates casting to a usize to get the backend to do the right thing.
18241845
// for now I will break AVR to silence *a billion* lints. We should probably
@@ -1827,51 +1848,72 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
18271848
// Impls for function pointers
18281849
macro_rules! fnptr_impls_safety_abi {
18291850
($FnTy: ty, $($Arg: ident),*) => {
1830-
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1831-
impl<Ret, $($Arg),*> PartialEq for $FnTy {
1832-
#[inline]
1833-
fn eq(&self, other: &Self) -> bool {
1834-
*self as usize == *other as usize
1851+
maybe_fnptr_doc! {
1852+
$($Arg)* @
1853+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1854+
impl<Ret, $($Arg),*> PartialEq for $FnTy {
1855+
#[inline]
1856+
fn eq(&self, other: &Self) -> bool {
1857+
*self as usize == *other as usize
1858+
}
18351859
}
18361860
}
18371861

1838-
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1839-
impl<Ret, $($Arg),*> Eq for $FnTy {}
1862+
maybe_fnptr_doc! {
1863+
$($Arg)* @
1864+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1865+
impl<Ret, $($Arg),*> Eq for $FnTy {}
1866+
}
18401867

1841-
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1842-
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
1843-
#[inline]
1844-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1845-
(*self as usize).partial_cmp(&(*other as usize))
1868+
maybe_fnptr_doc! {
1869+
$($Arg)* @
1870+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1871+
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
1872+
#[inline]
1873+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1874+
(*self as usize).partial_cmp(&(*other as usize))
1875+
}
18461876
}
18471877
}
18481878

1849-
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1850-
impl<Ret, $($Arg),*> Ord for $FnTy {
1851-
#[inline]
1852-
fn cmp(&self, other: &Self) -> Ordering {
1853-
(*self as usize).cmp(&(*other as usize))
1879+
maybe_fnptr_doc! {
1880+
$($Arg)* @
1881+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1882+
impl<Ret, $($Arg),*> Ord for $FnTy {
1883+
#[inline]
1884+
fn cmp(&self, other: &Self) -> Ordering {
1885+
(*self as usize).cmp(&(*other as usize))
1886+
}
18541887
}
18551888
}
18561889

1857-
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1858-
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
1859-
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
1860-
state.write_usize(*self as usize)
1890+
maybe_fnptr_doc! {
1891+
$($Arg)* @
1892+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1893+
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
1894+
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
1895+
state.write_usize(*self as usize)
1896+
}
18611897
}
18621898
}
18631899

1864-
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1865-
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
1866-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1867-
fmt::pointer_fmt_inner(*self as usize, f)
1900+
maybe_fnptr_doc! {
1901+
$($Arg)* @
1902+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1903+
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
1904+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1905+
fmt::pointer_fmt_inner(*self as usize, f)
1906+
}
18681907
}
18691908
}
18701909

1871-
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1872-
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
1873-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1874-
fmt::pointer_fmt_inner(*self as usize, f)
1910+
maybe_fnptr_doc! {
1911+
$($Arg)* @
1912+
#[stable(feature = "fnptr_impls", since = "1.4.0")]
1913+
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
1914+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1915+
fmt::pointer_fmt_inner(*self as usize, f)
1916+
}
18751917
}
18761918
}
18771919
}

library/std/src/primitive_docs.rs

+50-10
Original file line numberDiff line numberDiff line change
@@ -1441,11 +1441,16 @@ mod prim_ref {}
14411441
/// Note that all of this is not portable to platforms where function pointers and data pointers
14421442
/// have different sizes.
14431443
///
1444-
/// ### Traits
1444+
/// ### Trait implementations
14451445
///
1446-
/// Function pointers implement the following traits:
1446+
/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
1447+
/// function pointers of varying length. Note that this is a convenience notation to avoid
1448+
/// repetitive documentation, not valid Rust syntax.
1449+
///
1450+
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
1451+
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
1452+
/// may change:
14471453
///
1448-
/// * [`Clone`]
14491454
/// * [`PartialEq`]
14501455
/// * [`Eq`]
14511456
/// * [`PartialOrd`]
@@ -1454,15 +1459,50 @@ mod prim_ref {}
14541459
/// * [`Pointer`]
14551460
/// * [`Debug`]
14561461
///
1462+
/// The following traits are implemented for function pointers with any number of arguments and
1463+
/// any ABI. These traits have implementations that are automatically generated by the compiler,
1464+
/// so are not limited by missing language features:
1465+
///
1466+
/// * [`Clone`]
1467+
/// * [`Copy`]
1468+
/// * [`Send`]
1469+
/// * [`Sync`]
1470+
/// * [`Unpin`]
1471+
/// * [`UnwindSafe`]
1472+
/// * [`RefUnwindSafe`]
1473+
///
14571474
/// [`Hash`]: hash::Hash
14581475
/// [`Pointer`]: fmt::Pointer
1476+
/// [`UnwindSafe`]: panic::UnwindSafe
1477+
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
14591478
///
1460-
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
1461-
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
1462-
/// may change.
1463-
///
1464-
/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
1465-
/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
1466-
/// are specially known to the compiler.
1479+
/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
1480+
/// these traits are specially known to the compiler.
14671481
#[stable(feature = "rust1", since = "1.0.0")]
14681482
mod prim_fn {}
1483+
1484+
// Required to make auto trait impls render.
1485+
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
1486+
#[doc(hidden)]
1487+
#[cfg(not(bootstrap))]
1488+
impl<Ret, T> fn(T) -> Ret {}
1489+
1490+
// Fake impl that's only really used for docs.
1491+
#[cfg(doc)]
1492+
#[stable(feature = "rust1", since = "1.0.0")]
1493+
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
1494+
/// This trait is implemented on function pointers with any number of arguments.
1495+
impl<Ret, T> Clone for fn(T) -> Ret {
1496+
fn clone(&self) -> Self {
1497+
loop {}
1498+
}
1499+
}
1500+
1501+
// Fake impl that's only really used for docs.
1502+
#[cfg(doc)]
1503+
#[stable(feature = "rust1", since = "1.0.0")]
1504+
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
1505+
/// This trait is implemented on function pointers with any number of arguments.
1506+
impl<Ret, T> Copy for fn(T) -> Ret {
1507+
// empty
1508+
}

src/librustdoc/clean/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1841,7 +1841,7 @@ impl PrimitiveType {
18411841
Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into_iter().collect(),
18421842
// FIXME: This will be wrong if we ever add inherent impls
18431843
// for function pointers.
1844-
Fn => ArrayVec::new(),
1844+
Fn => single(FunctionSimplifiedType(1)),
18451845
Never => single(NeverSimplifiedType),
18461846
}
18471847
})

src/librustdoc/html/format.rs

+26-6
Original file line numberDiff line numberDiff line change
@@ -1165,18 +1165,38 @@ impl clean::Impl {
11651165

11661166
if let clean::Type::Tuple(types) = &self.for_ &&
11671167
let [clean::Type::Generic(name)] = &types[..] &&
1168-
(self.kind.is_fake_variadic() || self.kind.is_auto()) {
1168+
(self.kind.is_fake_variadic() || self.kind.is_auto())
1169+
{
11691170
// Hardcoded anchor library/core/src/primitive_docs.rs
11701171
// Link should match `# Trait implementations`
11711172
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("({name}₁, {name}₂, …, {name}ₙ)"), "#trait-implementations-1", cx)?;
1172-
} else if let clean::Type::BareFunction(bare_fn) = &self.for_ &&
1173+
} else if let clean::BareFunction(bare_fn) = &self.for_ &&
11731174
let [clean::Argument { type_: clean::Type::Generic(name), .. }] = &bare_fn.decl.inputs.values[..] &&
1174-
(self.kind.is_fake_variadic() || self.kind.is_auto()) {
1175+
(self.kind.is_fake_variadic() || self.kind.is_auto())
1176+
{
11751177
// Hardcoded anchor library/core/src/primitive_docs.rs
11761178
// Link should match `# Trait implementations`
1177-
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("fn ({name}₁, {name}₂, …, {name}ₙ)"), "#trait-implementations-1", cx)?;
1178-
// Not implemented.
1179-
assert!(!bare_fn.decl.c_variadic);
1179+
1180+
let hrtb = bare_fn.print_hrtb_with_space(cx);
1181+
let unsafety = bare_fn.unsafety.print_with_space();
1182+
let abi = print_abi_with_space(bare_fn.abi);
1183+
if f.alternate() {
1184+
write!(
1185+
f,
1186+
"{hrtb:#}{unsafety}{abi:#}",
1187+
)?;
1188+
} else {
1189+
write!(
1190+
f,
1191+
"{hrtb}{unsafety}{abi}",
1192+
)?;
1193+
}
1194+
let ellipsis = if bare_fn.decl.c_variadic {
1195+
", ..."
1196+
} else {
1197+
""
1198+
};
1199+
primitive_link_fragment(f, PrimitiveType::Tuple, &format!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"), "#trait-implementations-1", cx)?;
11801200
// Write output.
11811201
if let clean::FnRetTy::Return(ty) = &bare_fn.decl.output {
11821202
write!(f, " -> ")?;

src/test/ui/error-codes/E0118.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
impl fn(u8) { //~ ERROR E0118
1+
impl<T> T { //~ ERROR E0118
22
fn get_state(&self) -> String {
33
String::new()
44
}

0 commit comments

Comments
 (0)