From: Philip Herron <herron.phi...@googlemail.com>

When we generate derivations for Copy and Clone we need to make sure
the associated impl block sets up the generic parameters and arguments
correctly. This patch introduces the framework to copy chunks of the AST
because we need to make sure these new AST nodes have their own associated
id, calling clone on the nodes will just confuse name-resolution and
subsequent mappings.

Fixes #3139

gcc/rust/ChangeLog:

        * Make-lang.in: new objects
        * ast/rust-ast-builder.cc (Builder::generic_type_path_segment): new 
helper
        (Builder::single_generic_type_path): likewise
        (Builder::new_type): likewise
        (Builder::new_lifetime_param): likewise
        (Builder::new_type_param): likewise
        (Builder::new_lifetime): likewise
        (Builder::new_generic_args): likewise
        * ast/rust-ast-builder.h: new helper decls
        * ast/rust-ast.h: new const getters
        * ast/rust-path.h: likewise
        * ast/rust-type.h: likewise
        * expand/rust-derive-clone.cc (DeriveClone::clone_impl): take the types 
generics
        (DeriveClone::visit_tuple): likewise
        (DeriveClone::visit_struct): likewise
        (DeriveClone::visit_union): likewise
        * expand/rust-derive-clone.h: update header
        * expand/rust-derive-copy.cc (DeriveCopy::copy_impl): similarly take 
type generics
        (DeriveCopy::visit_struct): likewise
        (DeriveCopy::visit_tuple): likewise
        (DeriveCopy::visit_enum): likewise
        (DeriveCopy::visit_union): likewise
        * expand/rust-derive-copy.h: likewse
        * ast/rust-ast-builder-type.cc: New file.
        * ast/rust-ast-builder-type.h: New file.

gcc/testsuite/ChangeLog:

        * rust/compile/issue-3139-1.rs: New test.
        * rust/compile/issue-3139-2.rs: New test.
        * rust/compile/issue-3139-3.rs: New test.
        * rust/compile/nr2/exclude: these all break nr2
---
 gcc/rust/Make-lang.in                      |   1 +
 gcc/rust/ast/rust-ast-builder-type.cc      | 164 +++++++++++++++++
 gcc/rust/ast/rust-ast-builder-type.h       |  57 ++++++
 gcc/rust/ast/rust-ast-builder.cc           | 201 ++++++++++++++++++++-
 gcc/rust/ast/rust-ast-builder.h            |  17 ++
 gcc/rust/ast/rust-ast.h                    |  20 +-
 gcc/rust/ast/rust-path.h                   |  14 +-
 gcc/rust/ast/rust-type.h                   |  10 +
 gcc/rust/expand/rust-derive-clone.cc       |  88 ++++++++-
 gcc/rust/expand/rust-derive-clone.h        |   5 +-
 gcc/rust/expand/rust-derive-copy.cc        |  87 ++++++++-
 gcc/rust/expand/rust-derive-copy.h         |   4 +-
 gcc/testsuite/rust/compile/issue-3139-1.rs |  45 +++++
 gcc/testsuite/rust/compile/issue-3139-2.rs |  57 ++++++
 gcc/testsuite/rust/compile/issue-3139-3.rs |  32 ++++
 gcc/testsuite/rust/compile/nr2/exclude     |   3 +
 16 files changed, 783 insertions(+), 22 deletions(-)
 create mode 100644 gcc/rust/ast/rust-ast-builder-type.cc
 create mode 100644 gcc/rust/ast/rust-ast-builder-type.h
 create mode 100644 gcc/testsuite/rust/compile/issue-3139-1.rs
 create mode 100644 gcc/testsuite/rust/compile/issue-3139-2.rs
 create mode 100644 gcc/testsuite/rust/compile/issue-3139-3.rs

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 51645be6ff6..b1777e39963 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -92,6 +92,7 @@ GRS_OBJS = \
     rust/rust-cfg-strip.o \
     rust/rust-expand-visitor.o \
     rust/rust-ast-builder.o \
+    rust/rust-ast-builder-type.o \
     rust/rust-derive.o \
     rust/rust-derive-clone.o \
     rust/rust-derive-copy.o \
