From: Arthur Cohen <arthur.co...@embecosm.com> gcc/rust/ChangeLog:
* expand/rust-derive-clone.cc (DeriveClone::variant_match_path): New function. (DeriveClone::clone_enum_identifier): Rename. (DeriveClone::clone_enum_tuple): New function. (DeriveClone::visit_enum): Visit tuple variants properly. * expand/rust-derive-clone.h: Declare new functions. --- gcc/rust/expand/rust-derive-clone.cc | 58 ++++++++++++++++++++++++++-- gcc/rust/expand/rust-derive-clone.h | 12 ++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc index e4702d8a818..c2994b7b4f8 100644 --- a/gcc/rust/expand/rust-derive-clone.cc +++ b/gcc/rust/expand/rust-derive-clone.cc @@ -21,6 +21,8 @@ #include "rust-ast-dump.h" #include "rust-item.h" #include "rust-path.h" +#include "rust-pattern.h" +#include "rust-system.h" namespace Rust { namespace AST { @@ -236,14 +238,20 @@ DeriveClone::visit_struct (StructStruct &item) item.get_generic_params ()); } +PathInExpression +DeriveClone::variant_match_path (Enum &item, const Identifier &variant) +{ + return PathInExpression ({builder.path_segment ( + item.get_identifier ().as_string ()), + builder.path_segment (variant.as_string ())}, + {}, loc, false); +} + MatchCase DeriveClone::clone_enum_identifier (Enum &item, const std::unique_ptr<EnumItem> &variant) { - auto variant_path = PathInExpression ( - {builder.path_segment (item.get_identifier ().as_string ()), - builder.path_segment (variant->get_identifier ().as_string ())}, - {}, loc, false); + auto variant_path = variant_match_path (item, variant->get_identifier ()); auto pattern = std::unique_ptr<Pattern> (new ReferencePattern ( std::unique_ptr<Pattern> (new PathInExpression (variant_path)), false, @@ -253,6 +261,45 @@ DeriveClone::clone_enum_identifier (Enum &item, return builder.match_case (std::move (pattern), std::move (expr)); } +MatchCase +DeriveClone::clone_enum_tuple (Enum &item, const EnumItemTuple &variant) +{ + auto variant_path = variant_match_path (item, variant.get_identifier ()); + + auto patterns = std::vector<std::unique_ptr<Pattern>> (); + auto cloned_patterns = std::vector<std::unique_ptr<Expr>> (); + + for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++) + { + // The pattern we're creating for each field is `self_<i>` where `i` is + // the index of the field. It doesn't actually matter what we use, as long + // as it's ordered, unique, and that we can reuse it in the match case's + // return expression to clone the field. + auto pattern_str = "__self_" + std::to_string (i); + + patterns.emplace_back (builder.identifier_pattern (pattern_str)); + + // Now, for each tuple's element, we create a new expression calling + // `clone` on it for the match case's return expression + cloned_patterns.emplace_back ( + clone_call (builder.ref (builder.identifier (pattern_str)))); + } + + auto pattern_items = std::unique_ptr<TupleStructItems> ( + new TupleStructItemsNoRange (std::move (patterns))); + + auto pattern = std::unique_ptr<Pattern> ( + new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern ( + variant_path, std::move (pattern_items))), + false, false, loc)); + + auto expr + = builder.call (std::unique_ptr<Expr> (new PathInExpression (variant_path)), + std::move (cloned_patterns)); + + return builder.match_case (std::move (pattern), std::move (expr)); +} + void DeriveClone::visit_enum (Enum &item) { @@ -274,6 +321,9 @@ DeriveClone::visit_enum (Enum &item) cases.emplace_back (clone_enum_identifier (item, variant)); break; case EnumItem::Kind::Tuple: + cases.emplace_back ( + clone_enum_tuple (item, static_cast<EnumItemTuple &> (*variant))); + break; case EnumItem::Kind::Struct: rust_unreachable (); break; diff --git a/gcc/rust/expand/rust-derive-clone.h b/gcc/rust/expand/rust-derive-clone.h index 339cf6357ae..d48ec5d2889 100644 --- a/gcc/rust/expand/rust-derive-clone.h +++ b/gcc/rust/expand/rust-derive-clone.h @@ -63,8 +63,20 @@ private: clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn, std::string name, const std::vector<std::unique_ptr<GenericParam>> &type_generics); + /** + * Get the path to use for matching and creating a variant when matching on an + * enum. E.g. for the `Option` enum, with the `None` variant, this will create + * a path `Option::None` + */ + PathInExpression variant_match_path (Enum &item, const Identifier &variant); + + /** + * Implementation of clone for all possible variants of an enum + */ MatchCase clone_enum_identifier (Enum &item, const std::unique_ptr<EnumItem> &variant); + MatchCase clone_enum_tuple (Enum &item, const EnumItemTuple &variant); + MatchCase clone_enum_struct (Enum &item, const EnumItemStruct &variant); virtual void visit_struct (StructStruct &item); virtual void visit_tuple (TupleStruct &item); -- 2.45.2