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