Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the function pointer docs #98180

Merged
merged 3 commits into from
Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -402,8 +402,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 @@ -685,6 +685,7 @@ symbols! {
fabsf32,
fabsf64,
fadd_fast,
fake_variadic,
fdiv_fast,
feature,
fence,
Expand Down Expand Up @@ -1460,7 +1461,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 }
GuillaumeGomez marked this conversation as resolved.
Show resolved Hide resolved
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