Skip to content

Commit fd78b67

Browse files
Rollup merge of #131457 - kpreid:fnaddr, r=dtolnay
Expand `ptr::fn_addr_eq()` documentation. * Describe more clearly what is (not) guaranteed, and de-emphasize the description of rustc implementation details. * Explain what you *can* reliably use it for. Tracking issue for `ptr_fn_addr_eq`: #129322 The motivation for this PR is that I just learned that `ptr::fn_addr_eq()` exists, read the documentation, and thought: “*I* know what this means, but someone not already familiar with how `rustc` works could be left wondering whether this is even good for anything.” Fixing that seems especially important if we’re going to recommend people use it instead of `==` (as per #118833).
2 parents 788202a + 5280f15 commit fd78b67

File tree

1 file changed

+34
-6
lines changed

1 file changed

+34
-6
lines changed

library/core/src/ptr/mod.rs

+34-6
Original file line numberDiff line numberDiff line change
@@ -2107,13 +2107,39 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool {
21072107

21082108
/// Compares the *addresses* of the two function pointers for equality.
21092109
///
2110-
/// Function pointers comparisons can have surprising results since
2111-
/// they are never guaranteed to be unique and could vary between different
2112-
/// code generation units. Furthermore, different functions could have the
2113-
/// same address after being merged together.
2110+
/// This is the same as `f == g`, but using this function makes clear that the potentially
2111+
/// surprising semantics of function pointer comparison are involved.
2112+
///
2113+
/// There are **very few guarantees** about how functions are compiled and they have no intrinsic
2114+
/// “identity”; in particular, this comparison:
2115+
///
2116+
/// * May return `true` unexpectedly, in cases where functions are equivalent.
2117+
///
2118+
/// For example, the following program is likely (but not guaranteed) to print `(true, true)`
2119+
/// when compiled with optimization:
2120+
///
2121+
/// ```
2122+
/// # #![feature(ptr_fn_addr_eq)]
2123+
/// let f: fn(i32) -> i32 = |x| x;
2124+
/// let g: fn(i32) -> i32 = |x| x + 0; // different closure, different body
2125+
/// let h: fn(u32) -> u32 = |x| x + 0; // different signature too
2126+
/// dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h)); // not guaranteed to be equal
2127+
/// ```
2128+
///
2129+
/// * May return `false` in any case.
2130+
///
2131+
/// This is particularly likely with generic functions but may happen with any function.
2132+
/// (From an implementation perspective, this is possible because functions may sometimes be
2133+
/// processed more than once by the compiler, resulting in duplicate machine code.)
2134+
///
2135+
/// Despite these false positives and false negatives, this comparison can still be useful.
2136+
/// Specifically, if
2137+
///
2138+
/// * `T` is the same type as `U`, `T` is a [subtype] of `U`, or `U` is a [subtype] of `T`, and
2139+
/// * `ptr::fn_addr_eq(f, g)` returns true,
2140+
///
2141+
/// then calling `f` and calling `g` will be equivalent.
21142142
///
2115-
/// This is the same as `f == g` but using this function makes clear
2116-
/// that you are aware of these potentially surprising semantics.
21172143
///
21182144
/// # Examples
21192145
///
@@ -2125,6 +2151,8 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool {
21252151
/// fn b() { println!("b"); }
21262152
/// assert!(!ptr::fn_addr_eq(a as fn(), b as fn()));
21272153
/// ```
2154+
///
2155+
/// [subtype]: https://doc.rust-lang.org/reference/subtyping.html
21282156
#[unstable(feature = "ptr_fn_addr_eq", issue = "129322")]
21292157
#[inline(always)]
21302158
#[must_use = "function pointer comparison produces a value"]

0 commit comments

Comments
 (0)