diff options
| author | Jubilee <workingjubilee@gmail.com> | 2024-10-24 23:23:54 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-10-24 23:23:54 -0700 |
| commit | fd78b671a88a8b5c3470234bcd52a84fc552d510 (patch) | |
| tree | d7e5341d7c7b591cc1d4bb79c1291a5978b9ed69 | |
| parent | 788202a2cef5dde0743490fd51515f373d4207a6 (diff) | |
| parent | 5280f152b0dad9faf33478a06c6a1cdf97b71ae4 (diff) | |
| download | rust-fd78b671a88a8b5c3470234bcd52a84fc552d510.tar.gz rust-fd78b671a88a8b5c3470234bcd52a84fc552d510.zip | |
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).
| -rw-r--r-- | library/core/src/ptr/mod.rs | 40 |
1 files changed, 34 insertions, 6 deletions
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index ea185f0fbe5..03cab232742 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -2107,13 +2107,39 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool { /// Compares the *addresses* of the two function pointers for equality. /// -/// Function pointers comparisons can have surprising results since -/// they are never guaranteed to be unique and could vary between different -/// code generation units. Furthermore, different functions could have the -/// same address after being merged together. +/// 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 **very few guarantees** about how functions are compiled and they have no intrinsic +/// “identity”; in particular, this comparison: +/// +/// * May return `true` unexpectedly, in cases where functions are equivalent. +/// +/// For example, the following program is likely (but not guaranteed) to print `(true, true)` +/// when compiled with optimization: +/// +/// ``` +/// # #![feature(ptr_fn_addr_eq)] +/// let f: fn(i32) -> i32 = |x| x; +/// let g: fn(i32) -> i32 = |x| x + 0; // different closure, different body +/// let h: fn(u32) -> u32 = |x| x + 0; // different signature too +/// dbg!(std::ptr::fn_addr_eq(f, g), std::ptr::fn_addr_eq(f, h)); // not guaranteed to be equal +/// ``` +/// +/// * May return `false` in 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.) +/// +/// Despite these false positives and false negatives, this comparison can still be useful. +/// Specifically, if +/// +/// * `T` is the same type as `U`, `T` is a [subtype] of `U`, or `U` is a [subtype] of `T`, and +/// * `ptr::fn_addr_eq(f, g)` returns true, +/// +/// then calling `f` and calling `g` will be equivalent. /// -/// This is the same as `f == g` but using this function makes clear -/// that you are aware of these potentially surprising semantics. /// /// # Examples /// @@ -2125,6 +2151,8 @@ pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool { /// fn b() { println!("b"); } /// assert!(!ptr::fn_addr_eq(a as fn(), b as fn())); /// ``` +/// +/// [subtype]: https://doc.rust-lang.org/reference/subtyping.html #[unstable(feature = "ptr_fn_addr_eq", issue = "129322")] #[inline(always)] #[must_use = "function pointer comparison produces a value"] |
