From: Arthur Cohen <arthur.co...@embecosm.com>

gcc/rust/ChangeLog:

        * expand/rust-derive-clone.cc (DeriveClone::variant_match_path): New 
function.
        (DeriveClone::clone_enum_identifier): Rename.
        (DeriveClone::clone_enum_tuple): New function.
        (DeriveClone::visit_enum): Visit tuple variants properly.
        * expand/rust-derive-clone.h: Declare new functions.
---
 gcc/rust/expand/rust-derive-clone.cc | 58 ++++++++++++++++++++++++++--
 gcc/rust/expand/rust-derive-clone.h  | 12 ++++++
 2 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/gcc/rust/expand/rust-derive-clone.cc 
b/gcc/rust/expand/rust-derive-clone.cc
index e4702d8a818..c2994b7b4f8 100644
--- a/gcc/rust/expand/rust-derive-clone.cc
+++ b/gcc/rust/expand/rust-derive-clone.cc
@@ -21,6 +21,8 @@
 #include "rust-ast-dump.h"
 #include "rust-item.h"
 #include "rust-path.h"
+#include "rust-pattern.h"
+#include "rust-system.h"
 
 namespace Rust {
 namespace AST {
@@ -236,14 +238,20 @@ DeriveClone::visit_struct (StructStruct &item)
                         item.get_generic_params ());
 }
 
+PathInExpression
+DeriveClone::variant_match_path (Enum &item, const Identifier &variant)
+{
+  return PathInExpression ({builder.path_segment (
+                             item.get_identifier ().as_string ()),
+                           builder.path_segment (variant.as_string ())},
+                          {}, loc, false);
+}
+
 MatchCase
 DeriveClone::clone_enum_identifier (Enum &item,
                                    const std::unique_ptr<EnumItem> &variant)
 {
-  auto variant_path = PathInExpression (
-    {builder.path_segment (item.get_identifier ().as_string ()),
-     builder.path_segment (variant->get_identifier ().as_string ())},
-    {}, loc, false);
+  auto variant_path = variant_match_path (item, variant->get_identifier ());
 
   auto pattern = std::unique_ptr<Pattern> (new ReferencePattern (
     std::unique_ptr<Pattern> (new PathInExpression (variant_path)), false,
@@ -253,6 +261,45 @@ DeriveClone::clone_enum_identifier (Enum &item,
   return builder.match_case (std::move (pattern), std::move (expr));
 }
 
+MatchCase
+DeriveClone::clone_enum_tuple (Enum &item, const EnumItemTuple &variant)
+{
+  auto variant_path = variant_match_path (item, variant.get_identifier ());
+
+  auto patterns = std::vector<std::unique_ptr<Pattern>> ();
+  auto cloned_patterns = std::vector<std::unique_ptr<Expr>> ();
+
+  for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++)
+    {
+      // The pattern we're creating for each field is `self_<i>` where `i` is
+      // the index 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 clone the field.
+      auto pattern_str = "__self_" + std::to_string (i);
+
+      patterns.emplace_back (builder.identifier_pattern (pattern_str));
+
+      // Now, for each tuple's element, we create a new expression calling
+      // `clone` on it for the match case's return expression
+      cloned_patterns.emplace_back (
+       clone_call (builder.ref (builder.identifier (pattern_str))));
+    }
+
+  auto pattern_items = std::unique_ptr<TupleStructItems> (
+    new TupleStructItemsNoRange (std::move (patterns)));
+
+  auto pattern = std::unique_ptr<Pattern> (
+    new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
+                           variant_path, std::move (pattern_items))),
+                         false, false, loc));
+
+  auto expr
+    = builder.call (std::unique_ptr<Expr> (new PathInExpression 
(variant_path)),
+                   std::move (cloned_patterns));
+
+  return builder.match_case (std::move (pattern), std::move (expr));
+}
+
 void
 DeriveClone::visit_enum (Enum &item)
 {
@@ -274,6 +321,9 @@ DeriveClone::visit_enum (Enum &item)
          cases.emplace_back (clone_enum_identifier (item, variant));
          break;
        case EnumItem::Kind::Tuple:
+         cases.emplace_back (
+           clone_enum_tuple (item, static_cast<EnumItemTuple &> (*variant)));
+         break;
        case EnumItem::Kind::Struct:
          rust_unreachable ();
          break;
diff --git a/gcc/rust/expand/rust-derive-clone.h 
b/gcc/rust/expand/rust-derive-clone.h
index 339cf6357ae..d48ec5d2889 100644
--- a/gcc/rust/expand/rust-derive-clone.h
+++ b/gcc/rust/expand/rust-derive-clone.h
@@ -63,8 +63,20 @@ private:
   clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn, std::string name,
              const std::vector<std::unique_ptr<GenericParam>> &type_generics);
 
+  /**
+   * Get the path to use for matching and creating a variant when matching on 
an
+   * enum. E.g. for the `Option` enum, with the `None` variant, this will 
create
+   * a path `Option::None`
+   */
+  PathInExpression variant_match_path (Enum &item, const Identifier &variant);
+
+  /**
+   * Implementation of clone for all possible variants of an enum
+   */
   MatchCase clone_enum_identifier (Enum &item,
                                   const std::unique_ptr<EnumItem> &variant);
+  MatchCase clone_enum_tuple (Enum &item, const EnumItemTuple &variant);
+  MatchCase clone_enum_struct (Enum &item, const EnumItemStruct &variant);
 
   virtual void visit_struct (StructStruct &item);
   virtual void visit_tuple (TupleStruct &item);
-- 
2.45.2

Reply via email to