https://gcc.gnu.org/g:9b4f8f2d5177b006c6996e790f3874c8b1eeacfa

commit r15-8418-g9b4f8f2d5177b006c6996e790f3874c8b1eeacfa
Author: Philip Herron <herron.phi...@googlemail.com>
Date:   Thu Sep 19 16:45:54 2024 +0100

    rust: Add support for Clone and Copy derive on generic types
    
    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

Diff:
---
 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(-)

diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index 51645be6ff63..b1777e399639 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 000000000000..e76d0de0e9ae
--- /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 000000000000..b67ae3b553ff
--- /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 4679aa7b0f1c..529c686db1b2 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 aed71e730304..bad79d067adc 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 129a3041c7f1..42ad0119231b 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 29163ac1df23..98fde5a26068 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 cf830f6661a3..20e0232c4f38 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 2f2554d38efa..18436be4bf75 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 ab64829c2ae5..4a43b2ac1fc2 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 a1c8ed0778c2..1de72900d044 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 98decc06bfe4..71972ebf6f72 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 000000000000..84ca3ddd6ef7
--- /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 000000000000..0d298fa20a58
--- /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 000000000000..4a4546e823bc
--- /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 769a6de89314..bfb51fd7fee9 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

Reply via email to