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
|