// 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-derive-clone.h" #include "rust-item.h" namespace Rust { namespace AST { std::unique_ptr DeriveClone::clone_call (std::unique_ptr &&to_clone) { // $crate::core::clone::Clone::clone for the fully qualified path - we don't // link with `core` yet so that might be an issue. Use `Clone::clone` for now? // TODO: Factor this function inside the DeriveAccumulator auto path = std::unique_ptr ( new PathInExpression (builder.path_in_expression ({"Clone", "clone"}))); auto args = std::vector> (); args.emplace_back (std::move (to_clone)); return builder.call (std::move (path), std::move (args)); } /** * Create the actual "clone" function of the implementation, so * * fn clone(&self) -> Self { } * */ std::unique_ptr DeriveClone::clone_fn (std::unique_ptr &&clone_expr) { auto block = std::unique_ptr ( new BlockExpr ({}, std::move (clone_expr), {}, {}, AST::LoopLabel::error (), loc, loc)); auto big_self_type = builder.single_type_path ("Self"); std::unique_ptr self (new SelfParam (Lifetime::error (), /* is_mut */ false, loc)); std::vector> params; params.push_back (std::move (self)); return std::unique_ptr ( new Function ({"clone"}, builder.fn_qualifiers (), /* generics */ {}, /* function params */ std::move (params), std::move (big_self_type), WhereClause::create_empty (), std::move (block), Visibility::create_private (), {}, loc)); } /** * Create the Clone trait implementation for a type * * impl Clone for { * * } * */ std::unique_ptr DeriveClone::clone_impl (std::unique_ptr &&clone_fn, std::string name) { // should that be `$crate::core::clone::Clone` instead? auto segments = std::vector> (); segments.emplace_back (builder.type_path_segment ("Clone")); auto clone = TypePath (std::move (segments), loc); auto trait_items = std::vector> (); trait_items.emplace_back (std::move (clone_fn)); return std::unique_ptr ( new TraitImpl (clone, /* unsafe */ false, /* exclam */ false, std::move (trait_items), /* generics */ {}, builder.single_type_path (name), WhereClause::create_empty (), Visibility::create_private (), {}, {}, loc)); } // TODO: Create new `make_qualified_call` helper function DeriveClone::DeriveClone (location_t loc) : DeriveVisitor (loc), expanded (nullptr) {} std::unique_ptr DeriveClone::go (Item &item) { item.accept_vis (*this); rust_assert (expanded); return std::move (expanded); } void DeriveClone::visit_tuple (TupleStruct &item) { auto cloned_fields = std::vector> (); for (size_t idx = 0; idx < item.get_fields ().size (); idx++) cloned_fields.emplace_back ( clone_call (builder.ref (builder.tuple_idx ("self", idx)))); auto path = std::unique_ptr (new PathInExpression ( builder.path_in_expression ({item.get_identifier ().as_string ()}))); auto constructor = builder.call (std::move (path), std::move (cloned_fields)); expanded = clone_impl (clone_fn (std::move (constructor)), item.get_identifier ().as_string ()); } void DeriveClone::visit_struct (StructStruct &item) { if (item.is_unit_struct ()) { 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 ()); return; } auto cloned_fields = std::vector> (); for (auto &field : item.get_fields ()) { auto name = field.get_field_name ().as_string (); auto expr = clone_call ( builder.ref (builder.field_access (builder.identifier ("self"), name))); cloned_fields.emplace_back ( builder.struct_expr_field (std::move (name), std::move (expr))); } 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 ()); } void DeriveClone::visit_enum (Enum &item) { rust_sorry_at (item.get_locus (), "cannot derive %qs for these items yet", "Clone"); } void DeriveClone::visit_union (Union &item) { // FIXME: Should be $crate::core::clone::AssertParamIsCopy (or similar) // auto arg = GenericArg::create_type (builder.single_type_path ("Self")); // AssertParamIsCopy:: auto type = std::unique_ptr ( new TypePathSegmentGeneric (PathIdentSegment ("AssertParamIsCopy", loc), false, GenericArgs ({}, {arg}, {}, loc), loc)); auto type_paths = std::vector> (); type_paths.emplace_back (std::move (type)); auto full_path = std::unique_ptr (new TypePath ({std::move (type_paths)}, loc)); auto stmts = std::vector> (); stmts.emplace_back ( builder.let (builder.wildcard (), std::move (full_path), nullptr)); auto tail_expr = builder.deref (builder.identifier ("self")); auto block = builder.block (std::move (stmts), std::move (tail_expr)); expanded = clone_impl (clone_fn (std::move (block)), item.get_identifier ().as_string ()); } } // namespace AST } // namespace Rust