diff --git a/gcc/rust/ast/rust-ast-builder-type.cc 
b/gcc/rust/ast/rust-ast-builder-type.cc
new file mode 100644
index 00000000000..e76d0de0e9a
--- /dev/null
+++ b/gcc/rust/ast/rust-ast-builder-type.cc
@@ -0,0 +1,164 @@
+// Copyright (C) 2020-2024 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-ast-builder-type.h"
+#include "rust-ast-builder.h"
+#include "rust-ast-full.h"
+#include "rust-common.h"
+#include "rust-make-unique.h"
+
+namespace Rust {
+namespace AST {
+
+ASTTypeBuilder::ASTTypeBuilder () : translated (nullptr) {}
+
+Type *
+ASTTypeBuilder::build (Type &type)
+{
+  ASTTypeBuilder builder;
+  type.accept_vis (builder);
+  rust_assert (builder.translated != nullptr);
+  return builder.translated;
+}
+
+void
+ASTTypeBuilder::visit (BareFunctionType &fntype)
+{
+  /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (TupleType &tuple)
+{
+  std::vector<std::unique_ptr<Type> > elems;
+  for (auto &elem : tuple.get_elems ())
+    {
+      Type *t = ASTTypeBuilder::build (*elem.get ());
+      std::unique_ptr<Type> ty (t);
+      elems.push_back (std::move (ty));
+    }
+  translated = new TupleType (std::move (elems), tuple.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (TypePath &path)
+{
+  std::vector<std::unique_ptr<TypePathSegment> > segments;
+  for (auto &seg : path.get_segments ())
+    {
+      switch (seg->get_type ())
+       {
+         case TypePathSegment::REG: {
+           const TypePathSegment &segment
+             = (const TypePathSegment &) (*seg.get ());
+           TypePathSegment *s
+             = new TypePathSegment (segment.get_ident_segment (),
+                                    segment.get_separating_scope_resolution (),
+                                    segment.get_locus ());
+           std::unique_ptr<TypePathSegment> sg (s);
+           segments.push_back (std::move (sg));
+         }
+         break;
+
+         case TypePathSegment::GENERIC: {
+           TypePathSegmentGeneric &generic
+             = (TypePathSegmentGeneric &) (*seg.get ());
+
+           GenericArgs args
+             = Builder::new_generic_args (generic.get_generic_args ());
+           TypePathSegmentGeneric *s
+             = new TypePathSegmentGeneric (generic.get_ident_segment (), false,
+                                           std::move (args),
+                                           generic.get_locus ());
+           std::unique_ptr<TypePathSegment> sg (s);
+           segments.push_back (std::move (sg));
+         }
+         break;
+
+         case TypePathSegment::FUNCTION: {
+           rust_unreachable ();
+           // TODO
+           // const TypePathSegmentFunction &fn
+           //   = (const TypePathSegmentFunction &) (*seg.get ());
+         }
+         break;
+       }
+    }
+
+  translated = new TypePath (std::move (segments), path.get_locus (),
+                            path.has_opening_scope_resolution_op ());
+}
+
+void
+ASTTypeBuilder::visit (QualifiedPathInType &path)
+{
+  /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (ArrayType &type)
+{
+  /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (ReferenceType &type)
+{
+  /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (RawPointerType &type)
+{
+  /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (SliceType &type)
+{
+  Type *t = ASTTypeBuilder::build (type.get_elem_type ());
+  std::unique_ptr<Type> ty (t);
+  translated = new SliceType (std::move (ty), type.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (InferredType &type)
+{
+  translated = new InferredType (type.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (NeverType &type)
+{
+  translated = new NeverType (type.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (TraitObjectTypeOneBound &type)
+{
+  /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (TraitObjectType &type)
+{
+  /* TODO */
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/ast/rust-ast-builder-type.h 
b/gcc/rust/ast/rust-ast-builder-type.h
new file mode 100644
index 00000000000..b67ae3b553f
--- /dev/null
+++ b/gcc/rust/ast/rust-ast-builder-type.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2020-2024 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_AST_BUILDER_TYPE
+#define RUST_AST_BUILDER_TYPE
+
+#include "rust-ast-visitor.h"
+
+namespace Rust {
+namespace AST {
+
+class ASTTypeBuilder : public DefaultASTVisitor
+{
+protected:
+  using DefaultASTVisitor::visit;
+
+public:
+  static Type *build (Type &type);
+
+  void visit (BareFunctionType &fntype) override;
+  void visit (TupleType &tuple) override;
+  void visit (TypePath &path) override;
+  void visit (QualifiedPathInType &path) override;
+  void visit (ArrayType &type) override;
+  void visit (ReferenceType &type) override;
+  void visit (RawPointerType &type) override;
+  void visit (SliceType &type) override;
+  void visit (InferredType &type) override;
+  void visit (NeverType &type) override;
+  void visit (TraitObjectTypeOneBound &type) override;
+  void visit (TraitObjectType &type) override;
+
+private:
+  ASTTypeBuilder ();
+
+  Type *translated;
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // RUST_AST_BUILDER_TYPE
diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc
index 4679aa7b0f1..529c686db1b 100644
--- a/gcc/rust/ast/rust-ast-builder.cc
+++ b/gcc/rust/ast/rust-ast-builder.cc
@@ -17,8 +17,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-ast-builder.h"
-#include "rust-ast-full-decls.h"
-#include "rust-ast-full.h"
+#include "rust-ast-builder-type.h"
 #include "rust-common.h"
 #include "rust-expr.h"
 #include "rust-token.h"
@@ -83,6 +82,13 @@ Builder::type_path_segment (std::string seg) const
     new TypePathSegment (seg, false, loc));
 }
 
+std::unique_ptr<TypePathSegment>
+Builder::generic_type_path_segment (std::string seg, GenericArgs args) const
+{
+  return std::unique_ptr<TypePathSegment> (
+    new TypePathSegmentGeneric (PathIdentSegment (seg, loc), false, args, 
loc));
+}
+
 std::unique_ptr<Type>
 Builder::single_type_path (std::string type) const
 {
@@ -92,6 +98,15 @@ Builder::single_type_path (std::string type) const
   return std::unique_ptr<Type> (new TypePath (std::move (segments), loc));
 }
 
+std::unique_ptr<Type>
+Builder::single_generic_type_path (std::string type, GenericArgs args) const
+{
+  auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
+  segments.emplace_back (generic_type_path_segment (type, args));
+
+  return std::unique_ptr<Type> (new TypePath (std::move (segments), loc));
+}
+
 PathInExpression
 Builder::path_in_expression (std::vector<std::string> &&segments) const
 {
@@ -174,5 +189,187 @@ Builder::wildcard () const
   return std::unique_ptr<Pattern> (new WildcardPattern (loc));
 }
 
+std::unique_ptr<Type>
+Builder::new_type (Type &type)
+{
+  Type *t = ASTTypeBuilder::build (type);
+  return std::unique_ptr<Type> (t);
+}
+
+std::unique_ptr<GenericParam>
+Builder::new_lifetime_param (LifetimeParam &param)
+{
+  Lifetime l = new_lifetime (param.get_lifetime ());
+  std::vector<Lifetime> lifetime_bounds;
+  for (auto b : param.get_lifetime_bounds ())
+    {
+      Lifetime bl = new_lifetime (b);
+      lifetime_bounds.push_back (bl);
+    }
+
+  auto p = new LifetimeParam (l, std::move (lifetime_bounds),
+                             param.get_outer_attrs (), param.get_locus ());
+  return std::unique_ptr<GenericParam> (p);
+}
+
+std::unique_ptr<GenericParam>
+Builder::new_type_param (TypeParam &param)
+{
+  location_t locus = param.get_locus ();
+  AST::AttrVec outer_attrs = param.get_outer_attrs ();
+  Identifier type_representation = param.get_type_representation ();
+  std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
+  std::unique_ptr<Type> type = nullptr;
+
+  if (param.has_type ())
+    type = new_type (param.get_type ());
+
+  for (const auto &b : param.get_type_param_bounds ())
+    {
+      switch (b->get_bound_type ())
+       {
+         case TypeParamBound::TypeParamBoundType::TRAIT: {
+           const TraitBound &tb = (const TraitBound &) *b.get ();
+           const TypePath &path = tb.get_type_path ();
+
+           std::vector<LifetimeParam> for_lifetimes;
+           for (const auto &lifetime : tb.get_for_lifetimes ())
+             {
+               std::vector<Lifetime> lifetime_bounds;
+               for (const auto &b : lifetime.get_lifetime_bounds ())
+                 {
+                   Lifetime bl = new_lifetime (b);
+                   lifetime_bounds.push_back (std::move (bl));
+                 }
+
+               Lifetime nl = new_lifetime (lifetime.get_lifetime ());
+               LifetimeParam p (std::move (nl), std::move (lifetime_bounds),
+                                {}, lifetime.get_locus ());
+               for_lifetimes.push_back (std::move (p));
+             }
+
+           std::vector<std::unique_ptr<TypePathSegment>> segments;
+           for (auto &seg : path.get_segments ())
+             {
+               switch (seg->get_type ())
+                 {
+                   case TypePathSegment::REG: {
+                     const TypePathSegment &segment
+                       = (const TypePathSegment &) (*seg.get ());
+                     TypePathSegment *s = new TypePathSegment (
+                       segment.get_ident_segment (),
+                       segment.get_separating_scope_resolution (),
+                       segment.get_locus ());
+                     std::unique_ptr<TypePathSegment> sg (s);
+                     segments.push_back (std::move (sg));
+                   }
+                   break;
+
+                   case TypePathSegment::GENERIC: {
+                     TypePathSegmentGeneric &generic
+                       = (TypePathSegmentGeneric &) (*seg.get ());
+
+                     GenericArgs args
+                       = new_generic_args (generic.get_generic_args ());
+                     TypePathSegmentGeneric *s = new TypePathSegmentGeneric (
+                       generic.get_ident_segment (), false, std::move (args),
+                       generic.get_locus ());
+                     std::unique_ptr<TypePathSegment> sg (s);
+                     segments.push_back (std::move (sg));
+                   }
+                   break;
+
+                   case TypePathSegment::FUNCTION: {
+                     rust_unreachable ();
+                     // TODO
+                     // const TypePathSegmentFunction &fn
+                     //   = (const TypePathSegmentFunction &) (*seg.get ());
+                   }
+                   break;
+                 }
+             }
+
+           TypePath p (std::move (segments), path.get_locus (),
+                       path.has_opening_scope_resolution_op ());
+
+           TraitBound *b = new TraitBound (std::move (p), tb.get_locus (),
+                                           tb.is_in_parens (),
+                                           tb.has_opening_question_mark (),
+                                           std::move (for_lifetimes));
+           std::unique_ptr<TypeParamBound> bound (b);
+           type_param_bounds.push_back (std::move (bound));
+         }
+         break;
+
+         case TypeParamBound::TypeParamBoundType::LIFETIME: {
+           const Lifetime &l = (const Lifetime &) *b.get ();
+
+           auto bl = new Lifetime (l.get_lifetime_type (),
+                                   l.get_lifetime_name (), l.get_locus ());
+           std::unique_ptr<TypeParamBound> bound (bl);
+           type_param_bounds.push_back (std::move (bound));
+         }
+         break;
+       }
+    }
+
+  auto type_param
+    = new TypeParam (type_representation, locus, std::move (type_param_bounds),
+                    std::move (type), std::move (outer_attrs));
+
+  return std::unique_ptr<GenericParam> (type_param);
+}
+
+Lifetime
+Builder::new_lifetime (const Lifetime &lifetime)
+{
+  return Lifetime (lifetime.get_lifetime_type (), lifetime.get_lifetime_name 
(),
+                  lifetime.get_locus ());
+}
+
+GenericArgs
+Builder::new_generic_args (GenericArgs &args)
+{
+  std::vector<Lifetime> lifetime_args;
+  std::vector<GenericArg> generic_args;
+  std::vector<GenericArgsBinding> binding_args;
+  location_t locus = args.get_locus ();
+
+  for (const auto &lifetime : args.get_lifetime_args ())
+    {
+      Lifetime l = new_lifetime (lifetime);
+      lifetime_args.push_back (std::move (l));
+    }
+
+  for (auto &binding : args.get_binding_args ())
+    {
+      Type &t = *binding.get_type_ptr ().get ();
+      std::unique_ptr<Type> ty = new_type (t);
+      GenericArgsBinding b (binding.get_identifier (), std::move (ty),
+                           binding.get_locus ());
+      binding_args.push_back (std::move (b));
+    }
+
+  for (auto &arg : args.get_generic_args ())
+    {
+      switch (arg.get_kind ())
+       {
+         case GenericArg::Kind::Type: {
+           std::unique_ptr<Type> ty = new_type (arg.get_type ());
+           GenericArg arg = GenericArg::create_type (std::move (ty));
+         }
+         break;
+
+       default:
+         // FIXME
+         rust_unreachable ();
+         break;
+       }
+    }
+
+  return GenericArgs (std::move (lifetime_args), std::move (generic_args),
+                     std::move (binding_args), locus);
+}
+
 } // namespace AST
 } // namespace Rust
diff --git a/gcc/rust/ast/rust-ast-builder.h b/gcc/rust/ast/rust-ast-builder.h
index aed71e73030..bad79d067ad 100644
--- a/gcc/rust/ast/rust-ast-builder.h
+++ b/gcc/rust/ast/rust-ast-builder.h
@@ -82,10 +82,16 @@ public:
   /* And similarly for type path segments */
   std::unique_ptr<TypePathSegment> type_path_segment (std::string seg) const;
 
+  std::unique_ptr<TypePathSegment>
+  generic_type_path_segment (std::string seg, GenericArgs args) const;
+
   /* Create a Type from a single string - the most basic kind of type in our 
AST
    */
   std::unique_ptr<Type> single_type_path (std::string type) const;
 
+  std::unique_ptr<Type> single_generic_type_path (std::string type,
+                                                 GenericArgs args) const;
+
   /**
    * Create a path in expression from multiple segments (`Clone::clone`). You
    * do not need to separate the segments using `::`, you can simply provide a
@@ -116,6 +122,17 @@ public:
   /* Create a wildcard pattern (`_`) */
   std::unique_ptr<Pattern> wildcard () const;
 
+  static std::unique_ptr<Type> new_type (Type &type);
+
+  static std::unique_ptr<GenericParam>
+  new_lifetime_param (LifetimeParam &param);
+
+  static std::unique_ptr<GenericParam> new_type_param (TypeParam &param);
+
+  static Lifetime new_lifetime (const Lifetime &lifetime);
+
+  static GenericArgs new_generic_args (GenericArgs &args);
+
 private:
   /**
    * Location of the generated AST nodes
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index 129a3041c7f..42ad0119231 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -1477,6 +1477,12 @@ protected:
 class TypeParamBound : public Visitable
 {
 public:
+  enum TypeParamBoundType
+  {
+    TRAIT,
+    LIFETIME
+  };
+
   virtual ~TypeParamBound () {}
 
   // Unique pointer custom clone function
@@ -1491,6 +1497,8 @@ public:
 
   virtual location_t get_locus () const = 0;
 
+  virtual TypeParamBoundType get_bound_type () const = 0;
+
 protected:
   // Clone function implementation as pure virtual method
   virtual TypeParamBound *clone_type_param_bound_impl () const = 0;
@@ -1546,12 +1554,17 @@ public:
 
   void accept_vis (ASTVisitor &vis) override;
 
-  LifetimeType get_lifetime_type () { return lifetime_type; }
+  LifetimeType get_lifetime_type () const { return lifetime_type; }
 
   location_t get_locus () const override final { return locus; }
 
   std::string get_lifetime_name () const { return lifetime_name; }
 
+  TypeParamBoundType get_bound_type () const override
+  {
+    return TypeParamBound::TypeParamBoundType::LIFETIME;
+  }
+
 protected:
   /* Use covariance to implement clone function as returning this object
    * rather than base */
@@ -1619,6 +1632,11 @@ public:
 
   std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; }
 
+  const std::vector<Lifetime> &get_lifetime_bounds () const
+  {
+    return lifetime_bounds;
+  }
+
   // Returns whether the lifetime param has an outer attribute.
   bool has_outer_attribute () const { return !outer_attrs.empty (); }
 
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index 29163ac1df2..98fde5a2606 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -479,15 +479,23 @@ public:
 
   std::string as_string () const;
 
-  // TODO: is this better? Or is a "vis_pattern" better?
   std::vector<GenericArg> &get_generic_args () { return generic_args; }
 
-  // TODO: is this better? Or is a "vis_pattern" better?
   std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; }
 
+  const std::vector<GenericArgsBinding> &get_binding_args () const
+  {
+    return binding_args;
+  }
+
   std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; };
 
-  location_t get_locus () { return locus; }
+  const std::vector<Lifetime> &get_lifetime_args () const
+  {
+    return lifetime_args;
+  };
+
+  location_t get_locus () const { return locus; }
 };
 
 /* A segment of a path in expression, including an identifier aspect and maybe
diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h
index cf830f6661a..20e0232c4f3 100644
--- a/gcc/rust/ast/rust-type.h
+++ b/gcc/rust/ast/rust-type.h
@@ -48,6 +48,11 @@ public:
 
   std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; }
 
+  const std::vector<LifetimeParam> &get_for_lifetimes () const
+  {
+    return for_lifetimes;
+  }
+
   TraitBound (TypePath type_path, location_t locus, bool in_parens = false,
              bool opening_question_mark = false,
              std::vector<LifetimeParam> for_lifetimes
@@ -81,6 +86,11 @@ public:
   bool is_in_parens () const { return in_parens; }
   bool has_opening_question_mark () const { return opening_question_mark; }
 
+  TypeParamBoundType get_bound_type () const override
+  {
+    return TypeParamBound::TypeParamBoundType::TRAIT;
+  }
+
 protected:
   /* Use covariance to implement clone function as returning this object rather
    * than base */
diff --git a/gcc/rust/expand/rust-derive-clone.cc 
b/gcc/rust/expand/rust-derive-clone.cc
index 2f2554d38ef..18436be4bf7 100644
--- a/gcc/rust/expand/rust-derive-clone.cc
+++ b/gcc/rust/expand/rust-derive-clone.cc
@@ -73,8 +73,9 @@ DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr)
  *
  */
 std::unique_ptr<Item>
-DeriveClone::clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn,
-                        std::string name)
+DeriveClone::clone_impl (
+  std::unique_ptr<AssociatedItem> &&clone_fn, std::string name,
+  const std::vector<std::unique_ptr<GenericParam>> &type_generics)
 {
   // should that be `$crate::core::clone::Clone` instead?
   auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
@@ -84,10 +85,79 @@ DeriveClone::clone_impl (std::unique_ptr<AssociatedItem> 
&&clone_fn,
   auto trait_items = std::vector<std::unique_ptr<AssociatedItem>> ();
   trait_items.emplace_back (std::move (clone_fn));
 
+  // we need to build up the generics for this impl block which will be just a
+  // clone of the types specified ones
+  //
+  // for example:
+  //
+  // #[derive(Clone)]
+  // struct Be<T: Clone> { ... }
+  //
+  // we need to generate the impl block:
+  //
+  // impl<T: Clone> Clone for Be<T>
+
+  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));
+
+           auto impl_type_param = builder.new_type_param (type_param);
+           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;
+       }
+    }
+
+  GenericArgs generic_args_for_self (lifetime_args, generic_args,
+                                    {} /*binding args*/, loc);
+  std::unique_ptr<Type> self_type_path
+    = impl_generics.empty ()
+       ? builder.single_type_path (name)
+       : builder.single_generic_type_path (name, generic_args_for_self);
+
   return std::unique_ptr<Item> (
     new TraitImpl (clone, /* unsafe */ false,
                   /* exclam */ false, std::move (trait_items),
-                  /* generics */ {}, builder.single_type_path (name),
+                  std::move (impl_generics), std::move (self_type_path),
                   WhereClause::create_empty (), Visibility::create_private (),
                   {}, {}, loc));
 }
@@ -122,7 +192,8 @@ DeriveClone::visit_tuple (TupleStruct &item)
   auto constructor = builder.call (std::move (path), std::move 
(cloned_fields));
 
   expanded = clone_impl (clone_fn (std::move (constructor)),
-                        item.get_identifier ().as_string ());
+                        item.get_identifier ().as_string (),
+                        item.get_generic_params ());
 }
 
 void
@@ -133,7 +204,8 @@ DeriveClone::visit_struct (StructStruct &item)
       auto unit_ctor
        = builder.struct_expr_struct (item.get_struct_name ().as_string ());
       expanded = clone_impl (clone_fn (std::move (unit_ctor)),
-                            item.get_struct_name ().as_string ());
+                            item.get_struct_name ().as_string (),
+                            item.get_generic_params ());
       return;
     }
 
@@ -151,7 +223,8 @@ DeriveClone::visit_struct (StructStruct &item)
   auto ctor = builder.struct_expr (item.get_struct_name ().as_string (),
                                   std::move (cloned_fields));
   expanded = clone_impl (clone_fn (std::move (ctor)),
-                        item.get_struct_name ().as_string ());
+                        item.get_struct_name ().as_string (),
+                        item.get_generic_params ());
 }
 
 void
@@ -187,7 +260,8 @@ DeriveClone::visit_union (Union &item)
   auto block = builder.block (std::move (stmts), std::move (tail_expr));
 
   expanded = clone_impl (clone_fn (std::move (block)),
-                        item.get_identifier ().as_string ());
+                        item.get_identifier ().as_string (),
+                        item.get_generic_params ());
 }
 
 } // namespace AST
