pub fn fn_addr_eq<T, U>(f: T, g: U) -> boolExpand description
Compares the addresses of the two function pointers for equality.
This is the same as f == g, but using this function makes clear that the potentially
surprising semantics of function pointer comparison are involved.
There are basically no guarantees about how functions are compiled as they have no intrinsic “identity”; in particular, this comparison:
-
May return
trueunexpectedly, even in cases where functions are not logically equivalent, as long as they compile to the same machine code.For example, the following program is likely (but not guaranteed) to print
(true, true)when compiled with optimization:use std::hint::assert_unchecked; let f: fn(i32) -> i32 = |x| x; let g: fn(u32) -> u32 = |x| x + 0; // different type, different body let h: unsafe fn(i32) -> i32 = |x| unsafe { assert_unchecked(x != 0); x }; // different unsafe preconditions // These three functions are allowed but not guaranteed to compare equal. dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h));In other words, functions that compare equal can have different behavior! Even if
fn_addr_eq(f, h)is true, it is still undefined behavior to callh(0), whilef(0)is safe to call.The explanation for this is that function pointers have provenance. If functions have the same assembly and get merged, their provenance decides which variant of the function will be called.
fandhtherefore end up with the same address but different provenance, andfn_addr_eqonly compares the address. -
May return
falsein any case.This is particularly likely with generic functions but may happen with any function. (From an implementation perspective, this is possible because functions may sometimes be processed more than once by the compiler, resulting in duplicate machine code.)
These limitations imply that comparing function pointers (via this function or via ==) is only
useful in extremely niche circumstances. For instance, if a library maintains a set of
callbacks, and doesn’t guarantee which of them are actually called (i.e., callbacks can be
spuriously skipped), then it can be legitimate to deduplicate callbacks based on fn_addr_eq.
This can never introduce undefined behavior because it only skips executing some of the
registered callbacks.