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

            Line data    Source code
       1              : // Copyright (C) 2025-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-partial-eq.h"
      20              : #include "rust-ast.h"
      21              : #include "rust-expr.h"
      22              : #include "rust-item.h"
      23              : #include "rust-operators.h"
      24              : #include "rust-path.h"
      25              : #include "rust-pattern.h"
      26              : #include "rust-system.h"
      27              : 
      28              : namespace Rust {
      29              : namespace AST {
      30           94 : DerivePartialEq::DerivePartialEq (location_t loc) : DeriveVisitor (loc) {}
      31              : 
      32              : std::vector<std::unique_ptr<AST::Item>>
      33           94 : DerivePartialEq::go (Item &item)
      34              : {
      35           94 :   item.accept_vis (*this);
      36              : 
      37           94 :   return std::move (expanded);
      38              : }
      39              : 
      40              : std::vector<std::unique_ptr<Item>>
      41           94 : DerivePartialEq::partialeq_impls (
      42              :   std::unique_ptr<AssociatedItem> &&eq_fn, std::string name,
      43              :   const std::vector<std::unique_ptr<GenericParam>> &type_generics)
      44              : {
      45           94 :   auto eq = [this] () { return builder.type_path (LangItem::Kind::EQ); };
      46           94 :   auto speq = builder.type_path (LangItem::Kind::STRUCTURAL_PEQ);
      47              : 
      48           94 :   auto trait_items = vec (std::move (eq_fn));
      49              : 
      50              :   // no extra bound on StructuralPeq
      51          188 :   auto peq_generics = setup_impl_generics (name, type_generics, [&, this] () {
      52            0 :     return builder.trait_bound (eq ());
      53           94 :   });
      54           94 :   auto speq_generics = setup_impl_generics (name, type_generics);
      55              : 
      56          188 :   auto peq = builder.trait_impl (eq (), std::move (peq_generics.self_type),
      57              :                                  std::move (trait_items),
      58           94 :                                  std::move (peq_generics.impl));
      59              : 
      60           94 :   auto structural_peq
      61          188 :     = builder.trait_impl (speq, std::move (speq_generics.self_type), {},
      62           94 :                           std::move (speq_generics.impl));
      63              : 
      64           94 :   return vec (std::move (peq), std::move (structural_peq));
      65          282 : }
      66              : 
      67              : std::unique_ptr<AssociatedItem>
      68           94 : DerivePartialEq::eq_fn (std::unique_ptr<BlockExpr> &&block,
      69              :                         std::string type_name)
      70              : {
      71           94 :   auto self_type
      72           94 :     = std::unique_ptr<TypeNoBounds> (new TypePath (builder.type_path ("Self")));
      73              : 
      74           94 :   auto params
      75          188 :     = vec (builder.self_ref_param (),
      76          188 :            builder.function_param (builder.identifier_pattern ("other"),
      77          188 :                                    builder.reference_type (
      78           94 :                                      std::move (self_type))));
      79              : 
      80          376 :   return builder.function ("eq", std::move (params),
      81          188 :                            builder.single_type_path ("bool"),
      82           94 :                            std::move (block));
      83           94 : }
      84              : 
      85              : std::unique_ptr<Expr>
      86          109 : DerivePartialEq::build_eq_expression (
      87              :   std::vector<SelfOther> &&field_expressions)
      88              : {
      89              :   // for unit structs or empty tuples, this is always true
      90          109 :   if (field_expressions.empty ())
      91            9 :     return builder.literal_bool (true);
      92              : 
      93          100 :   auto cmp_expression
      94          100 :     = builder.comparison_expr (std::move (field_expressions.at (0).self_expr),
      95          100 :                                std::move (field_expressions.at (0).other_expr),
      96          100 :                                ComparisonOperator::EQUAL);
      97              : 
      98          169 :   for (size_t i = 1; i < field_expressions.size (); i++)
      99              :     {
     100           69 :       auto tmp = builder.comparison_expr (
     101           69 :         std::move (field_expressions.at (i).self_expr),
     102           69 :         std::move (field_expressions.at (i).other_expr),
     103          138 :         ComparisonOperator::EQUAL);
     104              : 
     105           69 :       cmp_expression
     106           69 :         = builder.boolean_operation (std::move (cmp_expression),
     107              :                                      std::move (tmp),
     108           69 :                                      LazyBooleanOperator::LOGICAL_AND);
     109           69 :     }
     110              : 
     111          100 :   return cmp_expression;
     112          100 : }
     113              : 
     114              : void
     115            9 : DerivePartialEq::visit_tuple (TupleStruct &item)
     116              : {
     117           18 :   auto type_name = item.get_struct_name ().as_string ();
     118            9 :   auto fields = SelfOther::indexes (builder, item.get_fields ());
     119              : 
     120           27 :   auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
     121            9 :                    type_name);
     122              : 
     123            9 :   expanded
     124           18 :     = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
     125            9 : }
     126              : 
     127              : void
     128           63 : DerivePartialEq::visit_struct (StructStruct &item)
     129              : {
     130          126 :   auto type_name = item.get_struct_name ().as_string ();
     131           63 :   auto fields = SelfOther::fields (builder, item.get_fields ());
     132              : 
     133          189 :   auto fn = eq_fn (builder.block (build_eq_expression (std::move (fields))),
     134           63 :                    type_name);
     135              : 
     136           63 :   expanded
     137          126 :     = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
     138           63 : }
     139              : 
     140              : MatchCase
     141            0 : DerivePartialEq::match_enum_identifier (
     142              :   PathInExpression variant_path, const std::unique_ptr<EnumItem> &variant)
     143              : {
     144            0 :   auto inner_ref_patterns
     145            0 :     = vec (builder.ref_pattern (
     146            0 :              std::unique_ptr<Pattern> (new PathInExpression (variant_path))),
     147            0 :            builder.ref_pattern (
     148            0 :              std::unique_ptr<Pattern> (new PathInExpression (variant_path))));
     149              : 
     150            0 :   auto tuple_items = std::make_unique<TuplePatternItemsNoRest> (
     151            0 :     std::move (inner_ref_patterns));
     152              : 
     153            0 :   auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
     154              : 
     155            0 :   return builder.match_case (std::move (pattern), builder.literal_bool (true));
     156            0 : }
     157              : 
     158              : MatchCase
     159            0 : DerivePartialEq::match_enum_tuple (PathInExpression variant_path,
     160              :                                    const EnumItemTuple &variant)
     161              : {
     162            0 :   auto self_patterns = std::vector<std::unique_ptr<Pattern>> ();
     163            0 :   auto other_patterns = std::vector<std::unique_ptr<Pattern>> ();
     164              : 
     165            0 :   auto self_other_exprs = std::vector<SelfOther> ();
     166              : 
     167            0 :   for (size_t i = 0; i < variant.get_tuple_fields ().size (); i++)
     168              :     {
     169              :       // The patterns we're creating for each field are `self_<i>` and
     170              :       // `other_<i>` where `i` is the index of the field. It doesn't actually
     171              :       // matter what we use, as long as it's ordered, unique, and that we can
     172              :       // reuse it in the match case's return expression to check that they are
     173              :       // equal.
     174              : 
     175            0 :       auto self_pattern_str = "__self_" + std::to_string (i);
     176            0 :       auto other_pattern_str = "__other_" + std::to_string (i);
     177              : 
     178            0 :       self_patterns.emplace_back (
     179            0 :         builder.identifier_pattern (self_pattern_str));
     180            0 :       other_patterns.emplace_back (
     181            0 :         builder.identifier_pattern (other_pattern_str));
     182              : 
     183            0 :       self_other_exprs.emplace_back (SelfOther{
     184            0 :         builder.identifier (self_pattern_str),
     185            0 :         builder.identifier (other_pattern_str),
     186              :       });
     187            0 :     }
     188              : 
     189            0 :   auto self_pattern_items = std::unique_ptr<TupleStructItems> (
     190            0 :     new TupleStructItemsNoRest (std::move (self_patterns)));
     191            0 :   auto other_pattern_items = std::unique_ptr<TupleStructItems> (
     192            0 :     new TupleStructItemsNoRest (std::move (other_patterns)));
     193              : 
     194            0 :   auto self_pattern = std::unique_ptr<Pattern> (
     195            0 :     new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
     196            0 :                             variant_path, std::move (self_pattern_items))),
     197            0 :                           false, false, loc));
     198            0 :   auto other_pattern = std::unique_ptr<Pattern> (
     199            0 :     new ReferencePattern (std::unique_ptr<Pattern> (new TupleStructPattern (
     200            0 :                             variant_path, std::move (other_pattern_items))),
     201            0 :                           false, false, loc));
     202              : 
     203            0 :   auto tuple_items = std::make_unique<TuplePatternItemsNoRest> (
     204            0 :     vec (std::move (self_pattern), std::move (other_pattern)));
     205              : 
     206            0 :   auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
     207              : 
     208            0 :   auto expr = build_eq_expression (std::move (self_other_exprs));
     209              : 
     210            0 :   return builder.match_case (std::move (pattern), std::move (expr));
     211            0 : }
     212              : 
     213              : MatchCase
     214            0 : DerivePartialEq::match_enum_struct (PathInExpression variant_path,
     215              :                                     const EnumItemStruct &variant)
     216              : {
     217            0 :   auto self_fields = std::vector<std::unique_ptr<StructPatternField>> ();
     218            0 :   auto other_fields = std::vector<std::unique_ptr<StructPatternField>> ();
     219              : 
     220            0 :   auto self_other_exprs = std::vector<SelfOther> ();
     221              : 
     222            0 :   for (auto &field : variant.get_struct_fields ())
     223              :     {
     224              :       // The patterns we're creating for each field are `self_<field>` and
     225              :       // `other_<field>` where `field` is the name of the field. It doesn't
     226              :       // actually matter what we use, as long as it's ordered, unique, and that
     227              :       // we can reuse it in the match case's return expression to check that
     228              :       // they are equal.
     229              : 
     230            0 :       auto field_name = field.get_field_name ().as_string ();
     231              : 
     232            0 :       auto self_pattern_str = "__self_" + field_name;
     233            0 :       auto other_pattern_str = "__other_" + field_name;
     234              : 
     235            0 :       self_fields.emplace_back (builder.struct_pattern_ident_pattern (
     236            0 :         field_name, builder.identifier_pattern (self_pattern_str)));
     237            0 :       other_fields.emplace_back (builder.struct_pattern_ident_pattern (
     238            0 :         field_name, builder.identifier_pattern (other_pattern_str)));
     239              : 
     240            0 :       self_other_exprs.emplace_back (SelfOther{
     241            0 :         builder.identifier (self_pattern_str),
     242            0 :         builder.identifier (other_pattern_str),
     243              :       });
     244            0 :     }
     245              : 
     246            0 :   auto self_elts = StructPatternElements (std::move (self_fields));
     247            0 :   auto other_elts = StructPatternElements (std::move (other_fields));
     248              : 
     249            0 :   auto self_pattern = std::unique_ptr<Pattern> (
     250            0 :     new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
     251            0 :                             variant_path, loc, std::move (self_elts))),
     252            0 :                           false, false, loc));
     253            0 :   auto other_pattern = std::unique_ptr<Pattern> (
     254            0 :     new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
     255            0 :                             variant_path, loc, std::move (other_elts))),
     256            0 :                           false, false, loc));
     257              : 
     258            0 :   auto tuple_items = std::make_unique<TuplePatternItemsNoRest> (
     259            0 :     vec (std::move (self_pattern), std::move (other_pattern)));
     260              : 
     261            0 :   auto pattern = std::make_unique<TuplePattern> (std::move (tuple_items), loc);
     262              : 
     263            0 :   auto expr = build_eq_expression (std::move (self_other_exprs));
     264              : 
     265            0 :   return builder.match_case (std::move (pattern), std::move (expr));
     266            0 : }
     267              : 
     268              : void
     269           22 : DerivePartialEq::visit_enum (Enum &item)
     270              : {
     271           22 :   auto cases = std::vector<MatchCase> ();
     272           44 :   auto type_name = item.get_identifier ().as_string ();
     273              : 
     274           59 :   auto eq_expr_fn = [this] (std::vector<SelfOther> &&fields) {
     275           37 :     return build_eq_expression (std::move (fields));
     276           22 :   };
     277              : 
     278           22 :   auto let_sd
     279           22 :     = builder.discriminant_value (DerivePartialEq::self_discr, "self");
     280           22 :   auto let_od
     281           22 :     = builder.discriminant_value (DerivePartialEq::other_discr, "other");
     282              : 
     283           22 :   auto discr_cmp
     284           44 :     = builder.comparison_expr (builder.identifier (DerivePartialEq::self_discr),
     285           44 :                                builder.identifier (
     286           22 :                                  DerivePartialEq::other_discr),
     287           22 :                                ComparisonOperator::EQUAL);
     288              : 
     289           81 :   for (auto &variant : item.get_variants ())
     290              :     {
     291           59 :       auto enum_builder
     292          118 :         = EnumMatchBuilder (type_name, variant->get_identifier ().as_string (),
     293           59 :                             eq_expr_fn, builder);
     294              : 
     295           59 :       switch (variant->get_enum_item_kind ())
     296              :         {
     297           22 :         case EnumItem::Kind::Tuple:
     298           22 :           cases.emplace_back (enum_builder.tuple (*variant));
     299           22 :           break;
     300           15 :         case EnumItem::Kind::Struct:
     301           15 :           cases.emplace_back (enum_builder.strukt (*variant));
     302           15 :           break;
     303              :         case EnumItem::Kind::Identifier:
     304              :         case EnumItem::Kind::Discriminant:
     305              :           // We don't need to do anything for these, as they are handled by the
     306              :           // discriminant value comparison
     307              :           break;
     308              :         }
     309           59 :     }
     310              : 
     311              :   // In case the two instances of `Self` don't have the same discriminant,
     312              :   // automatically return false.
     313           22 :   cases.emplace_back (
     314           44 :     builder.match_case (builder.wildcard (), std::move (discr_cmp)));
     315              : 
     316           22 :   auto match
     317           44 :     = builder.match (builder.tuple (vec (builder.identifier ("self"),
     318           44 :                                          builder.identifier ("other"))),
     319           22 :                      std::move (cases));
     320              : 
     321           66 :   auto fn = eq_fn (builder.block (vec (std::move (let_sd), std::move (let_od)),
     322              :                                   std::move (match)),
     323           22 :                    type_name);
     324              : 
     325           22 :   expanded
     326           44 :     = partialeq_impls (std::move (fn), type_name, item.get_generic_params ());
     327           22 : }
     328              : 
     329              : void
     330            0 : DerivePartialEq::visit_union (Union &item)
     331              : {
     332            0 :   rust_error_at (item.get_locus (),
     333              :                  "derive(PartialEq) cannot be used on unions");
     334            0 : }
     335              : 
     336              : } // namespace AST
     337              : } // 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.