diff --git a/gcc/rust/expand/rust-derive-clone.h 
b/gcc/rust/expand/rust-derive-clone.h
index ab64829c2ae..4a43b2ac1fc 100644
--- a/gcc/rust/expand/rust-derive-clone.h
+++ b/gcc/rust/expand/rust-derive-clone.h
@@ -59,8 +59,9 @@ private:
    * }
    *
    */
-  std::unique_ptr<Item> clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn,
-                                   std::string name);
+  std::unique_ptr<Item>
+  clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn, std::string name,
+             const std::vector<std::unique_ptr<GenericParam>> &type_generics);
 
   virtual void visit_struct (StructStruct &item);
   virtual void visit_tuple (TupleStruct &item);
diff --git a/gcc/rust/expand/rust-derive-copy.cc 
b/gcc/rust/expand/rust-derive-copy.cc
index a1c8ed0778c..1de72900d04 100644
--- a/gcc/rust/expand/rust-derive-copy.cc
+++ b/gcc/rust/expand/rust-derive-copy.cc
@@ -37,17 +37,88 @@ DeriveCopy::go (Item &item)
 }
 
 std::unique_ptr<Item>
-DeriveCopy::copy_impl (std::string name)
+DeriveCopy::copy_impl (
+  std::string name,
+  const std::vector<std::unique_ptr<GenericParam>> &type_generics)
 {
   // `$crate::core::marker::Copy` instead
   auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
   segments.emplace_back (builder.type_path_segment ("Copy"));
   auto copy = TypePath (std::move (segments), loc);
 
+  // we need to build up the generics for this impl block which will be just a
+  // clone of the types specified ones
+  //
+  // for example:
+  //
+  // #[derive(Copy)]
+  // struct Be<T: Copy> { ... }
+  //
+  // we need to generate the impl block:
+  //
+  // impl<T: Copy> Clone for Be<T>
+
+  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));
+
+           auto impl_type_param = builder.new_type_param (type_param);
+           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;
+       }
+    }
+
+  GenericArgs generic_args_for_self (lifetime_args, generic_args,
+                                    {} /*binding args*/, loc);
+  std::unique_ptr<Type> self_type_path
+    = impl_generics.empty ()
+       ? builder.single_type_path (name)
+       : builder.single_generic_type_path (name, generic_args_for_self);
+
   return std::unique_ptr<Item> (
     new TraitImpl (copy, /* unsafe */ false,
                   /* exclam */ false, /* trait items */ {},
-                  /* generics */ {}, builder.single_type_path (name),
+                  std::move (impl_generics), std::move (self_type_path),
                   WhereClause::create_empty (), Visibility::create_private (),
                   {}, {}, loc));
 }
