Why is this an issue?

Manually implementing PartialOrd for a type that derives Ord can lead to inconsistencies, as the implementations of these traits must agree for sorting and other comparisons. According to the trait contract, the following must hold for any type implementing Ord:

k1.cmp(&k2) == k1.partial_cmp(&k2).unwrap()

Using a default-generated Ord implementation with an explicitly defined PartialOrd is a risky practice that may cause unexpected behavior.

Code examples

Noncompliant code example

#[derive(Ord, PartialEq, Eq)]
struct Foo;

impl PartialOrd for Foo {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        None  // Noncompliant: Manually implemented PartialOrd when Ord is derived.
    }
}

Compliant solution

#[derive(PartialEq, Eq)]
struct Foo;

impl PartialOrd for Foo {
    fn partial_cmp(&self, other: &Foo) -> Option<Ordering> {
        Some(self.cmp(other)) // Compliant: Manual implementation is consistent with Ord.
    }
}

impl Ord for Foo {
    fn cmp(&self, other: &Foo) -> Ordering {
        // Implementation here
    }
}

Or, if a custom ordering is not needed:

#[derive(Ord, PartialOrd, PartialEq, Eq)]
struct Foo; // Compliant: Both Ord and PartialOrd are derived.

Resources

Documentation