LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors - rust-readonly-check2.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 0.0 % 115 0
Test Date: 2025-09-20 13:40:47 Functions: 0.0 % 15 0
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2025 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-readonly-check2.h"
      20                 :             : #include "rust-hir-expr.h"
      21                 :             : #include "rust-hir-node.h"
      22                 :             : #include "rust-hir-path.h"
      23                 :             : #include "rust-hir-map.h"
      24                 :             : #include "rust-hir-pattern.h"
      25                 :             : #include "rust-mapping-common.h"
      26                 :             : #include "rust-system.h"
      27                 :             : #include "rust-immutable-name-resolution-context.h"
      28                 :             : #include "rust-tyty.h"
      29                 :             : 
      30                 :             : namespace Rust {
      31                 :             : namespace HIR {
      32                 :             : 
      33                 :             : static std::set<HirId> already_assigned_variables = {};
      34                 :             : 
      35                 :           0 : ReadonlyChecker::ReadonlyChecker ()
      36                 :           0 :   : resolver (*Resolver::Resolver::get ()),
      37                 :           0 :     mappings (Analysis::Mappings::get ()),
      38                 :           0 :     context (*Resolver::TypeCheckContext::get ())
      39                 :           0 : {}
      40                 :             : 
      41                 :             : void
      42                 :           0 : ReadonlyChecker::go (Crate &crate)
      43                 :             : {
      44                 :           0 :   for (auto &item : crate.get_items ())
      45                 :           0 :     item->accept_vis (*this);
      46                 :           0 : }
      47                 :             : 
      48                 :             : void
      49                 :           0 : ReadonlyChecker::visit (AssignmentExpr &expr)
      50                 :             : {
      51                 :           0 :   Expr &lhs = expr.get_lhs ();
      52                 :           0 :   mutable_context.enter (expr.get_mappings ().get_hirid ());
      53                 :           0 :   lhs.accept_vis (*this);
      54                 :           0 :   mutable_context.exit ();
      55                 :           0 : }
      56                 :             : 
      57                 :             : void
      58                 :           0 : ReadonlyChecker::visit (PathInExpression &expr)
      59                 :             : {
      60                 :           0 :   if (!mutable_context.is_in_context ())
      61                 :           0 :     return;
      62                 :             : 
      63                 :           0 :   NodeId ast_node_id = expr.get_mappings ().get_nodeid ();
      64                 :           0 :   NodeId def_id;
      65                 :             : 
      66                 :           0 :   auto &nr_ctx
      67                 :           0 :     = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
      68                 :           0 :   if (auto id = nr_ctx.lookup (ast_node_id))
      69                 :           0 :     def_id = *id;
      70                 :             :   else
      71                 :           0 :     return;
      72                 :             : 
      73                 :           0 :   auto hir_id = mappings.lookup_node_to_hir (def_id);
      74                 :           0 :   if (!hir_id)
      75                 :             :     return;
      76                 :             : 
      77                 :             :   // Check if the local variable is mutable.
      78                 :           0 :   auto maybe_pattern = mappings.lookup_hir_pattern (*hir_id);
      79                 :           0 :   if (maybe_pattern
      80                 :           0 :       && maybe_pattern.value ()->get_pattern_type ()
      81                 :             :            == HIR::Pattern::PatternType::IDENTIFIER)
      82                 :           0 :     check_variable (static_cast<IdentifierPattern *> (maybe_pattern.value ()),
      83                 :             :                     expr.get_locus ());
      84                 :             : 
      85                 :             :   // Check if the static item is mutable.
      86                 :           0 :   auto maybe_item = mappings.lookup_hir_item (*hir_id);
      87                 :           0 :   if (maybe_item
      88                 :           0 :       && maybe_item.value ()->get_item_kind () == HIR::Item::ItemKind::Static)
      89                 :             :     {
      90                 :           0 :       auto static_item = static_cast<HIR::StaticItem *> (*maybe_item);
      91                 :           0 :       if (!static_item->is_mut ())
      92                 :           0 :         rust_error_at (expr.get_locus (),
      93                 :             :                        "assignment of read-only location '%s'",
      94                 :           0 :                        static_item->get_identifier ().as_string ().c_str ());
      95                 :             :     }
      96                 :             : 
      97                 :             :   // Check if the constant item is mutable.
      98                 :           0 :   if (maybe_item
      99                 :           0 :       && maybe_item.value ()->get_item_kind () == HIR::Item::ItemKind::Constant)
     100                 :             :     {
     101                 :           0 :       auto const_item = static_cast<HIR::ConstantItem *> (*maybe_item);
     102                 :           0 :       rust_error_at (expr.get_locus (), "assignment of read-only location '%s'",
     103                 :           0 :                      const_item->get_identifier ().as_string ().c_str ());
     104                 :             :     }
     105                 :             : }
     106                 :             : 
     107                 :             : void
     108                 :           0 : ReadonlyChecker::check_variable (IdentifierPattern *pattern,
     109                 :             :                                  location_t assigned_loc)
     110                 :             : {
     111                 :           0 :   if (!mutable_context.is_in_context ())
     112                 :           0 :     return;
     113                 :           0 :   if (pattern->is_mut ())
     114                 :             :     return;
     115                 :             : 
     116                 :           0 :   auto hir_id = pattern->get_mappings ().get_hirid ();
     117                 :           0 :   if (already_assigned_variables.count (hir_id) > 0)
     118                 :           0 :     rust_error_at (assigned_loc, "assignment of read-only variable '%s'",
     119                 :           0 :                    pattern->as_string ().c_str ());
     120                 :           0 :   already_assigned_variables.insert (hir_id);
     121                 :             : }
     122                 :             : 
     123                 :             : void
     124                 :           0 : ReadonlyChecker::collect_assignment_identifier (IdentifierPattern &pattern,
     125                 :             :                                                 bool has_init_expr)
     126                 :             : {
     127                 :           0 :   if (has_init_expr)
     128                 :             :     {
     129                 :           0 :       HirId pattern_id = pattern.get_mappings ().get_hirid ();
     130                 :           0 :       already_assigned_variables.insert (pattern_id);
     131                 :             :     }
     132                 :           0 : }
     133                 :             : 
     134                 :             : void
     135                 :           0 : ReadonlyChecker::collect_assignment_tuple (TuplePattern &tuple_pattern,
     136                 :             :                                            bool has_init_expr)
     137                 :             : {
     138                 :           0 :   switch (tuple_pattern.get_items ().get_item_type ())
     139                 :             :     {
     140                 :           0 :     case HIR::TuplePatternItems::ItemType::MULTIPLE:
     141                 :           0 :       {
     142                 :           0 :         auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
     143                 :           0 :           tuple_pattern.get_items ());
     144                 :           0 :         for (auto &sub : items.get_patterns ())
     145                 :             :           {
     146                 :           0 :             collect_assignment (*sub, has_init_expr);
     147                 :             :           }
     148                 :             :       }
     149                 :             :       break;
     150                 :             :     default:
     151                 :             :       break;
     152                 :             :     }
     153                 :           0 : }
     154                 :             : 
     155                 :             : void
     156                 :           0 : ReadonlyChecker::collect_assignment (Pattern &pattern, bool has_init_expr)
     157                 :             : {
     158                 :           0 :   switch (pattern.get_pattern_type ())
     159                 :             :     {
     160                 :           0 :     case HIR::Pattern::PatternType::IDENTIFIER:
     161                 :           0 :       {
     162                 :           0 :         collect_assignment_identifier (static_cast<IdentifierPattern &> (
     163                 :             :                                          pattern),
     164                 :             :                                        has_init_expr);
     165                 :             :       }
     166                 :           0 :       break;
     167                 :           0 :     case HIR::Pattern::PatternType::TUPLE:
     168                 :           0 :       {
     169                 :           0 :         auto &tuple_pattern = static_cast<HIR::TuplePattern &> (pattern);
     170                 :           0 :         collect_assignment_tuple (tuple_pattern, has_init_expr);
     171                 :             :       }
     172                 :           0 :       break;
     173                 :             :     default:
     174                 :             :       break;
     175                 :             :     }
     176                 :           0 : }
     177                 :             : 
     178                 :             : void
     179                 :           0 : ReadonlyChecker::visit (LetStmt &stmt)
     180                 :             : {
     181                 :           0 :   HIR::Pattern &pattern = stmt.get_pattern ();
     182                 :           0 :   collect_assignment (pattern, stmt.has_init_expr ());
     183                 :           0 : }
     184                 :             : 
     185                 :             : void
     186                 :           0 : ReadonlyChecker::visit (FieldAccessExpr &expr)
     187                 :             : {
     188                 :           0 :   if (mutable_context.is_in_context ())
     189                 :             :     {
     190                 :           0 :       expr.get_receiver_expr ().accept_vis (*this);
     191                 :             :     }
     192                 :           0 : }
     193                 :             : 
     194                 :             : void
     195                 :           0 : ReadonlyChecker::visit (TupleIndexExpr &expr)
     196                 :             : {
     197                 :           0 :   if (mutable_context.is_in_context ())
     198                 :             :     {
     199                 :           0 :       expr.get_tuple_expr ().accept_vis (*this);
     200                 :             :     }
     201                 :           0 : }
     202                 :             : 
     203                 :             : void
     204                 :           0 : ReadonlyChecker::visit (ArrayIndexExpr &expr)
     205                 :             : {
     206                 :           0 :   if (mutable_context.is_in_context ())
     207                 :             :     {
     208                 :           0 :       expr.get_array_expr ().accept_vis (*this);
     209                 :             :     }
     210                 :           0 : }
     211                 :             : 
     212                 :             : void
     213                 :           0 : ReadonlyChecker::visit (TupleExpr &expr)
     214                 :             : {
     215                 :           0 :   if (mutable_context.is_in_context ())
     216                 :             :     {
     217                 :             :       // TODO: Add check for tuple expression
     218                 :             :     }
     219                 :           0 : }
     220                 :             : 
     221                 :             : void
     222                 :           0 : ReadonlyChecker::visit (LiteralExpr &expr)
     223                 :             : {
     224                 :           0 :   if (mutable_context.is_in_context ())
     225                 :             :     {
     226                 :           0 :       rust_error_at (expr.get_locus (), "assignment of read-only location");
     227                 :             :     }
     228                 :           0 : }
     229                 :             : 
     230                 :             : void
     231                 :           0 : ReadonlyChecker::visit (DereferenceExpr &expr)
     232                 :             : {
     233                 :           0 :   if (!mutable_context.is_in_context ())
     234                 :           0 :     return;
     235                 :           0 :   TyTy::BaseType *to_deref_type;
     236                 :           0 :   auto to_deref = expr.get_expr ().get_mappings ().get_hirid ();
     237                 :           0 :   if (!context.lookup_type (to_deref, &to_deref_type))
     238                 :             :     return;
     239                 :           0 :   if (to_deref_type->get_kind () == TyTy::TypeKind::REF)
     240                 :             :     {
     241                 :           0 :       auto ref_type = static_cast<TyTy::ReferenceType *> (to_deref_type);
     242                 :           0 :       if (!ref_type->is_mutable ())
     243                 :           0 :         rust_error_at (expr.get_locus (), "assignment of read-only location");
     244                 :             :     }
     245                 :           0 :   if (to_deref_type->get_kind () == TyTy::TypeKind::POINTER)
     246                 :             :     {
     247                 :           0 :       auto ptr_type = static_cast<TyTy::PointerType *> (to_deref_type);
     248                 :           0 :       if (!ptr_type->is_mutable ())
     249                 :           0 :         rust_error_at (expr.get_locus (), "assignment of read-only location");
     250                 :             :     }
     251                 :             : }
     252                 :             : } // namespace HIR
     253                 :             : } // namespace Rust
        

Generated by: LCOV version 2.1-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.