https://gcc.gnu.org/g:5d01bb8c5525b464e7713a15b8db4ffc69a3025a

commit 5d01bb8c5525b464e7713a15b8db4ffc69a3025a
Author: Arthur Cohen <arthur.co...@embecosm.com>
Date:   Wed Apr 16 17:38:27 2025 +0200

    derive(PartialEq): Allow deriving enum structs
    
    gcc/rust/ChangeLog:
    
            * expand/rust-derive-partial-eq.cc 
(DerivePartialEq::match_enum_tuple): Remove debug call.
            (DerivePartialEq::match_enum_struct): Add proper implementation.
            (DerivePartialEq::visit_enum): Call it.
    
    gcc/testsuite/ChangeLog:
    
            * rust/execute/torture/derive-partialeq2.rs: New test.

Diff:
---
 gcc/rust/expand/rust-derive-partial-eq.cc          | 66 +++++++++++++++++-----
 .../rust/execute/torture/derive-partialeq2.rs      | 66 ++++++++++++++++++++++
 2 files changed, 118 insertions(+), 14 deletions(-)

diff --git a/gcc/rust/expand/rust-derive-partial-eq.cc 
b/gcc/rust/expand/rust-derive-partial-eq.cc
index ff66faabc781..22368bcb2b01 100644
--- a/gcc/rust/expand/rust-derive-partial-eq.cc
+++ b/gcc/rust/expand/rust-derive-partial-eq.cc
@@ -199,8 +199,6 @@ DerivePartialEq::match_enum_tuple (PathInExpression 
variant_path,
       auto self_pattern_str = "__self_" + std::to_string (i);
       auto other_pattern_str = "__other_" + std::to_string (i);
 
-      rust_debug ("]ARTHUR[ %s", self_pattern_str.c_str ());
-
       self_patterns.emplace_back (
        builder.identifier_pattern (self_pattern_str));
       other_patterns.emplace_back (
@@ -240,15 +238,55 @@ MatchCase
 DerivePartialEq::match_enum_struct (PathInExpression variant_path,
                                    const EnumItemStruct &variant)
 {
-  // NOTE: We currently do not support compiling struct patterns where an
-  // identifier is assigned a new pattern, e.g. Bloop { f0: x }
-  // This is what we should be using to compile PartialEq for enum struct
-  // variants, as we need to be comparing the field of each instance meaning we
-  // need to give two different names to two different instances of the same
-  // field. We cannot just use the field's name like we do when deriving
-  // `Clone`.
-
-  rust_unreachable ();
+  auto self_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+  auto other_fields = std::vector<std::unique_ptr<StructPatternField>> ();
+
+  auto self_other_exprs = std::vector<SelfOther> ();
+
+  for (auto &field : variant.get_struct_fields ())
+    {
+      // The patterns we're creating for each field are `self_<field>` and
+      // `other_<field>` where `field` is the name of the field. It doesn't
+      // actually matter what we use, as long as it's ordered, unique, and that
+      // we can reuse it in the match case's return expression to check that
+      // they are equal.
+
+      auto field_name = field.get_field_name ().as_string ();
+
+      auto self_pattern_str = "__self_" + field_name;
+      auto other_pattern_str = "__other_" + field_name;
+
+      self_fields.emplace_back (builder.struct_pattern_ident_pattern (
+       field_name, builder.identifier_pattern (self_pattern_str)));
+      other_fields.emplace_back (builder.struct_pattern_ident_pattern (
+       field_name, builder.identifier_pattern (other_pattern_str)));
+
+      self_other_exprs.emplace_back (SelfOther{
+       builder.identifier (self_pattern_str),
+       builder.identifier (other_pattern_str),
+      });
+    }
+
+  auto self_elts = StructPatternElements (std::move (self_fields));
+  auto other_elts = StructPatternElements (std::move (other_fields));
+
+  auto self_pattern = std::unique_ptr<Pattern> (
+    new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
+                           variant_path, loc, std::move (self_elts))),
+                         false, false, loc));
+  auto other_pattern = std::unique_ptr<Pattern> (
+    new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
+                           variant_path, loc, std::move (other_elts))),
+                         false, false, loc));
+
+  auto tuple_items = std::make_unique<TuplePatternItemsMultiple> (
+    vec (std::move (self_pattern), std::move (other_pattern)));
+
+  auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
+
+  auto expr = build_eq_expression (std::move (self_other_exprs));
+
+  return builder.match_case (std::move (pattern), std::move (expr));
 }
 
 void
@@ -275,9 +313,9 @@ DerivePartialEq::visit_enum (Enum &item)
                              static_cast<EnumItemTuple &> (*variant)));
          break;
        case EnumItem::Kind::Struct:
-         rust_sorry_at (
-           item.get_locus (),
-           "cannot derive(PartialEq) for enum struct variants yet");
+         cases.emplace_back (
+           match_enum_struct (variant_path,
+                              static_cast<EnumItemStruct &> (*variant)));
          break;
        }
     }
diff --git a/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs 
b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs
new file mode 100644
index 000000000000..15374d9f5bf0
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/derive-partialeq2.rs
@@ -0,0 +1,66 @@
+// { dg-output "true\r*\nfalse\r*\nfalse\r*\nfalse\r*\nfalse\r*\n" }
+
+#![feature(intrinsics)]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "structural_peq"]
+trait StructuralPartialEq {}
+
+#[lang = "eq"]
+pub trait PartialEq<Rhs: ?Sized = Self> {
+    /// This method tests for `self` and `other` values to be equal, and is 
used
+    /// by `==`.
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn eq(&self, other: &Rhs) -> bool;
+
+    /// This method tests for `!=`.
+    #[inline]
+    #[must_use]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    fn ne(&self, other: &Rhs) -> bool {
+        !self.eq(other)
+    }
+}
+
+#[derive(PartialEq)]
+enum Foo {
+    A { a: i32, b: i32 },
+    B(i32, i32),
+    C,
+}
+
+extern "C" {
+    fn puts(s: *const i8);
+}
+
+fn print(b: bool) {
+    if b {
+        unsafe { puts("true" as *const str as *const i8) }
+    } else {
+        unsafe { puts("false" as *const str as *const i8) }
+    }
+}
+
+fn main() -> i32 {
+    let x = Foo::A { a: 15, b: 14 };
+
+    let b1 = x == Foo::A { a: 15, b: 14 };
+    let b12 = x == Foo::A { a: 15, b: 19 };
+    let b13 = x == Foo::A { a: 19, b: 14 };
+    let b2 = x == Foo::B(15, 14);
+    let b3 = x == Foo::C;
+
+    print(b1);
+    print(b12);
+    print(b13);
+    print(b2);
+    print(b3);
+
+    0
+}

Reply via email to