Allow expect on impl for derive_ord_xor_partial_ord (#16303)

Closes rust-lang/rust-clippy#16298

This lint flags on the type defination, while also giving a warning on
the span of the impl block. It is counter-intuitive that you need to put
the `expect` on top of the type defination instead of the impl block to
suppress the warning, and this PR addresses that.

changelog: [`derive_ord_xor_partial_ord`] allow `expect` on `impl` block
This commit is contained in:
Jason Newcomb 2026-01-06 19:14:14 +00:00 committed by GitHub
commit d227bf4b96
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 21 additions and 4 deletions

View file

@ -1,15 +1,16 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::fulfill_or_allowed;
use rustc_hir::{self as hir, HirId};
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
use rustc_span::{Span, sym};
use rustc_span::sym;
use super::DERIVE_ORD_XOR_PARTIAL_ORD;
/// Implementation of the `DERIVE_ORD_XOR_PARTIAL_ORD` lint.
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
span: Span,
item: &hir::Item<'_>,
trait_ref: &hir::TraitRef<'_>,
ty: Ty<'tcx>,
adt_hir_id: HirId,
@ -19,6 +20,8 @@ pub(super) fn check<'tcx>(
&& let Some(partial_ord_trait_def_id) = cx.tcx.lang_items().partial_ord_trait()
&& let Some(def_id) = &trait_ref.trait_def_id()
&& *def_id == ord_trait_def_id
&& let item_hir_id = cx.tcx.local_def_id_to_hir_id(item.owner_id)
&& !fulfill_or_allowed(cx, DERIVE_ORD_XOR_PARTIAL_ORD, [adt_hir_id])
{
// Look for the PartialOrd implementations for `ty`
cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
@ -39,7 +42,7 @@ pub(super) fn check<'tcx>(
"you are deriving `Ord` but have implemented `PartialOrd` explicitly"
};
span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, adt_hir_id, span, mess, |diag| {
span_lint_hir_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, item_hir_id, item.span, mess, |diag| {
if let Some(local_def_id) = impl_id.as_local() {
let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id);
diag.span_note(cx.tcx.hir_span(hir_id), "`PartialOrd` implemented here");

View file

@ -208,7 +208,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
derived_hash_with_manual_eq::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived);
derive_ord_xor_partial_ord::check(cx, item.span, trait_ref, ty, adt_hir_id, is_automatically_derived);
derive_ord_xor_partial_ord::check(cx, item, trait_ref, ty, adt_hir_id, is_automatically_derived);
if is_automatically_derived {
unsafe_derive_deserialize::check(cx, item, trait_ref, ty, adt_hir_id);

View file

@ -91,3 +91,17 @@ mod issue15708 {
}
}
}
mod issue16298 {
#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
struct Normalized<S>(S);
impl<S: Eq> Eq for Normalized<S> {}
#[expect(clippy::derive_ord_xor_partial_ord)]
impl<S: Eq + PartialOrd> Ord for Normalized<S> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.partial_cmp(other).unwrap()
}
}
}