Skip to content

Commit

Permalink
Rollup merge of rust-lang#103567 - RalfJung:ptr-eq-dyn-trait, r=dtolnay
Browse files Browse the repository at this point in the history
ptr::eq: clarify that comparing dyn Trait is fragile

Also remove the dyn trait example from `ptr::eq` since those tests are not actually guaranteed to pass due to how unstable vtable comparison is.

Cc `@rust-lang/libs-api`
Cc discussion following rust-lang#80505
  • Loading branch information
compiler-errors authored Oct 26, 2022
2 parents 29ad394 + 1946a18 commit f619f01
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 45 deletions.
10 changes: 5 additions & 5 deletions library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,8 +1110,8 @@ impl<T: ?Sized> Rc<T> {

#[inline]
#[stable(feature = "ptr_eq", since = "1.17.0")]
/// Returns `true` if the two `Rc`s point to the same allocation
/// (in a vein similar to [`ptr::eq`]).
/// Returns `true` if the two `Rc`s point to the same allocation in a vein similar to
/// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers.
///
/// # Examples
///
Expand Down Expand Up @@ -2419,9 +2419,9 @@ impl<T: ?Sized> Weak<T> {
}
}

/// Returns `true` if the two `Weak`s point to the same allocation (similar to
/// [`ptr::eq`]), or if both don't point to any allocation
/// (because they were created with `Weak::new()`).
/// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if
/// both don't point to any allocation (because they were created with `Weak::new()`). See [that
/// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers.
///
/// # Notes
///
Expand Down
10 changes: 5 additions & 5 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1117,8 +1117,8 @@ impl<T: ?Sized> Arc<T> {
drop(Weak { ptr: self.ptr });
}

/// Returns `true` if the two `Arc`s point to the same allocation
/// (in a vein similar to [`ptr::eq`]).
/// Returns `true` if the two `Arc`s point to the same allocation in a vein similar to
/// [`ptr::eq`]. See [that function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers.
///
/// # Examples
///
Expand Down Expand Up @@ -2069,9 +2069,9 @@ impl<T: ?Sized> Weak<T> {
}
}

/// Returns `true` if the two `Weak`s point to the same allocation (similar to
/// [`ptr::eq`]), or if both don't point to any allocation
/// (because they were created with `Weak::new()`).
/// Returns `true` if the two `Weak`s point to the same allocation similar to [`ptr::eq`], or if
/// both don't point to any allocation (because they were created with `Weak::new()`). See [that
/// function][`ptr::eq`] for caveats when comparing `dyn Trait` pointers.
///
/// # Notes
///
Expand Down
41 changes: 6 additions & 35 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,12 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
/// by their address rather than comparing the values they point to
/// (which is what the `PartialEq for &T` implementation does).
///
/// When comparing wide pointers, both the address and the metadata are tested for equality.
/// However, note that comparing trait object pointers (`*const dyn Trait`) is unrealiable: pointers
/// to values of the same underlying type can compare inequal (because vtables are duplicated in
/// multiple codegen units), and pointers to values of *different* underlying type can compare equal
/// (since identical vtables can be deduplicated within a codegen unit).
///
/// # Examples
///
/// ```
Expand All @@ -1759,41 +1765,6 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
/// assert!(!std::ptr::eq(&a[..2], &a[..3]));
/// assert!(!std::ptr::eq(&a[0..2], &a[1..3]));
/// ```
///
/// Traits are also compared by their implementation:
///
/// ```
/// #[repr(transparent)]
/// struct Wrapper { member: i32 }
///
/// trait Trait {}
/// impl Trait for Wrapper {}
/// impl Trait for i32 {}
///
/// let wrapper = Wrapper { member: 10 };
///
/// // Pointers have equal addresses.
/// assert!(std::ptr::eq(
/// &wrapper as *const Wrapper as *const u8,
/// &wrapper.member as *const i32 as *const u8
/// ));
///
/// // Objects have equal addresses, but `Trait` has different implementations.
/// assert!(!std::ptr::eq(
/// &wrapper as &dyn Trait,
/// &wrapper.member as &dyn Trait,
/// ));
/// assert!(!std::ptr::eq(
/// &wrapper as &dyn Trait as *const dyn Trait,
/// &wrapper.member as &dyn Trait as *const dyn Trait,
/// ));
///
/// // Converting the reference to a `*const u8` compares by address.
/// assert!(std::ptr::eq(
/// &wrapper as &dyn Trait as *const dyn Trait as *const u8,
/// &wrapper.member as &dyn Trait as *const dyn Trait as *const u8,
/// ));
/// ```
#[stable(feature = "ptr_eq", since = "1.17.0")]
#[inline]
pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
Expand Down

0 comments on commit f619f01

Please sign in to comment.