Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ pub(crate) fn expand_deriving_partial_eq(
path: path_std!(marker::StructuralPartialEq),
skip_path_as_bound: true, // crucial!
needs_copy_as_bound_if_packed: false,
additional_bounds: Vec::new(),
// The `StructuralPartialEq` impl must have the *same* bounds as the `PartialEq` impl,
// or it will apply in situations where it should not, such as in the bug
// <https://github.com/rust-lang/rust/issues/147714>.
additional_bounds: vec![ty::Ty::Path(path_std!(cmp::PartialEq))],
// We really don't support unions, but that's already checked by the impl generated below;
// a second check here would lead to redundant error messages.
supports_unions: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// `derive(PartialEq)`, which also implements `StructuralPartialEq`, must not allow the latter impl
// to be used with other non-derived implementations of `PartialEq`.
//
// Test case by theemathas from <https://github.com/rust-lang/rust/issues/147714>.

#[allow(dead_code)]
#[derive(PartialEq)]
enum Thing<T> {
A(T),
B,
}

struct Incomparable;

// This impl does not obey StructuralPartialEq's rules.
impl PartialEq for Thing<Incomparable> {
fn eq(&self, _: &Self) -> bool {
panic!()
}
}

// This constant does not obey StructuralPartialEq's rules, so it should not
// implement StructuralPartialEq.
const X: Thing<Incomparable> = Thing::B;

fn main() {
if let X = X {
//~^ ERROR constant of non-structural type `Thing<Incomparable>` in a pattern
println!("equal");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: constant of non-structural type `Thing<Incomparable>` in a pattern
--> $DIR/derive-and-manual-partialeq-issue-147714.rs:27:12
|
LL | enum Thing<T> {
| ------------- `Thing<Incomparable>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
LL | const X: Thing<Incomparable> = Thing::B;
| ---------------------------- constant defined here
...
LL | if let X = X {
| ^ constant of non-structural type
|
help: if `Thing<Incomparable>` manually implemented `PartialEq`, you could check for equality instead of pattern matching
|
LL - if let X = X {
LL + if X == X {
|

error: aborting due to 1 previous error

2 changes: 1 addition & 1 deletion tests/ui/consts/const_in_pattern/issue-65466.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const C: &[O<B>] = &[O::None];
fn main() {
let x = O::None;
match &[x][..] {
C => (), //~ ERROR constant of non-structural type `&[O<B>]` in a pattern
C => (), //~ ERROR constant of non-structural type `O<B>` in a pattern
_ => (),
}
}
14 changes: 9 additions & 5 deletions tests/ui/consts/const_in_pattern/issue-65466.stderr
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
error: constant of non-structural type `&[O<B>]` in a pattern
error: constant of non-structural type `O<B>` in a pattern
--> $DIR/issue-65466.rs:14:9
|
LL | struct B;
| -------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
LL |
LL | enum O<T> {
| --------- `O<B>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
LL | const C: &[O<B>] = &[O::None];
| ---------------- constant defined here
...
LL | C => (),
| ^ constant of non-structural type
|
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
help: if `O<B>` manually implemented `PartialEq`, you could add a condition to the match arm checking for equality
|
LL - C => (),
LL + binding if binding == C => (),
|

error: aborting due to 1 previous error

14 changes: 10 additions & 4 deletions tests/ui/derives/deriving-all-codegen.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,10 @@ impl<T: ::core::hash::Hash + Trait, U: ::core::hash::Hash> ::core::hash::Hash
}
}
#[automatically_derived]
impl<T: Trait, U> ::core::marker::StructuralPartialEq for Generic<T, U> { }
impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
::core::marker::StructuralPartialEq for Generic<T, U> where
T::A: ::core::cmp::PartialEq {
}
#[automatically_derived]
impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
::core::cmp::PartialEq for Generic<T, U> where
Expand Down Expand Up @@ -953,8 +956,9 @@ impl<T: ::core::hash::Hash + ::core::marker::Copy + Trait,
}
}
#[automatically_derived]
impl<T: Trait, U> ::core::marker::StructuralPartialEq for PackedGeneric<T, U>
{
impl<T: ::core::cmp::PartialEq + Trait, U: ::core::cmp::PartialEq>
::core::marker::StructuralPartialEq for PackedGeneric<T, U> where
T::A: ::core::cmp::PartialEq {
}
#[automatically_derived]
impl<T: ::core::cmp::PartialEq + ::core::marker::Copy + Trait,
Expand Down Expand Up @@ -1678,7 +1682,9 @@ impl<T: ::core::hash::Hash, U: ::core::hash::Hash> ::core::hash::Hash for
}
}
#[automatically_derived]
impl<T, U> ::core::marker::StructuralPartialEq for EnumGeneric<T, U> { }
impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
::core::marker::StructuralPartialEq for EnumGeneric<T, U> {
}
#[automatically_derived]
impl<T: ::core::cmp::PartialEq, U: ::core::cmp::PartialEq>
::core::cmp::PartialEq for EnumGeneric<T, U> {
Expand Down
10 changes: 7 additions & 3 deletions tests/ui/match/issue-72896-non-partial-eq-const.stderr
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
error: constant of non-structural type `EnumSet<Enum8>` in a pattern
--> $DIR/issue-72896-non-partial-eq-const.rs:19:9
|
LL | enum Enum8 { }
| ---------- must be annotated with `#[derive(PartialEq)]` to be usable in patterns
LL | struct EnumSet<T: EnumSetType> {
| ------------------------------ `EnumSet<Enum8>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
...
LL | const CONST_SET: EnumSet<Enum8> = EnumSet { __enumset_underlying: 3 };
| ------------------------------- constant defined here
...
LL | CONST_SET => { /* ok */ }
| ^^^^^^^^^ constant of non-structural type
|
= note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
help: if `EnumSet<Enum8>` manually implemented `PartialEq`, you could add a condition to the match arm checking for equality
|
LL - CONST_SET => { /* ok */ }
LL + binding if binding == CONST_SET => { /* ok */ }
|

error: aborting due to 1 previous error

Loading