about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2025-01-04 09:54:38 +0100
committerGitHub <noreply@github.com>2025-01-04 09:54:38 +0100
commit966a5be5598863d3acf2226a7e080c63d1929a0e (patch)
tree4c312bbb918281fb521ad096eb4dee1d4b024fdb
parentb0b54f2f8bbf62e130b5249af7e6da71a655a164 (diff)
parentb806dccdc41274152f91d1efb421f2e50b4ab463 (diff)
downloadrust-966a5be5598863d3acf2226a7e080c63d1929a0e.tar.gz
rust-966a5be5598863d3acf2226a7e080c63d1929a0e.zip
Rollup merge of #135064 - RalfJung:const-in-pat-partial-eq-not-const, r=compiler-errors
const-in-pattern: test that the PartialEq impl does not need to be const

Fixes https://github.com/rust-lang/rust/issues/119398 by adding a test.

`@compiler-errors`  is there some place in the code where we could add a comment saying "as a backcompat hack, here we only require `PartialEq` and not `const PartialEq`"?

r? `@compiler-errors`
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs4
-rw-r--r--tests/ui/traits/const-traits/pattern-custom-partial-eq.rs54
2 files changed, 58 insertions, 0 deletions
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 aed00aecefc..2b3c98db966 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 00000000000..1003775be2f
--- /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() {}