From bd4f8638d19ce8068bce57180f583b7d63aa4845 Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Thu, 19 Sep 2024 16:45:54 +0100 Subject: [PATCH] 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 --- 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 | 5 +- 16 files changed, 784 insertions(+), 23 deletions(-) create mode 100644 gcc/rust/ast/rust-ast-builder-type.cc create mode 100644 gcc/rust/ast/rust-ast-builder-type.h create mode 100644 gcc/testsuite/rust/compile/issue-3139-1.rs create mode 100644 gcc/testsuite/rust/compile/issue-3139-2.rs create mode 100644 gcc/testsuite/rust/compile/issue-3139-3.rs diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in index 73ec2193f50d..18fe786a5253 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 +// . + +#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 > elems; + for (auto &elem : tuple.get_elems ()) + { + Type *t = ASTTypeBuilder::build (*elem.get ()); + std::unique_ptr ty (t); + elems.push_back (std::move (ty)); + } + translated = new TupleType (std::move (elems), tuple.get_locus ()); +} + +void +ASTTypeBuilder::visit (TypePath &path) +{ + std::vector > 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 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 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 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 +// . + +#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 @@ // . #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 +Builder::generic_type_path_segment (std::string seg, GenericArgs args) const +{ + return std::unique_ptr ( + new TypePathSegmentGeneric (PathIdentSegment (seg, loc), false, args, loc)); +} + std::unique_ptr Builder::single_type_path (std::string type) const { @@ -92,6 +98,15 @@ Builder::single_type_path (std::string type) const return std::unique_ptr (new TypePath (std::move (segments), loc)); } +std::unique_ptr +Builder::single_generic_type_path (std::string type, GenericArgs args) const +{ + auto segments = std::vector> (); + segments.emplace_back (generic_type_path_segment (type, args)); + + return std::unique_ptr (new TypePath (std::move (segments), loc)); +} + PathInExpression Builder::path_in_expression (std::vector &&segments) const { @@ -174,5 +189,187 @@ Builder::wildcard () const return std::unique_ptr (new WildcardPattern (loc)); } +std::unique_ptr +Builder::new_type (Type &type) +{ + Type *t = ASTTypeBuilder::build (type); + return std::unique_ptr (t); +} + +std::unique_ptr +Builder::new_lifetime_param (LifetimeParam ¶m) +{ + Lifetime l = new_lifetime (param.get_lifetime ()); + std::vector 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 (p); +} + +std::unique_ptr +Builder::new_type_param (TypeParam ¶m) +{ + location_t locus = param.get_locus (); + AST::AttrVec outer_attrs = param.get_outer_attrs (); + Identifier type_representation = param.get_type_representation (); + std::vector> type_param_bounds; + std::unique_ptr 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 for_lifetimes; + for (const auto &lifetime : tb.get_for_lifetimes ()) + { + std::vector 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> 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 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 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 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 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 (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_args; + std::vector generic_args; + std::vector 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 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 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 @@ class Builder /* And similarly for type path segments */ std::unique_ptr type_path_segment (std::string seg) const; + std::unique_ptr + 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 single_type_path (std::string type) const; + std::unique_ptr 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 @@ class Builder /* Create a wildcard pattern (`_`) */ std::unique_ptr wildcard () const; + static std::unique_ptr new_type (Type &type); + + static std::unique_ptr + new_lifetime_param (LifetimeParam ¶m); + + static std::unique_ptr new_type_param (TypeParam ¶m); + + 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 dc0fd8b0e478..ef5d10b6c732 100644 --- a/gcc/rust/ast/rust-ast.h +++ b/gcc/rust/ast/rust-ast.h @@ -1477,6 +1477,12 @@ class TypeNoBounds : public Type class TypeParamBound : public Visitable { public: + enum TypeParamBoundType + { + TRAIT, + LIFETIME + }; + virtual ~TypeParamBound () {} // Unique pointer custom clone function @@ -1491,6 +1497,8 @@ class TypeParamBound : public Visitable 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 @@ class Lifetime : public TypeParamBound 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 @@ class LifetimeParam : public GenericParam std::vector &get_lifetime_bounds () { return lifetime_bounds; } + const std::vector &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 @@ struct GenericArgs std::string as_string () const; - // TODO: is this better? Or is a "vis_pattern" better? std::vector &get_generic_args () { return generic_args; } - // TODO: is this better? Or is a "vis_pattern" better? std::vector &get_binding_args () { return binding_args; } + const std::vector &get_binding_args () const + { + return binding_args; + } + std::vector &get_lifetime_args () { return lifetime_args; }; - location_t get_locus () { return locus; } + const std::vector &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 @@ class TraitBound : public TypeParamBound std::vector &get_for_lifetimes () { return for_lifetimes; } + const std::vector &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 for_lifetimes @@ -81,6 +86,11 @@ class TraitBound : public TypeParamBound 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 &&clone_expr) * */ std::unique_ptr -DeriveClone::clone_impl (std::unique_ptr &&clone_fn, - std::string name) +DeriveClone::clone_impl ( + std::unique_ptr &&clone_fn, std::string name, + const std::vector> &type_generics) { // should that be `$crate::core::clone::Clone` instead? auto segments = std::vector> (); @@ -84,10 +85,79 @@ DeriveClone::clone_impl (std::unique_ptr &&clone_fn, auto trait_items = std::vector> (); 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 { ... } + // + // we need to generate the impl block: + // + // impl Clone for Be + + std::vector lifetime_args; + std::vector generic_args; + std::vector> 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 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 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 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 ( 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 @@ class DeriveClone : DeriveVisitor * } * */ - std::unique_ptr clone_impl (std::unique_ptr &&clone_fn, - std::string name); + std::unique_ptr + clone_impl (std::unique_ptr &&clone_fn, std::string name, + const std::vector> &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 -DeriveCopy::copy_impl (std::string name) +DeriveCopy::copy_impl ( + std::string name, + const std::vector> &type_generics) { // `$crate::core::marker::Copy` instead auto segments = std::vector> (); 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 { ... } + // + // we need to generate the impl block: + // + // impl Clone for Be + + std::vector lifetime_args; + std::vector generic_args; + std::vector> 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 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 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 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 ( 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 @@ class DeriveCopy : DeriveVisitor * * impl Copy for {} */ - std::unique_ptr copy_impl (std::string name); + std::unique_ptr + copy_impl (std::string name, + const std::vector> &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 { + 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 = Be {a:1,b:Abound { a:0,b:1 }}; + let _: Be = 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 { + a: T, + b: Abound, +} + +impl Clone for Be { + fn clone(&self) -> Self { + return Be:: { + 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 = Be { + a: 1, + b: Abound { a: 0, b: 1 }, + }; + let _: Be = 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 { + 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 = 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 3251921acd45..3fb53241c40d 100644 --- a/gcc/testsuite/rust/compile/nr2/exclude +++ b/gcc/testsuite/rust/compile/nr2/exclude @@ -291,4 +291,7 @@ unknown-associated-item.rs box_syntax_feature_gate.rs dropck_eyepatch_feature_gate.rs inline_asm_parse_output_operand.rs -issue-3030.rs \ No newline at end of file +issue-3030.rs +issue-3139-1.rs +issue-3139-2.rs +issue-3139-3.rs