LCOV - code coverage report
Current view: top level - gcc/rust/expand - rust-derive-clone.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 100.0 % 187 187
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 13 13
Legend: Lines:     hit not hit

            Line data    Source code
       1              : // Copyright (C) 2020-2026 Free Software Foundation, Inc.
       2              : 
       3              : // This file is part of GCC.
       4              : 
       5              : // GCC is free software; you can redistribute it and/or modify it under
       6              : // the terms of the GNU General Public License as published by the Free
       7              : // Software Foundation; either version 3, or (at your option) any later
       8              : // version.
       9              : 
      10              : // GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      11              : // WARRANTY; without even the implied warranty of MERCHANTABILITY or
      12              : // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      13              : // for more details.
      14              : 
      15              : // You should have received a copy of the GNU General Public License
      16              : // along with GCC; see the file COPYING3.  If not see
      17              : // <http://www.gnu.org/licenses/>.
      18              : 
      19              : #include "rust-derive-clone.h"
      20              : #include "rust-ast.h"
      21              : #include "rust-expr.h"
      22              : #include "rust-item.h"
      23              : #include "rust-path.h"
      24              : #include "rust-pattern.h"
      25              : #include "rust-system.h"
      26              : 
      27              : namespace Rust {
      28              : namespace AST {
      29              : 
      30              : std::unique_ptr<Expr>
      31           61 : DeriveClone::clone_call (std::unique_ptr<Expr> &&to_clone)
      32              : {
      33              :   // $crate::core::clone::Clone::clone for the fully qualified path - we don't
      34              :   // link with `core` yet so that might be an issue. Use `Clone::clone` for now?
      35              :   // TODO: Factor this function inside the DeriveAccumulator
      36              : 
      37              :   // Interestingly, later versions of Rust have a `clone_fn` lang item which
      38              :   // corresponds to this. But because we are first targeting 1.49, we cannot use
      39              :   // it yet. Once we target a new, more recent version of the language, we'll
      40              :   // have figured out how to compile and distribute `core`, meaning we'll be
      41              :   // able to directly call `::core::clone::Clone::clone()`
      42              : 
      43              :   // Not sure how to call it properly in the meantime...
      44              : 
      45           61 :   auto args = std::vector<std::unique_ptr<Expr>> ();
      46           61 :   args.emplace_back (std::move (to_clone));
      47              : 
      48           61 :   return builder.qualified_call ({"Clone", "clone"}, std::move (args));
      49           61 : }
      50              : 
      51              : /**
      52              :  * Create the actual "clone" function of the implementation, so
      53              :  *
      54              :  * fn clone(&self) -> Self { <clone_expr> }
      55              :  *
      56              :  */
      57              : std::unique_ptr<AssociatedItem>
      58           38 : DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr)
      59              : {
      60           38 :   auto block = std::unique_ptr<BlockExpr> (
      61           38 :     new BlockExpr ({}, std::move (clone_expr), {}, {}, tl::nullopt, loc, loc));
      62           38 :   auto big_self_type = builder.single_type_path ("Self");
      63              : 
      64           38 :   std::vector<std::unique_ptr<Param>> params;
      65              : 
      66           38 :   params.emplace_back (new SelfParam (tl::nullopt,
      67           38 :                                       /* is_mut */ false, loc));
      68              : 
      69           38 :   return std::unique_ptr<AssociatedItem> (
      70           38 :     new Function ({"clone"}, builder.fn_qualifiers (), /* generics */ {},
      71              :                   /* function params */ std::move (params),
      72           76 :                   std::move (big_self_type), WhereClause::create_empty (),
      73          114 :                   std::move (block), Visibility::create_private (), {}, loc));
      74           38 : }
      75              : 
      76              : /**
      77              :  * Create the Clone trait implementation for a type
      78              :  *
      79              :  * impl Clone for <type> {
      80              :  *     <clone_fn>
      81              :  * }
      82              :  *
      83              :  */
      84              : std::unique_ptr<Item>
      85           38 : DeriveClone::clone_impl (
      86              :   std::unique_ptr<AssociatedItem> &&clone_fn, std::string name,
      87              :   const std::vector<std::unique_ptr<GenericParam>> &type_generics)
      88              : {
      89           38 :   auto clone_trait_path
      90           38 :     = [this] () { return builder.type_path (LangItem::Kind::CLONE); };
      91              : 
      92           38 :   auto trait_items = vec (std::move (clone_fn));
      93              : 
      94           77 :   auto generics = setup_impl_generics (name, type_generics, [&, this] () {
      95            1 :     return builder.trait_bound (clone_trait_path ());
      96           38 :   });
      97              : 
      98           76 :   return builder.trait_impl (clone_trait_path (),
      99              :                              std::move (generics.self_type),
     100              :                              std::move (trait_items),
     101           76 :                              std::move (generics.impl));
     102           38 : }
     103              : 
     104           38 : DeriveClone::DeriveClone (location_t loc)
     105           38 :   : DeriveVisitor (loc), expanded (nullptr)
     106           38 : {}
     107              : 
     108              : std::unique_ptr<AST::Item>
     109           38 : DeriveClone::go (Item &item)
     110              : {
     111           38 :   item.accept_vis (*this);
     112              : 
     113           38 :   rust_assert (expanded);
     114              : 
     115           38 :   return std::move (expanded);
     116              : }
     117              : 
     118              : void
     119            7 : DeriveClone::visit_tuple (TupleStruct &item)
     120              : {
     121            7 :   auto cloned_fields = std::vector<std::unique_ptr<Expr>> ();
     122              : 
     123           21 :   for (size_t idx = 0; idx < item.get_fields ().size (); idx++)
     124           14 :     cloned_fields.emplace_back (
     125           28 :       clone_call (builder.ref (builder.tuple_idx ("self", idx))));
     126              : 
     127            7 :   auto path = std::unique_ptr<Expr> (new PathInExpression (
     128           21 :     builder.path_in_expression ({item.get_identifier ().as_string ()})));
     129            7 :   auto constructor = builder.call (std::move (path), std::move (cloned_fields));
     130              : 
     131           14 :   expanded = clone_impl (clone_fn (std::move (constructor)),
     132            7 :                          item.get_identifier ().as_string (),
     133           14 :                          item.get_generic_params ());
     134            7 : }
     135              : 
     136              : void
     137           19 : DeriveClone::visit_struct (StructStruct &item)
     138              : {
     139           19 :   if (item.is_unit_struct ())
     140              :     {
     141            3 :       auto unit_ctor
     142            6 :         = builder.struct_expr_struct (item.get_struct_name ().as_string ());
     143            6 :       expanded = clone_impl (clone_fn (std::move (unit_ctor)),
     144            3 :                              item.get_struct_name ().as_string (),
     145            6 :                              item.get_generic_params ());
     146            3 :       return;
     147            3 :     }
     148              : 
     149           16 :   auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
     150           41 :   for (auto &field : item.get_fields ())
     151              :     {
     152           50 :       auto name = field.get_field_name ().as_string ();
     153           25 :       auto expr = clone_call (
     154           50 :         builder.ref (builder.field_access (builder.identifier ("self"), name)));
     155              : 
     156           25 :       cloned_fields.emplace_back (
     157           50 :         builder.struct_expr_field (std::move (name), std::move (expr)));
     158           25 :     }
     159              : 
     160           32 :   auto ctor = builder.struct_expr (item.get_struct_name ().as_string (),
     161           32 :                                    std::move (cloned_fields));
     162           32 :   expanded = clone_impl (clone_fn (std::move (ctor)),
     163           16 :                          item.get_struct_name ().as_string (),
     164           32 :                          item.get_generic_params ());
     165           16 : }
     166              : 
     167              : MatchCase
     168            9 : DeriveClone::clone_enum_identifier (PathInExpression variant_path,
     169              :                                     const std::unique_ptr<EnumItem> &variant)
     170              : {
     171            9 :   auto pattern = std::unique_ptr<Pattern> (new ReferencePattern (
     172            9 :     std::unique_ptr<Pattern> (new PathInExpression (
     173            9 :       variant_path.get_segments (), {}, variant_path.get_locus (),
     174           18 :       variant_path.opening_scope_resolution ())),
     175           18 :     false, false, loc));
     176            9 :   auto expr = std::unique_ptr<Expr> (
     177            9 :     new PathInExpression (variant_path.get_segments (), {},
     178              :                           variant_path.get_locus (),
     179            9 :                           variant_path.opening_scope_resolution ()));
     180              : 
     181            9 :   return builder.match_case (std::move (pattern), std::move (expr));
     182            9 : }
     183              : 
     184              : MatchCase
     185            9 : DeriveClone::clone_enum_tuple (PathInExpression variant_path,
     186              :                                const EnumItemTuple &variant)
     187              : {
     188            9 :   auto patterns = std::vector<std::unique_ptr<Pattern>> ();
     189            9 :   auto cloned_patterns = std::vector<std::unique_ptr<Expr>> ();
     190              : 
     191           20 :   for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++)
     192              :     {
     193              :       // The pattern we're creating for each field is `self_<i>` where `i` is
     194              :       // the index of the field. It doesn't actually matter what we use, as long
     195              :       // as it's ordered, unique, and that we can reuse it in the match case's
     196              :       // return expression to clone the field.
     197           11 :       auto pattern_str = "__self_" + std::to_string (i);
     198              : 
     199           22 :       patterns.emplace_back (builder.identifier_pattern (pattern_str));
     200              : 
     201              :       // Now, for each tuple's element, we create a new expression calling
     202              :       // `clone` on it for the match case's return expression
     203           11 :       cloned_patterns.emplace_back (
     204           33 :         clone_call (builder.ref (builder.identifier (pattern_str))));
     205           11 :     }
     206              : 
     207            9 :   auto pattern_items = std::unique_ptr<TupleStructItems> (
     208            9 :     new TupleStructItemsNoRest (std::move (patterns)));
     209              : 
     210            9 :   auto pattern = std::unique_ptr<Pattern> (new ReferencePattern (
     211            9 :     std::unique_ptr<Pattern> (new TupleStructPattern (
     212           18 :       PathInExpression (variant_path.get_segments (), {},
     213              :                         variant_path.get_locus (),
     214           18 :                         variant_path.opening_scope_resolution ()),
     215           27 :       std::move (pattern_items))),
     216           18 :     false, false, loc));
     217              : 
     218            9 :   auto expr = builder.call (std::unique_ptr<Expr> (new PathInExpression (
     219            9 :                               variant_path.get_segments (), {},
     220              :                               variant_path.get_locus (),
     221           18 :                               variant_path.opening_scope_resolution ())),
     222           18 :                             std::move (cloned_patterns));
     223              : 
     224            9 :   return builder.match_case (std::move (pattern), std::move (expr));
     225            9 : }
     226              : 
     227              : MatchCase
     228            9 : DeriveClone::clone_enum_struct (PathInExpression variant_path,
     229              :                                 const EnumItemStruct &variant)
     230              : {
     231            9 :   auto field_patterns = std::vector<std::unique_ptr<StructPatternField>> ();
     232            9 :   auto cloned_fields = std::vector<std::unique_ptr<StructExprField>> ();
     233              : 
     234              : #if 0
     235              :   // NOTE: We currently do not support compiling struct patterns where an
     236              :   // identifier is assigned a new pattern, e.g. Bloop { f0: x }
     237              :   // This is the code we should eventually produce as it mimics what rustc does
     238              :   // - which is probably here for a good reason. In the meantime, we can just
     239              :   // use the field's identifier as the pattern: Bloop { f0 }
     240              :   // We can then clone the field directly instead of calling `clone()` on the
     241              :   // new pattern.
     242              :   // TODO: Figure out if that is actually needed and why rustc does it?
     243              : 
     244              :   for (size_t i = 0; i < variant.get_struct_fields ().size (); i++)
     245              :     {
     246              :       auto &field = variant.get_struct_fields ()[i];
     247              : 
     248              :       // Just like for tuples, the pattern we're creating for each field is
     249              :       // `self_<i>` where `i` is the index of the field. It doesn't actually
     250              :       // matter what we use, as long as it's ordered, unique, and that we can
     251              :       // reuse it in the match case's return expression to clone the field.
     252              :       auto pattern_str = "__self_" + std::to_string (i);
     253              : 
     254              :       field_patterns.emplace_back (
     255              :         std::unique_ptr<StructPatternField> (new StructPatternFieldIdentPat (
     256              :           field.get_field_name (), builder.identifier_pattern (pattern_str), {},
     257              :           loc)));
     258              : 
     259              :       cloned_fields.emplace_back (
     260              :         std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue (
     261              :           field.get_field_name (),
     262              :           clone_call (builder.ref (builder.identifier (pattern_str))), {},
     263              :           loc)));
     264              :     }
     265              : #endif
     266              : 
     267           20 :   for (const auto &field : variant.get_struct_fields ())
     268              :     {
     269              :       // We match on the struct's fields, and then recreate an instance of that
     270              :       // struct, cloning each field
     271              : 
     272           11 :       field_patterns.emplace_back (
     273           11 :         std::unique_ptr<StructPatternField> (new StructPatternFieldIdent (
     274           22 :           field.get_field_name (), false /* is_ref? true? */, false, {}, loc)));
     275              : 
     276           11 :       cloned_fields.emplace_back (
     277           11 :         std::unique_ptr<StructExprField> (new StructExprFieldIdentifierValue (
     278           22 :           field.get_field_name (),
     279           22 :           clone_call (builder.ref (
     280           33 :             builder.identifier (field.get_field_name ().as_string ()))),
     281           33 :           {}, loc)));
     282              :     }
     283              : 
     284            9 :   auto pattern_elts = StructPatternElements (std::move (field_patterns));
     285              : 
     286            9 :   auto pattern = std::unique_ptr<Pattern> (
     287            9 :     new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
     288           18 :                             variant_path, loc, pattern_elts)),
     289           18 :                           false, false, loc));
     290              : 
     291            9 :   PathInExpression new_path (variant_path.get_segments (),
     292            9 :                              variant_path.get_outer_attrs (),
     293              :                              variant_path.get_locus (),
     294           18 :                              variant_path.opening_scope_resolution ());
     295              : 
     296            9 :   auto expr = std::unique_ptr<Expr> (
     297            9 :     new StructExprStructFields (new_path, std::move (cloned_fields), loc));
     298              : 
     299            9 :   return builder.match_case (std::move (pattern), std::move (expr));
     300           18 : }
     301              : 
     302              : void
     303           10 : DeriveClone::visit_enum (Enum &item)
     304              : {
     305              :   // Create an arm for each variant of the enum:
     306              :   // - For enum item variants (simple identifiers), just create the same
     307              :   // variant.
     308              :   // - For struct and tuple variants, destructure the pattern and call clone for
     309              :   // each field.
     310              : 
     311           10 :   auto cases = std::vector<MatchCase> ();
     312              : 
     313           37 :   for (const auto &variant : item.get_variants ())
     314              :     {
     315           27 :       auto path
     316           54 :         = builder.variant_path (item.get_identifier ().as_string (),
     317           27 :                                 variant->get_identifier ().as_string ());
     318              : 
     319           27 :       switch (variant->get_enum_item_kind ())
     320              :         {
     321              :         // Identifiers and discriminated variants are the same for a clone - we
     322              :         // just return the same variant
     323            9 :         case EnumItem::Kind::Identifier:
     324            9 :         case EnumItem::Kind::Discriminant:
     325           18 :           cases.emplace_back (clone_enum_identifier (path, variant));
     326            9 :           break;
     327            9 :         case EnumItem::Kind::Tuple:
     328           18 :           cases.emplace_back (
     329           18 :             clone_enum_tuple (path, static_cast<EnumItemTuple &> (*variant)));
     330            9 :           break;
     331            9 :         case EnumItem::Kind::Struct:
     332           18 :           cases.emplace_back (
     333           18 :             clone_enum_struct (path, static_cast<EnumItemStruct &> (*variant)));
     334            9 :           break;
     335              :         }
     336           27 :     }
     337              : 
     338              :   // match self { ... }
     339           10 :   auto match = builder.match (builder.identifier ("self"), std::move (cases));
     340              : 
     341           30 :   expanded = clone_impl (clone_fn (std::move (match)),
     342           10 :                          item.get_identifier ().as_string (),
     343           20 :                          item.get_generic_params ());
     344           10 : }
     345              : 
     346              : void
     347            2 : DeriveClone::visit_union (Union &item)
     348              : {
     349              :   // FIXME: Should be $crate::core::clone::AssertParamIsCopy (or similar)
     350              :   // (Rust-GCC#3329)
     351              : 
     352            2 :   auto copy_path = builder.type_path (LangItem::Kind::COPY);
     353            2 :   auto sized_path = builder.type_path (LangItem::Kind::SIZED);
     354              : 
     355            2 :   auto copy_bound = std::unique_ptr<TypeParamBound> (
     356            2 :     new TraitBound (copy_path, item.get_locus ()));
     357            2 :   auto sized_bound = std::unique_ptr<TypeParamBound> (
     358              :     new TraitBound (sized_path, item.get_locus (), false,
     359            2 :                     true /* opening_question_mark */));
     360              : 
     361            2 :   auto bounds = vec (std::move (copy_bound), std::move (sized_bound));
     362              : 
     363              :   // struct AssertParamIsCopy<T: Copy + ?Sized> { _t: PhantomData<T> }
     364            2 :   auto assert_param_is_copy = "AssertParamIsCopy";
     365            2 :   auto t = std::unique_ptr<GenericParam> (
     366            4 :     new TypeParam (Identifier ("T"), item.get_locus (), std::move (bounds)));
     367            6 :   auto assert_param_is_copy_struct = builder.struct_struct (
     368            4 :     assert_param_is_copy, vec (std::move (t)),
     369              :     {StructField (
     370            6 :       Identifier ("_t"),
     371            4 :       builder.single_generic_type_path (
     372              :         LangItem::Kind::PHANTOM_DATA,
     373            2 :         GenericArgs (
     374            6 :           {}, {GenericArg::create_type (builder.single_type_path ("T"))}, {})),
     375            6 :       Visibility::create_private (), item.get_locus ())});
     376              : 
     377              :   // <Self>
     378            2 :   auto arg = GenericArg::create_type (builder.single_type_path ("Self"));
     379              : 
     380              :   // AssertParamIsCopy::<Self>
     381            2 :   auto type = std::unique_ptr<TypePathSegment> (
     382            4 :     new TypePathSegmentGeneric (PathIdentSegment (assert_param_is_copy, loc),
     383            8 :                                 false, GenericArgs ({}, {arg}, {}, loc), loc));
     384            2 :   auto type_paths = std::vector<std::unique_ptr<TypePathSegment>> ();
     385            2 :   type_paths.emplace_back (std::move (type));
     386              : 
     387            2 :   auto full_path
     388            2 :     = std::unique_ptr<Type> (new TypePath ({std::move (type_paths)}, loc));
     389              : 
     390            2 :   auto tail_expr = builder.deref (builder.identifier ("self"));
     391              : 
     392            2 :   auto stmts
     393              :     = vec (std::move (assert_param_is_copy_struct),
     394            2 :            builder.let (builder.wildcard (), std::move (full_path), nullptr));
     395              : 
     396            2 :   auto block = builder.block (std::move (stmts), std::move (tail_expr));
     397              : 
     398            6 :   expanded = clone_impl (clone_fn (std::move (block)),
     399            2 :                          item.get_identifier ().as_string (),
     400            4 :                          item.get_generic_params ());
     401            2 : }
     402              : 
     403              : } // namespace AST
     404              : } // namespace Rust
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.