@@ -55,25 +126,29 @@ DeriveCopy::copy_impl (std::string name)
 void
 DeriveCopy::visit_struct (StructStruct &item)
 {
-  expanded = copy_impl (item.get_struct_name ().as_string ());
+  expanded = copy_impl (item.get_struct_name ().as_string (),
+                       item.get_generic_params ());
 }
 
 void
 DeriveCopy::visit_tuple (TupleStruct &item)
 {
-  expanded = copy_impl (item.get_struct_name ().as_string ());
+  expanded = copy_impl (item.get_struct_name ().as_string (),
+                       item.get_generic_params ());
 }
 
 void
 DeriveCopy::visit_enum (Enum &item)
 {
-  expanded = copy_impl (item.get_identifier ().as_string ());
+  expanded = copy_impl (item.get_identifier ().as_string (),
+                       item.get_generic_params ());
 }
 
 void
 DeriveCopy::visit_union (Union &item)
 {
-  expanded = copy_impl (item.get_identifier ().as_string ());
+  expanded = copy_impl (item.get_identifier ().as_string (),
+                       item.get_generic_params ());
 }
 
 } // namespace AST
diff --git a/gcc/rust/expand/rust-derive-copy.h 
b/gcc/rust/expand/rust-derive-copy.h
index 98decc06bfe..71972ebf6f7 100644
--- a/gcc/rust/expand/rust-derive-copy.h
+++ b/gcc/rust/expand/rust-derive-copy.h
@@ -40,7 +40,9 @@ private:
    *
    * impl Copy for <type> {}
    */
