Skip to content

Commit e2ec55b

Browse files
committed
Add T: PartialEq bounds to derived StructuralPartialEq impls.
Fixes <#147714>.
1 parent 037b621 commit e2ec55b

7 files changed

Lines changed: 82 additions & 14 deletions

File tree

compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,10 @@ pub(crate) fn expand_deriving_partial_eq(
2222
path: path_std!(marker::StructuralPartialEq),
2323
skip_path_as_bound: true, // crucial!
2424
needs_copy_as_bound_if_packed: false,
25-
additional_bounds: Vec::new(),
25+
// The `StructuralPartialEq` impl must have the *same* bounds as the `PartialEq` impl,
26+
// or it will apply in situations where it should not, such as in the bug
27+
// <https://github.com/rust-lang/rust/issues/147714>.
28+
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::PartialEq))],
2629
// We really don't support unions, but that's already checked by the impl generated below;
2730
// a second check here would lead to redundant error messages.
2831
supports_unions: true,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// `derive(PartialEq)`, which also implements `StructuralPartialEq`, must not allow the latter impl
2+
// to be used with other non-derived implementations of `PartialEq`.
3+
//
4+
// Test case by theemathas from <https://github.com/rust-lang/rust/issues/147714>.
5+
6+
#[allow(dead_code)]
7+
#[derive(PartialEq)]
8+
enum Thing<T> {
9+
A(T),
10+
B,
11+
}
12+
13+
struct Incomparable;
14+
15+
// This impl does not obey StructuralPartialEq's rules.
16+
impl PartialEq for Thing<Incomparable> {
17+
fn eq(&self, _: &Self) -> bool {
18+
panic!()
19+
}
20+
}
21+
22+
// This constant does not obey StructuralPartialEq's rules, so it should not
23+
// implement StructuralPartialEq.
24+
const X: Thing<Incomparable> = Thing::B;
25+
26+
fn main() {
27+
if let X = X {
28+
//~^ ERROR constant of non-structural type `Thing<Incomparable>` in a pattern
29+
println!("equal");
30+
}
31+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
error: constant of non-structural type `Thing<Incomparable>` in a pattern
2+
--> $DIR/issue-147714.rs:27:12
3+
|
4+
LL | enum Thing<T> {
5+
| ------------- `Thing<Incomparable>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
6+
...
7+
LL | const X: Thing<Incomparable> = Thing::B;
8+
| ---------------------------- constant defined here
9+
...
10+
LL | if let X = X {
11+
| ^ constant of non-structural type
12+
|
13+
help: if `Thing<Incomparable>` manually implemented `PartialEq`, you could check for equality instead of pattern matching
14+
|
15+
LL - if let X = X {
16+
LL + if X == X {
17+
|
18+
19+
error: aborting due to 1 previous error
20+

tests/ui/consts/const_in_pattern/issue-65466.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const C: &[O<B>] = &[O::None];
1111
fn main() {
1212
let x = O::None;
1313
match &[x][..] {
14-
C => (), //~ ERROR constant of non-structural type `&[O<B>]` in a pattern
14+
C => (), //~ ERROR constant of non-structural type `O<B>` in a pattern
1515
_ => (),
1616
}
1717
}
Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
1-
error: constant of non-structural type `&[O<B>]` in a pattern
1+
error: constant of non-structural type `O<B>` in a pattern
22
--> $DIR/issue-65466.rs:14:9
33
|
4-
LL | struct B;
5-
| -------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
6-
LL |
4+
LL | enum O<T> {
5+
| --------- `O<B>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
6+
...
77
LL | const C: &[O<B>] = &[O::None];
88
| ---------------- constant defined here
99
...
1010
LL | C => (),
1111
| ^ constant of non-structural type
1212
|
13-
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
13+
help: if `O<B>` manually implemented `PartialEq`, you could add a condition to the match arm checking for equality
14+
|
15+
LL - C => (),
16+
LL + binding if binding == C => (),
17+
|
1418

1519
error: aborting due to 1 previous error
1620

tests/ui/derives/deriving-all-codegen.stdout

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -836,7 +836,10 @@ impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash
836836
}
837837
}
838838
#[automatically_derived]
839-
impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { }
839+
impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
840+
::core::marker::StructuralPartialEq for Generic<T, U> where
841+
T::A: ::core::cmp::PartialEq {
842+
}
840843
#[automatically_derived]
841844
impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
842845
::core::cmp::PartialEq for Generic<T, U> where
@@ -953,8 +956,9 @@ impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait,
953956
}
954957
}
955958
#[automatically_derived]
956-
impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U>
957-
{
959+
impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
960+
::core::marker::StructuralPartialEq for PackedGeneric<T, U> where
961+
T::A: ::core::cmp::PartialEq {
958962
}
959963
#[automatically_derived]
960964
impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
@@ -1678,7 +1682,9 @@ impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for
16781682
}
16791683
}
16801684
#[automatically_derived]
1681-
impl<T, U> ::core::marker::StructuralPartialEq for EnumGeneric<T, U> { }
1685+
impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
1686+
::core::marker::StructuralPartialEq for EnumGeneric<T, U> {
1687+
}
16821688
#[automatically_derived]
16831689
impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
16841690
::core::cmp::PartialEq for EnumGeneric<T, U> {
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
error: constant of non-structural type `EnumSet<Enum8>` in a pattern
22
--> $DIR/issue-72896-non-partial-eq-const.rs:19:9
33
|
4-
LL | enum Enum8 { }
5-
| ---------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
4+
LL | struct EnumSet<T: EnumSetType> {
5+
| ------------------------------ `EnumSet<Enum8>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
66
...
77
LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
88
| ------------------------------- constant defined here
99
...
1010
LL | CONST_SET => { /* ok */ }
1111
| ^^^^^^^^^ constant of non-structural type
1212
|
13-
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
13+
help: if `EnumSet<Enum8>` manually implemented `PartialEq`, you could add a condition to the match arm checking for equality
14+
|
15+
LL - CONST_SET => { /* ok */ }
16+
LL + binding if binding == CONST_SET => { /* ok */ }
17+
|
1418

1519
error: aborting due to 1 previous error
1620

0 commit comments

Comments
 (0)