diff options
| author | Ralf Jung <post@ralfj.de> | 2022-05-23 18:47:05 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2022-05-23 18:47:08 +0200 |
| commit | cec6dfcd67b2841e44248a070fd33895330bdfcf (patch) | |
| tree | 4244fb5592ca0f1a1752ce3c943317d3f25e00d9 | |
| parent | 09ea21343a432a4c51b363d6f53bed694f81ea3a (diff) | |
| download | rust-cec6dfcd67b2841e44248a070fd33895330bdfcf.tar.gz rust-cec6dfcd67b2841e44248a070fd33895330bdfcf.zip | |
explain how to turn integers into fn ptrs
(with an intermediate raw ptr, not a direct transmute)
| -rw-r--r-- | library/core/src/intrinsics.rs | 3 | ||||
| -rw-r--r-- | library/core/src/primitive_docs.rs | 26 |
2 files changed, 29 insertions, 0 deletions
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 88e4262922d..6ba359f6edc 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -930,6 +930,9 @@ extern "rust-intrinsic" { /// fn foo() -> i32 { /// 0 /// } + /// // Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer. + /// // This avoids an integer-to-pointer `transmute`, which can be problematic. + /// // Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine. /// let pointer = foo as *const (); /// let function = unsafe { /// std::mem::transmute::<*const (), fn() -> i32>(pointer) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index ac4e668112b..147312b9720 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1338,6 +1338,32 @@ mod prim_ref {} /// is a reference to the function-specific ZST. `&bar` is basically never what you /// want when `bar` is a function. /// +/// ### Casting to and from integers +/// +/// You cast function pointers directly to integers: +/// +/// ```rust +/// let fnptr: fn(i32) -> i32 = |x| x+2; +/// let fnptr_addr = fnptr as usize; +/// ``` +/// +/// However, a direct cast back is not possible. You need to use `transmute`: +/// +/// ```rust +/// # let fnptr: fn(i32) -> i32 = |x| x+2; +/// # let fnptr_addr = fnptr as usize; +/// let fnptr = fnptr_addr as *const (); +/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) }; +/// assert_eq!(fnptr(40), 42); +/// ``` +/// +/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer. +/// This avoids an integer-to-pointer `transmute`, which can be problematic. +/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine. +/// +/// Note that all of this is not portable to platforms where function pointers and data pointers +/// have different sizes. +/// /// ### Traits /// /// Function pointers implement the following traits: |
