Skip to content

Commit

Permalink
Auto merge of #98180 - notriddle:notriddle/rustdoc-fn, r=petrochenkov…
Browse files Browse the repository at this point in the history
…,GuillaumeGomez

Improve the function pointer docs

This is #97842 but for function pointers instead of tuples. The concept is basically the same.

* Reduce duplicate impls; show `fn (T₁, T₂, …, 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`.

https://notriddle.com/notriddle-rustdoc-test/std/primitive.fn.html
  • Loading branch information
bors committed Jul 19, 2022
2 parents 29c5a02 + ddb5a26 commit 9a7b7d5
Show file tree
Hide file tree
Showing 29 changed files with 278 additions and 106 deletions.
4 changes: 2 additions & 2 deletions compiler/rustc_ast_passes/src/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,8 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
}

if nested_meta.has_name(sym::tuple_variadic) {
let msg = "`#[doc(tuple_variadic)]` is meant for internal use only";
if nested_meta.has_name(sym::fake_variadic) {
let msg = "`#[doc(fake_variadic)]` is meant for internal use only";
gate_feature_post!(self, rustdoc_internals, attr.span, msg);
}
}
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_error_codes/src/error_codes/E0118.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ enum, union, or trait object.
Erroneous code example:

```compile_fail,E0118
impl fn(u8) { // error: no nominal type found for inherent implementation
impl<T> T { // error: no nominal type found for inherent implementation
fn get_state(&self) -> String {
// ...
}
Expand All @@ -20,8 +20,8 @@ trait LiveLongAndProsper {
fn get_state(&self) -> String;
}
// and now you can implement it on fn(u8)
impl LiveLongAndProsper for fn(u8) {
// and now you can implement it on T
impl<T> LiveLongAndProsper for T {
fn get_state(&self) -> String {
"He's dead, Jim!".to_owned()
}
Expand All @@ -33,9 +33,9 @@ For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`.
Example:

```
struct TypeWrapper(fn(u8));
struct TypeWrapper<T>(T);
impl TypeWrapper {
impl<T> TypeWrapper<T> {
fn get_state(&self) -> String {
"Fascinating!".to_owned()
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_error_messages/locales/en-US/passes.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ passes-doc-keyword-not-mod = `#[doc(keyword = "...")]` should be used on modules
passes-doc-keyword-invalid-ident = `{$doc_keyword}` is not a valid identifier
passes-doc-tuple-variadic-not-first =
`#[doc(tuple_variadic)]` must be used on the first of a set of tuple trait impls with varying arity
passes-doc-fake-variadic-not-valid =
`#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
passes-doc-keyword-only-impl = `#[doc(keyword = "...")]` should be used on impl blocks
Expand Down
20 changes: 13 additions & 7 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,14 +706,20 @@ impl CheckAttrVisitor<'_> {
true
}

