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 631cc313fa0..688ab63bf13 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1351,6 +1351,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: diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 631cc313fa0..688ab63bf13 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1351,6 +1351,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: