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

gcc/rust/ChangeLog:

        * expand/rust-derive.cc (DeriveVisitor::setup_impl_generics): New 
method.
        * expand/rust-derive.h: Declare it, define DeriveVisitor::ImplGenerics 
struct.
---
 gcc/rust/expand/rust-derive.cc | 74 ++++++++++++++++++++++++++++++++++
 gcc/rust/expand/rust-derive.h  | 23 +++++++++++
 2 files changed, 97 insertions(+)

diff --git a/gcc/rust/expand/rust-derive.cc b/gcc/rust/expand/rust-derive.cc
index a3784837ad7..13675ba594c 100644
--- a/gcc/rust/expand/rust-derive.cc
+++ b/gcc/rust/expand/rust-derive.cc
@@ -50,5 +50,79 @@ DeriveVisitor::derive (Item &item, const Attribute &attr,
     };
 }
 
+DeriveVisitor::ImplGenerics
+DeriveVisitor::setup_impl_generics (
+  const std::string &type_name,
+  const std::vector<std::unique_ptr<GenericParam>> &type_generics,
+  tl::optional<std::unique_ptr<TypeParamBound>> &&extra_bound) const
+{
+  std::vector<Lifetime> lifetime_args;
+  std::vector<GenericArg> generic_args;
+  std::vector<std::unique_ptr<GenericParam>> impl_generics;
+  for (const auto &generic : type_generics)
+    {
+      switch (generic->get_kind ())
+       {
+         case GenericParam::Kind::Lifetime: {
+           LifetimeParam &lifetime_param = (LifetimeParam &) *generic.get ();
+
+           Lifetime l = builder.new_lifetime (lifetime_param.get_lifetime ());
+           lifetime_args.push_back (std::move (l));
+
+           auto impl_lifetime_param
+             = builder.new_lifetime_param (lifetime_param);
+           impl_generics.push_back (std::move (impl_lifetime_param));
+         }
+         break;
+
+         case GenericParam::Kind::Type: {
+           TypeParam &type_param = (TypeParam &) *generic.get ();
+
+           std::unique_ptr<Type> associated_type = builder.single_type_path (
+             type_param.get_type_representation ().as_string ());
+
+           GenericArg type_arg
+             = GenericArg::create_type (std::move (associated_type));
+           generic_args.push_back (std::move (type_arg));
+
+           std::vector<std::unique_ptr<TypeParamBound>> extra_bounds;
+
+           if (extra_bound)
+             extra_bounds.emplace_back (std::move (*extra_bound));
+
+           auto impl_type_param
+             = builder.new_type_param (type_param, std::move (extra_bounds));
+
+           impl_generics.push_back (std::move (impl_type_param));
+         }
+         break;
+
+         case GenericParam::Kind::Const: {
+           rust_unreachable ();
+
+           // TODO
+           // const ConstGenericParam *const_param
+           //   = (const ConstGenericParam *) generic.get ();
+           // std::unique_ptr<Expr> const_expr = nullptr;
+
+           // GenericArg type_arg
+           //   = GenericArg::create_const (std::move (const_expr));
+           // generic_args.push_back (std::move (type_arg));
+         }
+         break;
+       }
+    }
+
+  auto generic_args_for_self
+    = GenericArgs (lifetime_args, generic_args, {} /*binding args*/, loc);
+
+  std::unique_ptr<Type> self_type_path
+    = impl_generics.empty ()
+       ? builder.single_type_path (type_name)
+       : builder.single_generic_type_path (type_name, generic_args_for_self);
+
+  return ImplGenerics{std::move (self_type_path), std::move (impl_generics)};
+}
+
 } // namespace AST
 } // namespace Rust
diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h
index 1924432d8ed..a494cc3c312 100644
--- a/gcc/rust/expand/rust-derive.h
+++ b/gcc/rust/expand/rust-derive.h
@@ -43,6 +43,29 @@ protected:
   location_t loc;
   Builder builder;
 
+  struct ImplGenerics
+  {
+    /* The type we are deriving the impl for */
+    std::unique_ptr<Type> self_type;
+
+    /* Generics for the impl itself */
+    std::vector<std::unique_ptr<GenericParam>> impl;
+  };
+
+  /**
+   * Create the generic parameters for a derive impl block. Derived impl blocks
+   * will often share the same structure of reusing the exact same bounds as
+   * their original type, plus adding an extra one for the trait we are
+   * deriving. For example, when deriving `Clone` on `Foo<T>`, you want to make
+   * sure that you implement `Clone` only if `T: Clone` - so you add an extra
+   * `Clone` bound to all of your generics.
+   */
+  ImplGenerics setup_impl_generics (
+    const std::string &type_name,
+    const std::vector<std::unique_ptr<GenericParam>> &type_generics,
+    tl::optional<std::unique_ptr<TypeParamBound>> &&extra_bound
+    = tl::nullopt) const;
+
 private:
   // the 4 "allowed" visitors, which a derive-visitor can specify and override
   virtual void visit_struct (StructStruct &struct_item) = 0;
-- 
2.45.2

Reply via email to