https://gcc.gnu.org/g:c6a479fb9312b9166ca94a588aa85c9172f5ae19

commit c6a479fb9312b9166ca94a588aa85c9172f5ae19
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 58a5d5f73636..7f04136fe637 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 381501498bd3..121b8c8d7e0a 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 5c33954131f3..fa258c7dfa82 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 35f27e37dcd4..f83c99a57d2d 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 3b88a15f7774..5ca2c7f4394a 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 410d64819bbf..b6b76497d3ba 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 d09ea2c455b7..2d1b5995ba2f 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 31756576c5f3..043f9182efac 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 a9a300bf750f..070a7cd63bc5 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 73903b901b39..ef6817679ed2 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