diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index a1ed993b7d9bf..961b54ee0aec9 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -25,8 +25,8 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-mod bytewise;
-pub(crate) use bytewise::BytewiseEq;
+mod spec;
+pub(crate) use spec::{AlwaysApplicableOrd, BytewiseEq, UnsignedBytewiseOrd};
 
 use self::Ordering::*;
 
@@ -817,7 +817,9 @@ impl<T: Clone> Clone for Reverse<T> {
 #[doc(alias = ">=")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Ord"]
-pub trait Ord: Eq + PartialOrd<Self> {
+pub trait Ord<#[unstable(feature = "generic_ord", issue = "none")] Rhs: ?Sized = Self>:
+    Eq + PartialOrd<Rhs>
+{
     /// This method returns an [`Ordering`] between `self` and `other`.
     ///
     /// By convention, `self.cmp(&other)` returns the ordering matching the expression
@@ -835,7 +837,7 @@ pub trait Ord: Eq + PartialOrd<Self> {
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "ord_cmp_method"]
-    fn cmp(&self, other: &Self) -> Ordering;
+    fn cmp(&self, other: &Rhs) -> Ordering;
 
     /// Compares and returns the maximum of two values.
     ///
@@ -851,11 +853,12 @@ pub trait Ord: Eq + PartialOrd<Self> {
     #[inline]
     #[must_use]
     #[rustc_diagnostic_item = "cmp_ord_max"]
-    fn max(self, other: Self) -> Self
+    fn max(self, other: Rhs) -> Self
     where
         Self: Sized,
+        Rhs: Sized + Into<Self>,
     {
-        max_by(self, other, Ord::cmp)
+        if self > other { self } else { other.into() }
     }
 
     /// Compares and returns the minimum of two values.
@@ -872,11 +875,12 @@ pub trait Ord: Eq + PartialOrd<Self> {
     #[inline]
     #[must_use]
     #[rustc_diagnostic_item = "cmp_ord_min"]
-    fn min(self, other: Self) -> Self
+    fn min(self, other: Rhs) -> Self
     where
         Self: Sized,
+        Rhs: Sized + Into<Self>,
     {
-        min_by(self, other, Ord::cmp)
+        if self <= other { self } else { other.into() }
     }
 
     /// Restrict a value to a certain interval.
@@ -898,16 +902,16 @@ pub trait Ord: Eq + PartialOrd<Self> {
     #[must_use]
     #[inline]
     #[stable(feature = "clamp", since = "1.50.0")]
-    fn clamp(self, min: Self, max: Self) -> Self
+    fn clamp(self, min: Rhs, max: Rhs) -> Self
     where
         Self: Sized,
-        Self: PartialOrd,
+        Rhs: Sized + PartialOrd + Into<Self>,
     {
         assert!(min <= max);
         if self < min {
-            min
+            min.into()
         } else if self > max {
-            max
+            max.into()
         } else {
             self
         }
@@ -1692,12 +1696,12 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized> Ord for &A
+    impl<A: ?Sized, B: ?Sized> Ord<&B> for &A
     where
-        A: Ord,
+        A: Ord<B>,
     {
         #[inline]
-        fn cmp(&self, other: &Self) -> Ordering {
+        fn cmp(&self, other: &&B) -> Ordering {
             Ord::cmp(*self, *other)
         }
     }
@@ -1747,12 +1751,12 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized> Ord for &mut A
+    impl<A: ?Sized, B: ?Sized> Ord<&mut B> for &mut A
     where
-        A: Ord,
+        A: Ord<B>,
     {
         #[inline]
-        fn cmp(&self, other: &Self) -> Ordering {
+        fn cmp(&self, other: &&mut B) -> Ordering {
             Ord::cmp(*self, *other)
         }
     }
diff --git a/library/core/src/cmp/bytewise.rs b/library/core/src/cmp/spec.rs
similarity index 67%
rename from library/core/src/cmp/bytewise.rs
rename to library/core/src/cmp/spec.rs
index a06a5227fe285..354c397b57d3a 100644
--- a/library/core/src/cmp/bytewise.rs
+++ b/library/core/src/cmp/spec.rs
@@ -1,3 +1,4 @@
+use crate::ascii;
 use crate::num::NonZero;
 
 /// Types where `==` & `!=` are equivalent to comparing their underlying bytes.
@@ -80,3 +81,40 @@ macro_rules! is_bytewise_comparable_array_length {
 //    error: specializing impl repeats parameter `N`
 // so just do it for a couple of plausibly-common ones.
 is_bytewise_comparable_array_length!(0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64);
+
+/// Marks that a type should be treated as an unsigned byte for comparisons.
+///
+/// # Safety
+/// * The type must be readable as an `u8`, meaning it has to have the same
+///   layout as `u8` and always be initialized.
+/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
+///   value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
+#[rustc_specialization_trait]
+pub(crate) unsafe trait UnsignedBytewiseOrd<Rhs = Self>: Ord<Rhs> + Sized {}
+
+unsafe impl UnsignedBytewiseOrd for bool {}
+unsafe impl UnsignedBytewiseOrd for u8 {}
+unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
+unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
+unsafe impl UnsignedBytewiseOrd for ascii::Char {}
+
+/// Marks that a type's [`Ord`] impl can always be used instead of its [`PartialOrd`] impl,
+/// so that we can specialize slice `Ord`.
+#[rustc_specialization_trait]
+pub(crate) trait AlwaysApplicableOrd<Rhs: ?Sized = Self>: Ord<Rhs> {}
+
+macro_rules! always_applicable_ord {
+    ($($t:ty,)*) => {
+        $(impl AlwaysApplicableOrd for $t {})*
+    }
+}
+
+always_applicable_ord! {
+    u8, u16, u32, u64, u128, usize,
+    i8, i16, i32, i64, i128, isize,
+    bool, char,
+}
+
+// to ensure soundness, these must have differing types
+impl<T: ?Sized, U: ?Sized> AlwaysApplicableOrd<&U> for &T where T: AlwaysApplicableOrd<U> {}
+impl<T: ?Sized, U: ?Sized> AlwaysApplicableOrd<&mut U> for &mut T where T: AlwaysApplicableOrd<U> {}
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index 1769612def0a5..bc39240922739 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -1,10 +1,9 @@
 //! Comparison traits for `[T]`.
 
 use super::{from_raw_parts, memchr};
-use crate::cmp::{self, BytewiseEq, Ordering};
+use crate::cmp::{self, AlwaysApplicableOrd, BytewiseEq, Ordering, UnsignedBytewiseOrd};
 use crate::intrinsics::compare_bytes;
-use crate::num::NonZero;
-use crate::{ascii, mem};
+use crate::mem;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T, U> PartialEq<[U]> for [T]
@@ -20,51 +19,32 @@ where
     }
 }
 
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Eq> Eq for [T] {}
-
-/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Ord> Ord for [T] {
-    fn cmp(&self, other: &[T]) -> Ordering {
-        SliceOrd::compare(self, other)
-    }
-}
-
-/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T: PartialOrd> PartialOrd for [T] {
-    fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
-        SlicePartialOrd::partial_compare(self, other)
-    }
-}
-
 #[doc(hidden)]
 // intermediate trait for specialization of slice's PartialEq
-trait SlicePartialEq<B> {
-    fn equal(&self, other: &[B]) -> bool;
+trait SlicePartialEq<B>: Sized {
+    fn equal(left: &[Self], right: &[B]) -> bool;
 
-    fn not_equal(&self, other: &[B]) -> bool {
-        !self.equal(other)
+    fn not_equal(left: &[Self], right: &[B]) -> bool {
+        !Self::equal(left, right)
     }
 }
 
 // Generic slice equality
-impl<A, B> SlicePartialEq<B> for [A]
+impl<A, B> SlicePartialEq<B> for A
 where
     A: PartialEq<B>,
 {
-    default fn equal(&self, other: &[B]) -> bool {
-        if self.len() != other.len() {
+    default fn equal(left: &[A], right: &[B]) -> bool {
+        if left.len() != right.len() {
             return false;
         }
 
         // Implemented as explicit indexing rather
         // than zipped iterators for performance reasons.
         // See PR https://github.com/rust-lang/rust/pull/116846
-        for idx in 0..self.len() {
+        for idx in 0..left.len() {
             // bound checks are optimized away
-            if self[idx] != other[idx] {
+            if left[idx] != right[idx] {
                 return false;
             }
         }
@@ -75,32 +55,49 @@ where
 
 // When each element can be compared byte-wise, we can compare all the bytes
 // from the whole size in one call to the intrinsics.
-impl<A, B> SlicePartialEq<B> for [A]
+impl<A, B> SlicePartialEq<B> for A
 where
     A: BytewiseEq<B>,
 {
-    fn equal(&self, other: &[B]) -> bool {
-        if self.len() != other.len() {
+    fn equal(left: &[A], right: &[B]) -> bool {
+        if left.len() != right.len() {
             return false;
         }
 
         // SAFETY: `self` and `other` are references and are thus guaranteed to be valid.
         // The two slices have been checked to have the same size above.
         unsafe {
-            let size = mem::size_of_val(self);
-            compare_bytes(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0
+            let size = mem::size_of_val(left);
+            compare_bytes(left.as_ptr() as *const u8, right.as_ptr() as *const u8, size) == 0
         }
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T: Eq> Eq for [T] {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T, U> PartialOrd<[U]> for [T]
+where
+    T: PartialOrd<U>,
+{
+    fn partial_cmp(&self, other: &[U]) -> Option<Ordering> {
+        SlicePartialOrd::partial_compare(self, other)
+    }
+}
+
 #[doc(hidden)]
 // intermediate trait for specialization of slice's PartialOrd
-trait SlicePartialOrd: Sized {
-    fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
+trait SlicePartialOrd<B>: Sized {
+    fn partial_compare(left: &[Self], right: &[B]) -> Option<Ordering>;
 }
 
-impl<A: PartialOrd> SlicePartialOrd for A {
-    default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
+impl<A, B> SlicePartialOrd<B> for A
+where
+    A: PartialOrd<B>,
+{
+    default fn partial_compare(left: &[A], right: &[B]) -> Option<Ordering> {
         let l = cmp::min(left.len(), right.len());
 
         // Slice to the loop iteration range to enable bound check
@@ -119,52 +116,37 @@ impl<A: PartialOrd> SlicePartialOrd for A {
     }
 }
 
-// This is the impl that we would like to have. Unfortunately it's not sound.
-// See `partial_ord_slice.rs`.
-/*
-impl<A> SlicePartialOrd for A
+impl<A, B> SlicePartialOrd<B> for A
 where
-    A: Ord,
+    A: AlwaysApplicableOrd<B>,
 {
-    default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
-        Some(SliceOrd::compare(left, right))
-    }
-}
-*/
-
-impl<A: AlwaysApplicableOrd> SlicePartialOrd for A {
-    fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
+    fn partial_compare(left: &[A], right: &[B]) -> Option<Ordering> {
         Some(SliceOrd::compare(left, right))
     }
 }
 
-#[rustc_specialization_trait]
-trait AlwaysApplicableOrd: SliceOrd + Ord {}
-
-macro_rules! always_applicable_ord {
-    ($([$($p:tt)*] $t:ty,)*) => {
-        $(impl<$($p)*> AlwaysApplicableOrd for $t {})*
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<T> Ord for [T]
+where
+    T: Ord,
+{
+    fn cmp(&self, other: &[T]) -> Ordering {
+        SliceOrd::compare(self, other)
     }
 }
 
-always_applicable_ord! {
-    [] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
-    [] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
-    [] bool, [] char,
-    [T: ?Sized] *const T, [T: ?Sized] *mut T,
-    [T: AlwaysApplicableOrd] &T,
-    [T: AlwaysApplicableOrd] &mut T,
-    [T: AlwaysApplicableOrd] Option<T>,
-}
-
 #[doc(hidden)]
 // intermediate trait for specialization of slice's Ord
-trait SliceOrd: Sized {
-    fn compare(left: &[Self], right: &[Self]) -> Ordering;
+trait SliceOrd<B>: Sized + Ord<B> {
+    fn compare(left: &[Self], right: &[B]) -> Ordering;
 }
 
-impl<A: Ord> SliceOrd for A {
-    default fn compare(left: &[Self], right: &[Self]) -> Ordering {
+/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
+impl<A, B> SliceOrd<B> for A
+where
+    A: Ord<B>,
+{
+    default fn compare(left: &[A], right: &[B]) -> Ordering {
         let l = cmp::min(left.len(), right.len());
 
         // Slice to the loop iteration range to enable bound check
@@ -183,27 +165,14 @@ impl<A: Ord> SliceOrd for A {
     }
 }
 
-/// Marks that a type should be treated as an unsigned byte for comparisons.
-///
-/// # Safety
-/// * The type must be readable as an `u8`, meaning it has to have the same
-///   layout as `u8` and always be initialized.
-/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
-///   value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
-#[rustc_specialization_trait]
-unsafe trait UnsignedBytewiseOrd {}
-
-unsafe impl UnsignedBytewiseOrd for bool {}
-unsafe impl UnsignedBytewiseOrd for u8 {}
-unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
-unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
-unsafe impl UnsignedBytewiseOrd for ascii::Char {}
-
 // `compare_bytes` compares a sequence of unsigned bytes lexicographically, so
 // use it if the requirements for `UnsignedBytewiseOrd` are fulfilled.
-impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
+impl<A, B> SliceOrd<B> for A
+where
+    A: UnsignedBytewiseOrd<B>,
+{
     #[inline]
-    fn compare(left: &[Self], right: &[Self]) -> Ordering {
+    fn compare(left: &[A], right: &[B]) -> Ordering {
         // Since the length of a slice is always less than or equal to
         // isize::MAX, this never underflows.
         let diff = left.len() as isize - right.len() as isize;
@@ -225,6 +194,7 @@ impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A {
     }
 }
 
+// trait for specialization of `slice::contains`
 pub(super) trait SliceContains: Sized {
     fn slice_contains(&self, x: &[Self]) -> bool;
 }