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