]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
rust: Add support for Clone and Copy derive on generic types
authorPhilip Herron <herron.philip@googlemail.com>
Thu, 19 Sep 2024 15:45:54 +0000 (16:45 +0100)
committerPhilip Herron <philip.herron@embecosm.com>
Fri, 27 Sep 2024 10:01:40 +0000 (10:01 +0000)
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

16 files changed:
gcc/rust/Make-lang.in
gcc/rust/ast/rust-ast-builder-type.cc [new file with mode: 0644]
gcc/rust/ast/rust-ast-builder-type.h [new file with mode: 0644]
gcc/rust/ast/rust-ast-builder.cc
gcc/rust/ast/rust-ast-builder.h
gcc/rust/ast/rust-ast.h
gcc/rust/ast/rust-path.h
gcc/rust/ast/rust-type.h
gcc/rust/expand/rust-derive-clone.cc
gcc/rust/expand/rust-derive-clone.h
gcc/rust/expand/rust-derive-copy.cc
gcc/rust/expand/rust-derive-copy.h
gcc/testsuite/rust/compile/issue-3139-1.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-3139-2.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/issue-3139-3.rs [new file with mode: 0644]
gcc/testsuite/rust/compile/nr2/exclude

index 58a5d5f73636868ef8aec2422fe880f53c5d2315..7f04136fe6376f74f6274b94137bdb2f56332912 100644 (file)
@@ -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 (file)
index 0000000..e76d0de
--- /dev/null
@@ -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 (file)
index 0000000..b67ae3b
--- /dev/null
@@ -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
index 381501498bd30a2577732b38b593ce038600c214..121b8c8d7e0a3db069a77a3826c9017202392d9c 100644 (file)
@@ -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
index 5c33954131f37d4f45ee44de57730870ae38669e..fa258c7dfa82b73ec3ac62eb7ae25dd980dc344a 100644 (file)
@@ -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
index 35f27e37dcd4e3fd42544025661e7fea582903db..f83c99a57d2d2c6bbe1e0f26d2051fc0cee60abe 100644 (file)
@@ -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 (); }
 
index 3b88a15f77744d8308b41574dc5f2c18a578f5aa..5ca2c7f4394a77a483461670505e900f96fda377 100644 (file)
@@ -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
index 410d64819bbf5d9d6c6bd6e341b5df212bbaf0ed..b6b76497d3ba5a2d4d6e39808171388fa4b6f27b 100644 (file)
@@ -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 */
index d09ea2c455b72f80700445759971886214bd9ac9..2d1b5995ba2f9e57e6ba53d8897f7e7cb88509ab 100644 (file)
@@ -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
index 31756576c5f3ea4987b1f9ca624a892c490624d8..043f9182efacb3e1c0f8a6efdebfed4a83e20b5a 100644 (file)
@@ -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);
index a9a300bf750fab436a80800d944a077a264f82ce..070a7cd63bc57d99444c11ece843391c4812c135 100644 (file)
@@ -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
index 73903b901b390d4b925e0f28eafa9cd5f6fdfc52..ef6817679ed2dfa83d84fde5e933a1c584043f6b 100644 (file)
@@ -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 (file)
index 0000000..84ca3dd
--- /dev/null
@@ -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 (file)
index 0000000..0d298fa
--- /dev/null
@@ -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 (file)
index 0000000..4a4546e
--- /dev/null
@@ -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 },
+    };
+}
index 769a6de89314114aff7c460e0787d7610d192cdd..bfb51fd7fee991456d5463acd6495b687bf8d52e 100644 (file)
@@ -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