LCOV - code coverage report
Current view: top level - gcc/rust/checks/errors - rust-readonly-check.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 86.4 % 59 51
Test Date: 2025-07-12 13:27:34 Functions: 100.0 % 6 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (C) 2021-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-check.h"
      20                 :             : #include "rust-tree.h"
      21                 :             : #include "rust-gcc.h"
      22                 :             : #include "print-tree.h"
      23                 :             : 
      24                 :             : namespace Rust {
      25                 :             : namespace Analysis {
      26                 :             : 
      27                 :             : static std::map<tree, int> assignment_map = {};
      28                 :             : 
      29                 :             : // ported over from c-family/c-warn.cc
      30                 :             : void
      31                 :          10 : readonly_error (location_t loc, tree arg, enum lvalue_use use)
      32                 :             : {
      33                 :          10 :   gcc_assert (use == lv_assign || use == lv_increment || use == lv_decrement
      34                 :             :               || use == lv_asm);
      35                 :          10 :   STRIP_ANY_LOCATION_WRAPPER (arg);
      36                 :             :   /* Using this macro rather than (for example) arrays of messages
      37                 :             :      ensures that all the format strings are checked at compile
      38                 :             :      time.  */
      39                 :             : #define READONLY_MSG(A, I, D, AS)                                              \
      40                 :             :   (use == lv_assign                                                            \
      41                 :             :      ? (A)                                                                     \
      42                 :             :      : (use == lv_increment ? (I) : (use == lv_decrement ? (D) : (AS))))
      43                 :          10 :   if (TREE_CODE (arg) == COMPONENT_REF)
      44                 :             :     {
      45                 :           0 :       if (TYPE_READONLY (TREE_TYPE (TREE_OPERAND (arg, 0))))
      46                 :           0 :         error_at (loc,
      47                 :             :                   READONLY_MSG (G_ ("assignment of member "
      48                 :             :                                     "%qD in read-only object"),
      49                 :             :                                 G_ ("increment of member "
      50                 :             :                                     "%qD in read-only object"),
      51                 :             :                                 G_ ("decrement of member "
      52                 :             :                                     "%qD in read-only object"),
      53                 :             :                                 G_ ("member %qD in read-only object "
      54                 :             :                                     "used as %<asm%> output")),
      55                 :           0 :                   TREE_OPERAND (arg, 1));
      56                 :             :       else
      57                 :           0 :         error_at (
      58                 :             :           loc,
      59                 :             :           READONLY_MSG (G_ ("assignment of read-only member %qD"),
      60                 :             :                         G_ ("increment of read-only member %qD"),
      61                 :             :                         G_ ("decrement of read-only member %qD"),
      62                 :             :                         G_ ("read-only member %qD used as %<asm%> output")),
      63                 :           0 :           TREE_OPERAND (arg, 1));
      64                 :             :     }
      65                 :             :   else if (VAR_P (arg))
      66                 :          12 :     error_at (loc,
      67                 :             :               READONLY_MSG (G_ ("assignment of read-only variable %qD"),
      68                 :             :                             G_ ("increment of read-only variable %qD"),
      69                 :             :                             G_ ("decrement of read-only variable %qD"),
      70                 :             :                             G_ (
      71                 :             :                               "read-only variable %qD used as %<asm%> output")),
      72                 :             :               arg);
      73                 :             :   else if (TREE_CODE (arg) == PARM_DECL)
      74                 :           0 :     error_at (loc,
      75                 :             :               READONLY_MSG (G_ ("assignment of read-only parameter %qD"),
      76                 :             :                             G_ ("increment of read-only parameter %qD"),
      77                 :             :                             G_ ("decrement of read-only parameter %qD"),
      78                 :             :                             G_ (
      79                 :             :                               "read-only parameter %qD use as %<asm%> output")),
      80                 :             :               arg);
      81                 :             :   else if (TREE_CODE (arg) == RESULT_DECL)
      82                 :             :     {
      83                 :           0 :       error_at (loc,
      84                 :             :                 READONLY_MSG (G_ ("assignment of "
      85                 :             :                                   "read-only named return value %qD"),
      86                 :             :                               G_ ("increment of "
      87                 :             :                                   "read-only named return value %qD"),
      88                 :             :                               G_ ("decrement of "
      89                 :             :                                   "read-only named return value %qD"),
      90                 :             :                               G_ ("read-only named return value %qD "
      91                 :             :                                   "used as %<asm%>output")),
      92                 :             :                 arg);
      93                 :             :     }
      94                 :             :   else if (TREE_CODE (arg) == FUNCTION_DECL)
      95                 :           0 :     error_at (loc,
      96                 :             :               READONLY_MSG (G_ ("assignment of function %qD"),
      97                 :             :                             G_ ("increment of function %qD"),
      98                 :             :                             G_ ("decrement of function %qD"),
      99                 :             :                             G_ ("function %qD used as %<asm%> output")),
     100                 :             :               arg);
     101                 :             :   else
     102                 :           8 :     error_at (loc,
     103                 :             :               READONLY_MSG (G_ ("assignment of read-only location %qE"),
     104                 :             :                             G_ ("increment of read-only location %qE"),
     105                 :             :                             G_ ("decrement of read-only location %qE"),
     106                 :             :                             G_ (
     107                 :             :                               "read-only location %qE used as %<asm%> output")),
     108                 :             :               arg);
     109                 :          10 : }
     110                 :             : 
     111                 :             : static void
     112                 :          10 : emit_error (tree *t, tree lhs, enum lvalue_use use)
     113                 :             : {
     114                 :          10 :   readonly_error (EXPR_LOCATION (*t), lhs, use);
     115                 :          10 :   TREE_OPERAND (*t, 0) = error_mark_node;
     116                 :          10 : }
     117                 :             : 
     118                 :             : static void
     119                 :       23798 : check_modify_expr (tree *t)
     120                 :             : {
     121                 :       23798 :   tree lhs = TREE_OPERAND (*t, 0);
     122                 :       23798 :   if (TREE_CODE (lhs) == ARRAY_REF || TREE_CODE (lhs) == COMPONENT_REF)
     123                 :          36 :     lhs = TREE_OPERAND (lhs, 0);
     124                 :             : 
     125                 :       23798 :   tree lhs_type = TREE_TYPE (lhs);
     126                 :       23798 :   if (TYPE_READONLY (lhs_type) || TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
     127                 :             :     {
     128                 :        2750 :       if (TREE_CODE (lhs) != VAR_DECL)
     129                 :           4 :         emit_error (t, lhs, lv_assign);
     130                 :        2746 :       else if (!DECL_ARTIFICIAL (lhs))
     131                 :             :         {
     132                 :        1045 :           if (DECL_INITIAL (lhs) != NULL)
     133                 :           4 :             emit_error (t, lhs, lv_assign);
     134                 :             :           else
     135                 :             :             {
     136                 :        1041 :               if (assignment_map.find (lhs) == assignment_map.end ())
     137                 :             :                 {
     138                 :        1039 :                   assignment_map.insert ({lhs, 0});
     139                 :             :                 }
     140                 :        1041 :               assignment_map[lhs]++;
     141                 :             : 
     142                 :        1041 :               if (assignment_map[lhs] > 1)
     143                 :           2 :                 emit_error (t, lhs, lv_assign);
     144                 :             :             }
     145                 :             :         }
     146                 :             :     }
     147                 :       23798 : }
     148                 :             : 
     149                 :             : static void
     150                 :      331561 : check_decl (tree *t)
     151                 :             : {
     152                 :      331561 :   switch (TREE_CODE (*t))
     153                 :             :     {
     154                 :       23798 :     case MODIFY_EXPR:
     155                 :       23798 :       check_modify_expr (t);
     156                 :       23798 :       break;
     157                 :             : 
     158                 :             :     default:
     159                 :             :       break;
     160                 :             :     }
     161                 :      331561 : }
     162                 :             : 
     163                 :             : static tree
     164                 :      318726 : readonly_walk_fn (tree *t, int *, void *)
     165                 :             : {
     166                 :      318726 :   check_decl (t);
     167                 :      318726 :   return NULL_TREE;
     168                 :             : }
     169                 :             : 
     170                 :             : void
     171                 :        4203 : ReadonlyCheck::Lint (Compile::Context &ctx)
     172                 :             : {
     173                 :        4203 :   assignment_map.clear ();
     174                 :       19295 :   for (auto &fndecl : ctx.get_func_decls ())
     175                 :             :     {
     176                 :       27341 :       for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p))
     177                 :             :         {
     178                 :       12249 :           check_decl (&p);
     179                 :             :         }
     180                 :             : 
     181                 :       15092 :       walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
     182                 :             :                                     &readonly_walk_fn, &ctx);
     183                 :             :     }
     184                 :             : 
     185                 :        4203 :   assignment_map.clear ();
     186                 :        4258 :   for (auto &var : ctx.get_var_decls ())
     187                 :             :     {
     188                 :          55 :       tree decl = var->get_decl ();
     189                 :          55 :       check_decl (&decl);
     190                 :             :     }
     191                 :             : 
     192                 :        4203 :   assignment_map.clear ();
     193                 :        4734 :   for (auto &const_decl : ctx.get_const_decls ())
     194                 :             :     {
     195                 :         531 :       check_decl (&const_decl);
     196                 :             :     }
     197                 :        4203 : }
     198                 :             : 
     199                 :             : } // namespace Analysis
     200                 :             : } // 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.