https://gcc.gnu.org/g:535aaf9882c44598c89a8d91153b831c11cb9ea1

commit r16-2852-g535aaf9882c44598c89a8d91153b831c11cb9ea1
Author: Arthur Cohen <arthur.co...@embecosm.com>
Date:   Fri Mar 7 17:08:34 2025 +0000

    gccrs: derive(Ord, PartialOrd): Add base for deriving them.
    
    gcc/rust/ChangeLog:
    
            * Make-lang.in: Compile it.
            * expand/rust-derive.cc (DeriveVisitor::derive): Call them.
            * expand/rust-derive-ord.cc: New file.
            * expand/rust-derive-ord.h: New file.

Diff:
---
 gcc/rust/Make-lang.in              |   1 +
 gcc/rust/expand/rust-derive-ord.cc | 172 +++++++++++++++++++++++++++++++++++++
 gcc/rust/expand/rust-derive-ord.h  |  74 ++++++++++++++++
 gcc/rust/expand/rust-derive.cc     |   6 +-
 4 files changed, 251 insertions(+), 2 deletions(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 399271a3bc74..c919b3d43e25 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -100,6 +100,7 @@ GRS_OBJS = \
     rust/rust-derive-default.o \
     rust/rust-derive-partial-eq.o \
     rust/rust-derive-eq.o \
+    rust/rust-derive-ord.o \
     rust/rust-derive-hash.o \
     rust/rust-proc-macro.o \
     rust/rust-macro-invoc-lexer.o \
diff --git a/gcc/rust/expand/rust-derive-ord.cc 
b/gcc/rust/expand/rust-derive-ord.cc
new file mode 100644
index 000000000000..7eaaa474d1bf
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-ord.cc
@@ -0,0 +1,172 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-derive-ord.h"
+#include "rust-ast-dump.h"
+#include "rust-ast.h"
+#include "rust-derive.h"
+#include "rust-item.h"
+
+namespace Rust {
+namespace AST {
+
+DeriveOrd::DeriveOrd (Ordering ordering, location_t loc)
+  : DeriveVisitor (loc), ordering (ordering)
+{}
+
+std::unique_ptr<Item>
+DeriveOrd::go (Item &item)
+{
+  item.accept_vis (*this);
+
+  AST::Dump::debug (*expanded);
+
+  return std::move (expanded);
+}
+
+std::unique_ptr<Item>
+DeriveOrd::cmp_impl (
+  std::unique_ptr<BlockExpr> &&fn_block, Identifier type_name,
+  const std::vector<std::unique_ptr<GenericParam>> &type_generics)
+{
+  auto fn = cmp_fn (std::move (fn_block), type_name);
+
+  auto trait = ordering == Ordering::Partial ? "PartialOrd" : "Ord";
+  auto trait_path = builder.type_path ({"core", "cmp", trait}, true);
+
+  auto trait_bound
+    = builder.trait_bound (builder.type_path ({"core", "cmp", trait}, true));
+
+  auto trait_items = vec (std::move (fn));
+
+  auto cmp_generics
+    = setup_impl_generics (type_name.as_string (), type_generics,
+                          std::move (trait_bound));
+
+  return builder.trait_impl (trait_path, std::move (cmp_generics.self_type),
+                            std::move (trait_items),
+                            std::move (cmp_generics.impl));
+}
+
+std::unique_ptr<AssociatedItem>
+DeriveOrd::cmp_fn (std::unique_ptr<BlockExpr> &&block, Identifier type_name)
+{
+  // Ordering
+  auto return_type = builder.type_path ({"core", "cmp", "Ordering"}, true);
+
+  // In the case of PartialOrd, we return an Option<Ordering>
+  if (ordering == Ordering::Partial)
+    {
+      auto generic = GenericArg::create_type (ptrify (return_type));
+
+      auto generic_seg = builder.type_path_segment_generic (
+       "Option", GenericArgs ({}, {generic}, {}, loc));
+      auto core = builder.type_path_segment ("core");
+      auto option = builder.type_path_segment ("option");
+
+      return_type
+       = builder.type_path (vec (std::move (core), std::move (option),
+                                 std::move (generic_seg)),
+                            true);
+    }
+
+  // &self, other: &Self
+  auto params = vec (
+    builder.self_ref_param (),
+    builder.function_param (builder.identifier_pattern ("other"),
+                           builder.reference_type (ptrify (
+                             builder.type_path (type_name.as_string ())))));
+
+  auto function_name = ordering == Ordering::Partial ? "partial_cmp" : "cmp";
+
+  return builder.function (function_name, std::move (params),
+                          ptrify (return_type), std::move (block));
+}
+std::unique_ptr<Expr>
+recursive_match ()
+{
+  return nullptr;
+}
+
+// we need to do a recursive match expression for all of the fields used in a
+// struct so for something like struct Foo { a: i32, b: i32, c: i32 } we must
+// first compare each `a` field, then `b`, then `c`, like this:
+//
+// match cmp_fn(self.<field>, other.<field>) {
+//     Ordering::Equal => <recurse>,
+//     cmp => cmp,
+// }
+//
+// and the recurse will be the exact same expression, on the next field. so 
that
+// our result looks like this:
+//
+// match cmp_fn(self.a, other.a) {
+//     Ordering::Equal => match cmp_fn(self.b, other.b) {
+//         Ordering::Equal =>cmp_fn(self.c, other.c),
+//         cmp => cmp,
+//     }
+//     cmp => cmp,
+// }
+//
+// the last field comparison needs not to be a match but just the function 
call.
+// this is going to be annoying lol
+void
+DeriveOrd::visit_struct (StructStruct &item)
+{
+  // FIXME: Put cmp_fn call inside cmp_impl, pass a block to cmp_impl instead -
+  // this avoids repeating the same parameter twice (the type name)
+  expanded = cmp_impl (builder.block (), item.get_identifier (),
+                      item.get_generic_params ());
+}
+
+// same as structs, but for each field index instead of each field name -
+// straightforward once we have `visit_struct` working
+void
+DeriveOrd::visit_tuple (TupleStruct &item)
+{}
+
+// for enums, we need to generate a match for each of the enum's variant that
+// contains data and then do the same thing as visit_struct or visit_enum. if
+// the two aren't the same variant, then compare the two discriminant values 
for
+// all the dataless enum variants and in the general case.
+//
+// so for enum Foo { A(i32, i32), B, C } we need to do the following
+//
+// match (self, other) {
+//     (A(self_0, self_1), A(other_0, other_1)) => {
+//         match cmp_fn(self_0, other_0) {
+//             Ordering::Equal => cmp_fn(self_1, other_1),
+//             cmp => cmp,
+//         },
+//     _ => cmp_fn(discr_value(self), discr_value(other))
+// }
+void
+DeriveOrd::visit_enum (Enum &item)
+{}
+
+void
+DeriveOrd::visit_union (Union &item)
+{
+  auto trait_name = ordering == Ordering::Total ? "Ord" : "PartialOrd";
+
+  rust_error_at (item.get_locus (), "derive(%s) cannot be used on unions",
+                trait_name);
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-derive-ord.h 
b/gcc/rust/expand/rust-derive-ord.h
new file mode 100644
index 000000000000..fae13261e7c4
--- /dev/null
+++ b/gcc/rust/expand/rust-derive-ord.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2025 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_DERIVE_ORD_H
+#define RUST_DERIVE_ORD_H
+
+#include "rust-ast.h"
+#include "rust-derive.h"
+
+namespace Rust {
+namespace AST {
+
+/**
+ * DeriveOrd is a bit special as the expansion of both `PartialOrd` and `Ord`
+ * is extremely similar. The only difference is that `PartialOrd` concerns
+ * partial-ordering, and thus its main method returns an `Option<Ordering>`,
+ * while `Ord` concerns total-ordering, and its main method returns an
+ * `Ordering`. Otherwise, the expansion logic is the same, so we factor both
+ * derives into one.
+ */
+class DeriveOrd : public DeriveVisitor
+{
+public:
+  enum class Ordering
+  {
+    Total,
+    Partial
+  };
+
+  DeriveOrd (Ordering ordering, location_t loc);
+
+  std::unique_ptr<Item> go (Item &item);
+
+private:
+  std::unique_ptr<Item> expanded;
+
+  Ordering ordering;
+
+  /**
+   * Create the recursive matching structure used when implementing the
+   * comparison function on multiple sub items (fields, tuple indexes...) */
+  std::unique_ptr<Expr> recursive_match ();
+
+  std::unique_ptr<Item>
+  cmp_impl (std::unique_ptr<BlockExpr> &&fn_block, Identifier type_name,
+           const std::vector<std::unique_ptr<GenericParam>> &type_generics);
+  std::unique_ptr<AssociatedItem> cmp_fn (std::unique_ptr<BlockExpr> &&block,
+                                         Identifier type_name);
+
+  virtual void visit_struct (StructStruct &item) override;
+  virtual void visit_tuple (TupleStruct &item) override;
+  virtual void visit_enum (Enum &item) override;
+  virtual void visit_union (Union &item) override;
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // ! RUST_DERIVE_ORD_H
diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc
index 0e8a67c17a34..69081db29ada 100644
--- a/gcc/rust/expand/rust-derive.cc
+++ b/gcc/rust/expand/rust-derive.cc
@@ -22,6 +22,7 @@
 #include "rust-derive-debug.h"
 #include "rust-derive-default.h"
 #include "rust-derive-eq.h"
+#include "rust-derive-ord.h"
 #include "rust-derive-partial-eq.h"
 #include "rust-derive-hash.h"
 
@@ -59,10 +60,11 @@ DeriveVisitor::derive (Item &item, const Attribute &attr,
     case BuiltinMacro::Hash:
       return vec (DeriveHash (loc).go (item));
     case BuiltinMacro::Ord:
+      return vec (DeriveOrd (DeriveOrd::Ordering::Total, loc).go (item));
     case BuiltinMacro::PartialOrd:
+      return vec (DeriveOrd (DeriveOrd::Ordering::Partial, loc).go (item));
     default:
-      rust_sorry_at (loc, "unimplemented builtin derive macro");
-      return {};
+      rust_unreachable ();
     };
 }

Reply via email to