Skip to content

Commit decaba9

Browse files
committed
Auto merge of rust-lang#10184 - robertbastian:master, r=xFrednet
Allow implementing `Hash` with derived `PartialEq` (`derive_hash_xor_eq` This is a common pattern and is totally allowed by the `Hash` trait. Fixes rust-lang#2627 changelog: Move: Renamed `derive_hash_xor_eq` to [`derived_hash_with_manual_eq`] [rust-lang#10184](rust-lang/rust-clippy#10184) changelog: Enhancement: [`derived_hash_with_manual_eq`]: Now allows `#[derive(PartialEq)]` with custom `Hash` implementations [rust-lang#10184](rust-lang/rust-clippy#10184) <!-- changelog_checked -->
2 parents 7c01721 + 9206332 commit decaba9

10 files changed

+92
-133
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -4137,6 +4137,7 @@ Released 2018-09-13
41374137
[`derive_hash_xor_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_hash_xor_eq
41384138
[`derive_ord_xor_partial_ord`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_ord_xor_partial_ord
41394139
[`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
4140+
[`derived_hash_with_manual_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derived_hash_with_manual_eq
41404141
[`disallowed_macros`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_macros
41414142
[`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
41424143
[`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods

clippy_lints/src/declared_lints.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
111111
crate::dereference::NEEDLESS_BORROW_INFO,
112112
crate::dereference::REF_BINDING_TO_REFERENCE_INFO,
113113
crate::derivable_impls::DERIVABLE_IMPLS_INFO,
114-
crate::derive::DERIVE_HASH_XOR_EQ_INFO,
114+
crate::derive::DERIVED_HASH_WITH_MANUAL_EQ_INFO,
115115
crate::derive::DERIVE_ORD_XOR_PARTIAL_ORD_INFO,
116116
crate::derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ_INFO,
117117
crate::derive::EXPL_IMPL_CLONE_ON_COPY_INFO,

clippy_lints/src/derive.rs

+6-12
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ declare_clippy_lint! {
4646
/// }
4747
/// ```
4848
#[clippy::version = "pre 1.29.0"]
49-
pub DERIVE_HASH_XOR_EQ,
49+
pub DERIVED_HASH_WITH_MANUAL_EQ,
5050
correctness,
5151
"deriving `Hash` but implementing `PartialEq` explicitly"
5252
}
@@ -197,7 +197,7 @@ declare_clippy_lint! {
197197

198198
declare_lint_pass!(Derive => [
199199
EXPL_IMPL_CLONE_ON_COPY,
200-
DERIVE_HASH_XOR_EQ,
200+
DERIVED_HASH_WITH_MANUAL_EQ,
201201
DERIVE_ORD_XOR_PARTIAL_ORD,
202202
UNSAFE_DERIVE_DESERIALIZE,
203203
DERIVE_PARTIAL_EQ_WITHOUT_EQ
@@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for Derive {
226226
}
227227
}
228228

229-
/// Implementation of the `DERIVE_HASH_XOR_EQ` lint.
229+
/// Implementation of the `DERIVED_HASH_WITH_MANUAL_EQ` lint.
230230
fn check_hash_peq<'tcx>(
231231
cx: &LateContext<'tcx>,
232232
span: Span,
@@ -243,7 +243,7 @@ fn check_hash_peq<'tcx>(
243243
cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
244244
let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
245245

246-
if peq_is_automatically_derived == hash_is_automatically_derived {
246+
if !hash_is_automatically_derived || peq_is_automatically_derived {
247247
return;
248248
}
249249

@@ -252,17 +252,11 @@ fn check_hash_peq<'tcx>(
252252
// Only care about `impl PartialEq<Foo> for Foo`
253253
// For `impl PartialEq<B> for A, input_types is [A, B]
254254
if trait_ref.substs.type_at(1) == ty {
255-
let mess = if peq_is_automatically_derived {
256-
"you are implementing `Hash` explicitly but have derived `PartialEq`"
257-
} else {
258-
"you are deriving `Hash` but have implemented `PartialEq` explicitly"
259-
};
260-
261255
span_lint_and_then(
262256
cx,
263-
DERIVE_HASH_XOR_EQ,
257+
DERIVED_HASH_WITH_MANUAL_EQ,
264258
span,
265-
mess,
259+
"you are deriving `Hash` but have implemented `PartialEq` explicitly",
266260
|diag| {
267261
if let Some(local_def_id) = impl_id.as_local() {
268262
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id);

clippy_lints/src/renamed_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
99
("clippy::box_vec", "clippy::box_collection"),
1010
("clippy::const_static_lifetime", "clippy::redundant_static_lifetimes"),
1111
("clippy::cyclomatic_complexity", "clippy::cognitive_complexity"),
12+
("clippy::derive_hash_xor_eq", "clippy::derived_hash_with_manual_eq"),
1213
("clippy::disallowed_method", "clippy::disallowed_methods"),
1314
("clippy::disallowed_type", "clippy::disallowed_types"),
1415
("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"),

tests/ui/derive_hash_xor_eq.stderr

-59
This file was deleted.

tests/ui/derive_hash_xor_eq.rs tests/ui/derived_hash_with_manual_eq.rs

+2-19
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,13 @@ impl PartialEq<Baz> for Baz {
2727
}
2828
}
2929

30+
// Implementing `Hash` with a derived `PartialEq` is fine. See #2627
31+
3032
#[derive(PartialEq)]
3133
struct Bah;
3234

3335
impl std::hash::Hash for Bah {
3436
fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
3537
}
3638

37-
#[derive(PartialEq)]
38-
struct Foo2;
39-
40-
trait Hash {}
41-
42-
// We don't want to lint on user-defined traits called `Hash`
43-
impl Hash for Foo2 {}
44-
45-
mod use_hash {
46-
use std::hash::{Hash, Hasher};
47-
48-
#[derive(PartialEq)]
49-
struct Foo3;
50-
51-
impl Hash for Foo3 {
52-
fn hash<H: std::hash::Hasher>(&self, _: &mut H) {}
53-
}
54-
}
55-
5639
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error: you are deriving `Hash` but have implemented `PartialEq` explicitly
2+
--> $DIR/derived_hash_with_manual_eq.rs:12:10
3+
|
4+
LL | #[derive(Hash)]
5+
| ^^^^
6+
|
7+
note: `PartialEq` implemented here
8+
--> $DIR/derived_hash_with_manual_eq.rs:15:1
9+
|
10+
LL | impl PartialEq for Bar {
11+
| ^^^^^^^^^^^^^^^^^^^^^^
12+
= note: `#[deny(clippy::derived_hash_with_manual_eq)]` on by default
13+
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
14+
15+
error: you are deriving `Hash` but have implemented `PartialEq` explicitly
16+
--> $DIR/derived_hash_with_manual_eq.rs:21:10
17+
|
18+
LL | #[derive(Hash)]
19+
| ^^^^
20+
|
21+
note: `PartialEq` implemented here
22+
--> $DIR/derived_hash_with_manual_eq.rs:24:1
23+
|
24+
LL | impl PartialEq<Baz> for Baz {
25+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
26+
= note: this error originates in the derive macro `Hash` (in Nightly builds, run with -Z macro-backtrace for more info)
27+
28+
error: aborting due to 2 previous errors
29+

tests/ui/rename.fixed

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![allow(clippy::box_collection)]
1111
#![allow(clippy::redundant_static_lifetimes)]
1212
#![allow(clippy::cognitive_complexity)]
13+
#![allow(clippy::derived_hash_with_manual_eq)]
1314
#![allow(clippy::disallowed_methods)]
1415
#![allow(clippy::disallowed_types)]
1516
#![allow(clippy::mixed_read_write_in_expression)]
@@ -45,6 +46,7 @@
4546
#![warn(clippy::box_collection)]
4647
#![warn(clippy::redundant_static_lifetimes)]
4748
#![warn(clippy::cognitive_complexity)]
49+
#![warn(clippy::derived_hash_with_manual_eq)]
4850
#![warn(clippy::disallowed_methods)]
4951
#![warn(clippy::disallowed_types)]
5052
#![warn(clippy::mixed_read_write_in_expression)]

tests/ui/rename.rs

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#![allow(clippy::box_collection)]
1111
#![allow(clippy::redundant_static_lifetimes)]
1212
#![allow(clippy::cognitive_complexity)]
13+
#![allow(clippy::derived_hash_with_manual_eq)]
1314
#![allow(clippy::disallowed_methods)]
1415
#![allow(clippy::disallowed_types)]
1516
#![allow(clippy::mixed_read_write_in_expression)]
@@ -45,6 +46,7 @@
4546
#![warn(clippy::box_vec)]
4647
#![warn(clippy::const_static_lifetime)]
4748
#![warn(clippy::cyclomatic_complexity)]
49+
#![warn(clippy::derive_hash_xor_eq)]
4850
#![warn(clippy::disallowed_method)]
4951
#![warn(clippy::disallowed_type)]
5052
#![warn(clippy::eval_order_dependence)]

0 commit comments

Comments
 (0)