From 6f28cd5073b4738b3a630c7903fc0dd1d4f1e1f5 Mon Sep 17 00:00:00 2001 From: Josiah Glosson Date: Mon, 20 Apr 2026 21:48:58 -0500 Subject: [PATCH] Make Rcs and Arcs use pointer comparison for unsized types --- library/alloc/src/rc.rs | 6 +++--- library/alloc/src/sync.rs | 4 ++-- library/alloctests/tests/arc.rs | 28 ++++++++++++++++++++++++++++ library/alloctests/tests/rc.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 4e6d886658595..d0c415a2ec67a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2615,7 +2615,7 @@ impl RcEqIdent for Rc { #[rustc_unsafe_specialization_marker] pub(crate) trait MarkerEq: PartialEq {} -impl MarkerEq for T {} +impl MarkerEq for T {} /// We're doing this specialization here, and not as a more general optimization on `&T`, because it /// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to @@ -2628,12 +2628,12 @@ impl MarkerEq for T {} impl RcEqIdent for Rc { #[inline] fn eq(&self, other: &Rc) -> bool { - Rc::ptr_eq(self, other) || **self == **other + ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) || **self == **other } #[inline] fn ne(&self, other: &Rc) -> bool { - !Rc::ptr_eq(self, other) && **self != **other + !ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) && **self != **other } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 8004dd38d073b..229fcd2b429cf 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3549,12 +3549,12 @@ impl ArcEqIdent for Arc { impl ArcEqIdent for Arc { #[inline] fn eq(&self, other: &Arc) -> bool { - Arc::ptr_eq(self, other) || **self == **other + ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) || **self == **other } #[inline] fn ne(&self, other: &Arc) -> bool { - !Arc::ptr_eq(self, other) && **self != **other + !ptr::eq(self.ptr.as_ptr(), other.ptr.as_ptr()) && **self != **other } } diff --git a/library/alloctests/tests/arc.rs b/library/alloctests/tests/arc.rs index 00bdf527133f7..a56204187c0a0 100644 --- a/library/alloctests/tests/arc.rs +++ b/library/alloctests/tests/arc.rs @@ -86,6 +86,34 @@ fn eq() { assert_eq!(*x.0.borrow(), 0); } +#[test] +fn eq_unsized() { + #[derive(Eq)] + struct TestEq(RefCell, T); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Arc::>::new(TestEq(RefCell::new(0), [0, 1, 2])) as Arc>; + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +} + +#[test] +fn eq_unsized_slice() { + let a: Arc<[()]> = Arc::new([(); 3]); + let ptr: *const () = Arc::into_raw(a.clone()).cast(); + let b: Arc<[()]> = unsafe { Arc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) }; + assert!(a == a); + assert!(!(a != a)); + assert!(a != b); + assert!(!(a == b)); +} + // The test code below is identical to that in `rc.rs`. // For better maintainability we therefore define this type alias. type Rc = Arc; diff --git a/library/alloctests/tests/rc.rs b/library/alloctests/tests/rc.rs index bb68eb4ac9e3d..5be0e8f339119 100644 --- a/library/alloctests/tests/rc.rs +++ b/library/alloctests/tests/rc.rs @@ -87,6 +87,34 @@ fn eq() { assert_eq!(*x.0.borrow(), 0); } +#[test] +fn eq_unsized() { + #[derive(Eq)] + struct TestEq(RefCell, T); + impl PartialEq for TestEq { + fn eq(&self, other: &TestEq) -> bool { + *self.0.borrow_mut() += 1; + *other.0.borrow_mut() += 1; + true + } + } + let x = Rc::>::new(TestEq(RefCell::new(0), [0, 1, 2])) as Rc>; + assert!(x == x); + assert!(!(x != x)); + assert_eq!(*x.0.borrow(), 0); +} + +#[test] +fn eq_unsized_slice() { + let a: Rc<[()]> = Rc::new([(); 3]); + let ptr: *const () = Rc::into_raw(a.clone()).cast(); + let b: Rc<[()]> = unsafe { Rc::from_raw(core::ptr::slice_from_raw_parts(ptr, 42)) }; + assert!(a == a); + assert!(!(a != a)); + assert!(a != b); + assert!(!(a == b)); +} + const SHARED_ITER_MAX: u16 = 100; fn assert_trusted_len(_: &I) {}