-  std::unique_ptr<Item> copy_impl (std::string name);
+  std::unique_ptr<Item>
+  copy_impl (std::string name,
+            const std::vector<std::unique_ptr<GenericParam>> &type_generics);
 
   virtual void visit_struct (StructStruct &item);
   virtual void visit_tuple (TupleStruct &item);
diff --git a/gcc/testsuite/rust/compile/issue-3139-1.rs 
b/gcc/testsuite/rust/compile/issue-3139-1.rs
new file mode 100644
index 00000000000..84ca3ddd6ef
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3139-1.rs
@@ -0,0 +1,45 @@
+#![feature(lang_items)]
+
+#[lang = "clone"]
+trait Clone {
+    fn clone(&self) -> Self;
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+struct Abound {
+    a: u32,
+    // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+    b: u32,
+    // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+}
+
+#[derive(Clone)]
+struct Be<T:Clone> {
+    a: T,
+    b: Abound,
+}
+
+impl Clone for u32 {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Clone for usize {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Clone for Abound {
+    fn clone(&self) -> Self {
+        return Abound { a: self.a.clone(), b: self.b.clone() };
+    }
+}
+
+fn main() {
+    let b: Be<usize> = Be {a:1,b:Abound { a:0,b:1 }};
+    let _: Be<usize> = b.clone();
+}
diff --git a/gcc/testsuite/rust/compile/issue-3139-2.rs 
b/gcc/testsuite/rust/compile/issue-3139-2.rs
new file mode 100644
index 00000000000..0d298fa20a5
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3139-2.rs
@@ -0,0 +1,57 @@
+#![feature(lang_items)]
+
+#[lang = "clone"]
+trait Clone {
+    fn clone(&self) -> Self;
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+struct Abound {
+    a: u32,
+    b: u32,
+}
+
+struct Be<T: Clone> {
+    a: T,
+    b: Abound,
+}
+
+impl<T: Clone> Clone for Be<T> {
+    fn clone(&self) -> Self {
+        return Be::<T> {
+            a: self.a.clone(),
+            b: self.b.clone(),
+        };
+    }
+}
+
+impl Clone for u32 {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Clone for usize {
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl Clone for Abound {
+    fn clone(&self) -> Self {
+        return Abound {
+            a: self.a.clone(),
+            b: self.b.clone(),
+        };
+    }
+}
+
+fn main() {
+    let b: Be<usize> = Be {
+        a: 1,
+        b: Abound { a: 0, b: 1 },
+    };
+    let _: Be<usize> = b.clone();
+}
diff --git a/gcc/testsuite/rust/compile/issue-3139-3.rs 
b/gcc/testsuite/rust/compile/issue-3139-3.rs
new file mode 100644
index 00000000000..4a4546e823b
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3139-3.rs
@@ -0,0 +1,32 @@
+#![feature(lang_items)]
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[derive(Copy)]
+struct Abound {
+    a: u32,
+    // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+    b: u32,
+    // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+}
+
+#[derive(Copy)]
+struct Be<T: Copy> {
+    a: T,
+    // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+    b: Abound,
+    // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+}
+
+impl Copy for usize {}
+
+fn main() {
+    let _: Be<usize> = Be {
+        a: 1,
+        b: Abound { a: 0, b: 1 },
+    };
+}
diff --git a/gcc/testsuite/rust/compile/nr2/exclude 
b/gcc/testsuite/rust/compile/nr2/exclude
index 769a6de8931..bfb51fd7fee 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -249,3 +249,6 @@ inline_asm_parse_output_operand.rs
 issue-3030.rs
 issue-3035.rs
 issue-3082.rs
+issue-3139-1.rs
+issue-3139-2.rs
+issue-3139-3.rs
-- 
2.45.2

Reply via email to