fn check_doc_tuple_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
fn check_doc_fake_variadic(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
match self.tcx.hir().find(hir_id).and_then(|node| match node {
hir::Node::Item(item) => Some(&item.kind),
_ => None,
}) {
Some(ItemKind::Impl(ref i)) => {
if !matches!(&i.self_ty.kind, hir::TyKind::Tup([_])) {
self.tcx.sess.emit_err(errors::DocTupleVariadicNotFirst { span: meta.span() });
let is_valid = matches!(&i.self_ty.kind, hir::TyKind::Tup([_]))
|| if let hir::TyKind::BareFn(bare_fn_ty) = &i.self_ty.kind {
bare_fn_ty.decl.inputs.len() == 1
} else {
false
};
if !is_valid {
self.tcx.sess.emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
return false;
}
}
Expand Down Expand Up @@ -887,9 +893,9 @@ impl CheckAttrVisitor<'_> {
is_valid = false
}

sym::tuple_variadic
if !self.check_attr_not_crate_level(meta, hir_id, "tuple_variadic")
|| !self.check_doc_tuple_variadic(meta, hir_id) =>
sym::fake_variadic
if !self.check_attr_not_crate_level(meta, hir_id, "fake_variadic")
|| !self.check_doc_fake_variadic(meta, hir_id) =>
{
is_valid = false
}
Expand Down Expand Up @@ -939,7 +945,7 @@ impl CheckAttrVisitor<'_> {
| sym::notable_trait
| sym::passes
| sym::plugins
| sym::tuple_variadic => {}
| sym::fake_variadic => {}

sym::test => {
if !self.check_test_attr(meta, hir_id) {
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_passes/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ pub struct DocKeywordInvalidIdent {
}

#[derive(SessionDiagnostic)]
#[error(passes::doc_tuple_variadic_not_first)]
pub struct DocTupleVariadicNotFirst {
#[error(passes::doc_fake_variadic_not_valid)]
pub struct DocFakeVariadicNotValid {
#[primary_span]
pub span: Span,
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,7 @@ symbols! {
fabsf32,
fabsf64,
fadd_fast,
fake_variadic,
fdiv_fast,
feature,
fence,
Expand Down Expand Up @@ -1471,7 +1472,6 @@ symbols! {
tuple,
tuple_from_req,
tuple_indexing,
tuple_variadic,
two_phase,
ty,
type_alias_enum_variants,
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_typeck/src/coherence/inherent_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,9 @@ impl<'tcx> InherentCollect<'tcx> {
| ty::RawPtr(_)
| ty::Ref(..)
| ty::Never
| ty::FnPtr(_)
| ty::Tuple(..) => self.check_primitive_impl(item.def_id, self_ty, items, ty.span),
ty::FnPtr(_) | ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
let mut err = struct_span_err!(
self.tcx.sess,
ty.span,
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2562,7 +2562,7 @@ macro_rules! tuple {

macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
#[doc(tuple_variadic)]
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/hash/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,7 @@ mod impls {

macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
#[doc(tuple_variadic)]
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
Expand Down
64 changes: 52 additions & 12 deletions library/core/src/primitive_docs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,7 +996,7 @@ impl<T> (T,) {}
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(tuple_variadic)]
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Clone> Clone for (T,) {
fn clone(&self) -> Self {
Expand All @@ -1007,7 +1007,7 @@ impl<T: Clone> Clone for (T,) {
// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(tuple_variadic)]
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on arbitrary-length tuples.
impl<T: Copy> Copy for (T,) {
// empty
Expand Down Expand Up @@ -1441,11 +1441,16 @@ mod prim_ref {}
/// Note that all of this is not portable to platforms where function pointers and data pointers
/// have different sizes.
///
/// ### Traits
/// ### Trait implementations
///
/// Function pointers implement the following traits:
/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
/// function pointers of varying length. Note that this is a convenience notation to avoid
/// repetitive documentation, not valid Rust syntax.
///
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
/// may change:
///
/// * [`Clone`]
/// * [`PartialEq`]
/// * [`Eq`]
/// * [`PartialOrd`]
Expand All @@ -1454,15 +1459,50 @@ mod prim_ref {}
/// * [`Pointer`]
/// * [`Debug`]
///
/// The following traits are implemented for function pointers with any number of arguments and
/// any ABI. These traits have implementations that are automatically generated by the compiler,
/// so are not limited by missing language features:
///
/// * [`Clone`]
/// * [`Copy`]
/// * [`Send`]
/// * [`Sync`]
/// * [`Unpin`]
/// * [`UnwindSafe`]
/// * [`RefUnwindSafe`]
///
/// [`Hash`]: hash::Hash
/// [`Pointer`]: fmt::Pointer
/// [`UnwindSafe`]: panic::UnwindSafe
/// [`RefUnwindSafe`]: panic::RefUnwindSafe
///
/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
/// may change.
///
/// In addition, function pointers of *any* signature, ABI, or safety are [`Copy`], and all *safe*
/// function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`]. This works because these traits
/// are specially known to the compiler.
/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
/// these traits are specially known to the compiler.
#[stable(feature = "rust1", since = "1.0.0")]
mod prim_fn {}

// Required to make auto trait impls render.
// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
#[doc(hidden)]
#[cfg(not(bootstrap))]
impl<Ret, T> fn(T) -> Ret {}

// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on function pointers with any number of arguments.
impl<Ret, T> Clone for fn(T) -> Ret {
fn clone(&self) -> Self {
loop {}
}
}

// Fake impl that's only really used for docs.
#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
/// This trait is implemented on function pointers with any number of arguments.
impl<Ret, T> Copy for fn(T) -> Ret {
// empty
}
102 changes: 72 additions & 30 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1819,6 +1819,27 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
hashee.hash(into);
}

// 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) => {
#[doc(hidden)]
#[$meta]
$item
};
($a:ident @ #[$meta:meta] $item:item) => {
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
#[doc = "This trait is implemented for function pointers with up to twelve arguments."]
#[$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
// 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
Expand All @@ -1827,51 +1848,72 @@ pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
// Impls for function pointers
macro_rules! fnptr_impls_safety_abi {
($FnTy: ty, $($Arg: ident),*) => {
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> PartialEq for $FnTy {
#[inline]
fn eq(&self, other: &Self) -> bool {
*self as usize == *other as usize
maybe_fnptr_doc! {
$($Arg)* @
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> PartialEq for $FnTy {
#[inline]
fn eq(&self, other: &Self) -> bool {
*self as usize == *other as usize
}
}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> Eq for $FnTy {}
maybe_fnptr_doc! {
$($Arg)* @
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> Eq for $FnTy {}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(*self as usize).partial_cmp(&(*other as usize))
maybe_fnptr_doc! {
$($Arg)* @
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> PartialOrd for $FnTy {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
(*self as usize).partial_cmp(&(*other as usize))
}
}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> Ord for $FnTy {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
(*self as usize).cmp(&(*other as usize))
maybe_fnptr_doc! {
$($Arg)* @
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> Ord for $FnTy {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
(*self as usize).cmp(&(*other as usize))
}
}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
state.write_usize(*self as usize)
maybe_fnptr_doc! {
$($Arg)* @
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> hash::Hash for $FnTy {
fn hash<HH: hash::Hasher>(&self, state: &mut HH) {
state.write_usize(*self as usize)
}
}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(*self as usize, f)
maybe_fnptr_doc! {
$($Arg)* @
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> fmt::Pointer for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(*self as usize, f)
}
}
}

#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(*self as usize, f)
maybe_fnptr_doc! {
$($Arg)* @
#[stable(feature = "fnptr_impls", since = "1.4.0")]
impl<Ret, $($Arg),*> fmt::Debug for $FnTy {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::pointer_fmt_inner(*self as usize, f)
}
}
}
}
Expand All @@ -1896,7 +1938,7 @@ macro_rules! fnptr_impls_args {
}

fnptr_impls_args! {}
fnptr_impls_args! { A }
fnptr_impls_args! { T }
fnptr_impls_args! { A, B }
fnptr_impls_args! { A, B, C }
fnptr_impls_args! { A, B, C, D }
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ macro_rules! tuple_impls {
// Otherwise, it hides the docs entirely.
macro_rules! maybe_tuple_doc {
($a:ident @ #[$meta:meta] $item:item) => {
#[doc(tuple_variadic)]
#[cfg_attr(not(bootstrap), doc(fake_variadic))]
#[doc = "This trait is implemented for tuples up to twelve items long."]
#[$meta]
$item
Expand Down
Loading

0 comments on commit 9a7b7d5

Please sign in to comment.