Skip to content

Commit 2338903

Browse files
committed
fn type: structure, and talk a bit more about ABIs and how to create them
1 parent 5989bf4 commit 2338903

File tree

1 file changed

+48
-9
lines changed

1 file changed

+48
-9
lines changed

library/std/src/primitive_docs.rs

+48-9
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,8 @@ mod prim_ref {}
10601060
/// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null
10611061
/// pointers, make your type `Option<fn()>` with your required signature.
10621062
///
1063+
/// ### Safety
1064+
///
10631065
/// Plain function pointers are obtained by casting either plain functions, or closures that don't
10641066
/// capture an environment:
10651067
///
@@ -1097,23 +1099,60 @@ mod prim_ref {}
10971099
/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one;
10981100
/// ```
10991101
///
1100-
/// On top of that, function pointers can vary based on what ABI they use. This is achieved by
1101-
/// adding the `extern` keyword to the type name, followed by the ABI in question. For example,
1102-
/// `fn()` is different from `extern "C" fn()`, which itself is different from `extern "stdcall"
1103-
/// fn()`, and so on for the various ABIs that Rust supports. Non-`extern` functions have an ABI
1104-
/// of `"Rust"`, and `extern` functions without an explicit ABI have an ABI of `"C"`. For more
1105-
/// information, see [the nomicon's section on foreign calling conventions][nomicon-abi].
1102+
/// ### ABI
1103+
///
1104+
/// On top of that, function pointers can vary based on what ABI they use. This
1105+
/// is achieved by adding the `extern` keyword before the type, followed by the
1106+
/// ABI in question. The default ABI is "Rust", i.e., `fn()` is the exact same
1107+
/// type as `extern "Rust" fn()`. A pointer to a function with C ABI would have
1108+
/// type `extern "C" fn()`.
1109+
///
1110+
/// `extern "ABI" { ... }` blocks declare functions with ABI "ABI". The default
1111+
/// here is "C", i.e., functions declared in an `extern {...}` block have "C"
1112+
/// ABI.
1113+
///
1114+
/// For more information and a list of supported ABIs, see [the nomicon's
1115+
/// section on foreign calling conventions][nomicon-abi].
11061116
///
1107-
/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
1117+
/// ### Variadic functions
11081118
///
11091119
/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
1110-
/// to be called with a variable number of arguments. Normal rust functions, even those with an
1120+
/// to be called with a variable number of arguments. Normal Rust functions, even those with an
11111121
/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on
11121122
/// variadic functions][nomicon-variadic].
11131123
///
11141124
/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions
11151125
///
1116-
/// These markers can be combined, so `unsafe extern "stdcall" fn()` is a valid type.
1126+
/// ### Creating function pointers
1127+
///
1128+
/// When `bar` is the name of a function, then the expression `bar` is *not* a
1129+
/// function pointer. Rather, it denotes a value of an unnameable type that
1130+
/// uniquely identifies the function `bar`. The value is zero-sized because the
1131+
/// type already identifies the function. This has the advantage that "calling"
1132+
/// the value (it implements the `Fn*` traits) does not require dynamic
1133+
/// dispatch.
1134+
///
1135+
/// This zero-sized type *coerces* to a regular function pointer. For example:
1136+
///
1137+
/// ```rust
1138+
/// use std::mem;
1139+
///
1140+
/// fn bar(x: i32) {}
1141+
///
1142+
/// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar`
1143+
/// assert_eq!(mem::size_of_val(&not_bar_ptr), 0);
1144+
///
1145+
/// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer
1146+
/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::<usize>());
1147+
///
1148+
/// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar`
1149+
/// ```
1150+
///
1151+
/// The last line shows that `&bar` is not a function pointer either. Rather, it
1152+
/// is a reference to the function-specific ZST. `&bar` is basically never what you
1153+
/// want when `bar` is a function.
1154+
///
1155+
/// ### Traits
11171156
///
11181157
/// Function pointers implement the following traits:
11191158
///

0 commit comments

Comments
 (0)