Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 0ce4f76

Browse files
committedOct 9, 2024
Expand ptr::fn_addr_eq() documentation.
* Describe more clearly what is (not) guaranteed, and de-emphasize the implementation details. * Explain what you *can* reliably use it for.
1 parent 9ca739e commit 0ce4f76

File tree

1 file changed

+32
-6
lines changed

1 file changed

+32
-6
lines changed
 

‎core/src/ptr/mod.rs

+32-6
Original file line numberDiff line numberDiff line change
@@ -2164,13 +2164,36 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool {
21642164

21652165
/// Compares the *addresses* of the two function pointers for equality.
21662166
///
2167-
/// Function pointers comparisons can have surprising results since
2168-
/// they are never guaranteed to be unique and could vary between different
2169-
/// code generation units. Furthermore, different functions could have the
2170-
/// same address after being merged together.
2167+
/// This is the same as `f == g`, but using this function makes clear that the potentially
2168+
/// surprising semantics of function pointer comparison are involved.
2169+
/// There are very few guarantees about how functions are compiled and they have no intrinsic
2170+
/// “identity”; in particular, this comparison:
2171+
///
2172+
/// * May return `true` unexpectedly, in cases where functions are equivalent.
2173+
/// For example, the following program is likely (but not guaranteed) to print `(true, true)`
2174+
/// when compiled with optimization:
2175+
///
2176+
/// ```
2177+
/// # #![feature(ptr_fn_addr_eq)]
2178+
/// let f: fn(i32) -> i32 = |x| x;
2179+
/// let g: fn(i32) -> i32 = |x| x + 0; // different closure, different body
2180+
/// let h: fn(u32) -> u32 = |x| x + 0; // different signature too
2181+
/// dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h));
2182+
/// ```
2183+
///
2184+
/// * May return `false` in any case.
2185+
/// This is particularly likely with generic functions but may happen with any function.
2186+
/// (From an implementation perspective, this is possible because functions may sometimes be
2187+
/// processed more than once by the compiler, resulting in duplicate machine code.)
2188+
///
2189+
/// Despite these false positives and false negatives, this comparison can still be useful.
2190+
/// Specifically, if
2191+
///
2192+
/// * `T` is the same type as `U`, `T` is a [subtype] of `U`, or `U` is a [subtype] of `T`, and
2193+
/// * `ptr::fn_addr_eq(f, g)` returns true,
2194+
///
2195+
/// then calling `f` and calling `g` will be equivalent.
21712196
///
2172-
/// This is the same as `f == g` but using this function makes clear
2173-
/// that you are aware of these potentially surprising semantics.
21742197
///
21752198
/// # Examples
21762199
///
@@ -2182,6 +2205,9 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool {
21822205
/// fn b() { println!("b"); }
21832206
/// assert!(!ptr::fn_addr_eq(a as fn(), b as fn()));
21842207
/// ```
2208+
///
2209+
/// [subtype]: https://doc.rust-lang.org/reference/subtyping.html
2210+
21852211
#[unstable(feature = "ptr_fn_addr_eq", issue = "129322")]
21862212
#[inline(always)]
21872213
#[must_use = "function pointer comparison produces a value"]

0 commit comments

Comments
 (0)
Failed to load comments.