@@ -4,6 +4,7 @@ use super::{from_raw_parts, memchr};
44use crate :: ascii;
55use crate :: cmp:: { self , BytewiseEq , Ordering } ;
66use crate :: intrinsics:: compare_bytes;
7+ use crate :: mem:: SizedTypeProperties ;
78use crate :: num:: NonZero ;
89use crate :: ops:: ControlFlow ;
910
1516{
1617 #[ inline]
1718 fn eq ( & self , other : & [ U ] ) -> bool {
18- SlicePartialEq :: equal ( self , other)
19+ let len = self . len ( ) ;
20+ if len == other. len ( ) {
21+ // SAFETY: Just checked that they're the same length, and the pointers
22+ // come from references-to-slices so they're guaranteed readable.
23+ unsafe { SlicePartialEq :: equal_same_length ( self . as_ptr ( ) , other. as_ptr ( ) , len) }
24+ } else {
25+ false
26+ }
1927 }
2028}
2129
@@ -95,12 +103,14 @@ impl<T: PartialOrd> PartialOrd for [T] {
95103// intermediate trait for specialization of slice's PartialEq
96104#[ rustc_const_unstable( feature = "const_cmp" , issue = "143800" ) ]
97105const trait SlicePartialEq <B > {
98- fn equal ( & self , other : & [ B ] ) -> bool ;
106+ /// # Safety
107+ /// `lhs` and `rhs` are both readable for `len` elements
108+ unsafe fn equal_same_length ( lhs : * const Self , rhs : * const B , len : usize ) -> bool ;
99109}
100110
101111// Generic slice equality
102112#[ rustc_const_unstable( feature = "const_cmp" , issue = "143800" ) ]
103- impl < A , B > const SlicePartialEq < B > for [ A ]
113+ impl < A , B > const SlicePartialEq < B > for A
104114where
105115 A : [ const ] PartialEq < B > ,
106116{
@@ -109,19 +119,15 @@ where
109119 // such as in `<str as PartialEq>::eq`.
110120 // The codegen backend can still inline it later if needed.
111121 #[ rustc_no_mir_inline]
112- default fn equal ( & self , other : & [ B ] ) -> bool {
113- if self . len ( ) != other. len ( ) {
114- return false ;
115- }
116-
122+ default unsafe fn equal_same_length ( lhs : * const Self , rhs : * const B , len : usize ) -> bool {
117123 // Implemented as explicit indexing rather
118124 // than zipped iterators for performance reasons.
119125 // See PR https://github.com/rust-lang/rust/pull/116846
120- // FIXME(const_hack): make this a `for idx in 0..self. len() ` loop.
126+ // FIXME(const_hack): make this a `for idx in 0..len` loop.
121127 let mut idx = 0 ;
122- while idx < self . len ( ) {
123- // bound checks are optimized away
124- if self [ idx] != other [ idx] {
128+ while idx < len {
129+ // SAFETY: idx < len, so both are in-bounds and readable
130+ if unsafe { * lhs . add ( idx) != * rhs . add ( idx) } {
125131 return false ;
126132 }
127133 idx += 1 ;
@@ -134,30 +140,18 @@ where
134140// When each element can be compared byte-wise, we can compare all the bytes
135141// from the whole size in one call to the intrinsics.
136142#[ rustc_const_unstable( feature = "const_cmp" , issue = "143800" ) ]
137- impl < A , B > const SlicePartialEq < B > for [ A ]
143+ impl < A , B > const SlicePartialEq < B > for A
138144where
139145 A : [ const ] BytewiseEq < B > ,
140146{
141- // This is usually a pretty good backend inlining candidate because the
142- // intrinsic tends to just be `memcmp`. However, as of 2025-12 letting
143- // MIR inline this makes reuse worse because it means that, for example,
144- // `String::eq` doesn't inline, whereas by keeping this from inling all
145- // the wrappers until the call to this disappear. If the heuristics have
146- // changed and this is no longer fruitful, though, please do remove it.
147- // In the mean time, it's fine to not inline it in MIR because the backend
148- // will still inline it if it things it's important to do so.
149- #[ rustc_no_mir_inline]
150147 #[ inline]
151- fn equal ( & self , other : & [ B ] ) -> bool {
152- if self . len ( ) != other. len ( ) {
153- return false ;
154- }
155-
156- // SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
157- // The two slices have been checked to have the same size above.
148+ unsafe fn equal_same_length ( lhs : * const Self , rhs : * const B , len : usize ) -> bool {
149+ // SAFETY: by our precondition, `lhs` and `rhs` are guaranteed to be valid
150+ // for reading `len` values, which also means the size is guaranteed
151+ // not to overflow because it exists in memory;
158152 unsafe {
159- let size = size_of_val ( self ) ;
160- compare_bytes ( self . as_ptr ( ) as * const u8 , other . as_ptr ( ) as * const u8 , size) == 0
153+ let size = crate :: intrinsics :: unchecked_mul ( len , Self :: SIZE ) ;
154+ compare_bytes ( lhs as _ , rhs as _ , size) == 0
161155 }
162156 }
163157}
0 commit comments