From b806dccdc41274152f91d1efb421f2e50b4ab463 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jan 2025 10:55:15 +0100 Subject: [PATCH] const-in-pattern: test that the PartialEq impl does not need to be const --- .../src/thir/pattern/const_to_pat.rs | 4 ++ .../const-traits/pattern-custom-partial-eq.rs | 54 +++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 tests/ui/traits/const-traits/pattern-custom-partial-eq.rs diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index aed00aecefc99..2b3c98db966cd 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -491,6 +491,10 @@ fn type_has_partial_eq_impl<'tcx>( // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck // can ensure that the type really implements `PartialEq`. + // We also do *not* require `const PartialEq`, not even in `const fn`. This violates the model + // that patterns can only do things that the code could also do without patterns, but it is + // needed for backwards compatibility. The actual pattern matching compares primitive values, + // `PartialEq::eq` never gets invoked, so there's no risk of us running non-const code. ( infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation), automatically_derived, diff --git a/tests/ui/traits/const-traits/pattern-custom-partial-eq.rs b/tests/ui/traits/const-traits/pattern-custom-partial-eq.rs new file mode 100644 index 0000000000000..1003775be2f0b --- /dev/null +++ b/tests/ui/traits/const-traits/pattern-custom-partial-eq.rs @@ -0,0 +1,54 @@ +//! Ensure that a `const fn` can match on constants of a type that is `PartialEq` +//! but not `const PartialEq`. This is accepted for backwards compatibility reasons. +//@ check-pass +#![feature(const_trait_impl)] + +#[derive(Eq, PartialEq)] +pub struct Y(u8); +pub const GREEN: Y = Y(4); +pub const fn is_green(x: Y) -> bool { + match x { GREEN => true, _ => false } +} + +struct CustomEq; + +impl Eq for CustomEq {} +impl PartialEq for CustomEq { + fn eq(&self, _: &Self) -> bool { + false + } +} + +#[derive(PartialEq, Eq)] +#[allow(unused)] +enum Foo { + Bar, + Baz, + Qux(CustomEq), +} + +const BAR_BAZ: Foo = if 42 == 42 { + Foo::Bar +} else { + Foo::Qux(CustomEq) // dead arm +}; + +const EMPTY: &[CustomEq] = &[]; + +const fn test() { + // BAR_BAZ itself is fine but the enum has other variants + // that are non-structural. Still, this should be accepted. + match Foo::Qux(CustomEq) { + BAR_BAZ => panic!(), + _ => {} + } + + // Similarly, an empty slice of a type that is non-structural + // is accepted. + match &[CustomEq] as &[CustomEq] { + EMPTY => panic!(), + _ => {}, + } +} + +fn main() {}