19
19
#include " rust-readonly-check.h"
20
20
#include " rust-tree.h"
21
21
#include " rust-gcc.h"
22
+ #include " print-tree.h"
22
23
23
24
namespace Rust {
24
25
namespace Analysis {
25
26
27
+ static std::map<tree, int > assignment_map = {};
28
+
26
29
// ported over from c-family/c-warn.cc
27
30
void
28
31
readonly_error (location_t loc, tree arg, enum lvalue_use use)
@@ -106,37 +109,68 @@ readonly_error (location_t loc, tree arg, enum lvalue_use use)
106
109
}
107
110
108
111
static void
109
- check_decl (tree *t)
112
+ emit_error (tree *t, tree lhs, enum lvalue_use use )
110
113
{
111
- if (TREE_CODE (*t) == MODIFY_EXPR)
114
+ readonly_error (EXPR_LOCATION (*t), lhs, use);
115
+ TREE_OPERAND (*t, 0 ) = error_mark_node;
116
+ }
117
+
118
+ static void
119
+ check_modify_expr (tree *t)
120
+ {
121
+ tree lhs = TREE_OPERAND (*t, 0 );
122
+ if (TREE_CODE (lhs) == ARRAY_REF || TREE_CODE (lhs) == COMPONENT_REF)
123
+ lhs = TREE_OPERAND (lhs, 0 );
124
+
125
+ tree lhs_type = TREE_TYPE (lhs);
126
+ if (TYPE_READONLY (lhs_type) || TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
112
127
{
113
- tree lhs = TREE_OPERAND (*t, 0 );
114
- if (TREE_READONLY (lhs) || TREE_CONSTANT (lhs))
128
+ if (TREE_CODE (lhs) != VAR_DECL)
129
+ emit_error (t, lhs, lv_assign);
130
+ else if (!DECL_ARTIFICIAL (lhs))
115
131
{
116
- readonly_error (EXPR_LOCATION (*t), lhs, lv_assign);
117
- TREE_OPERAND (*t, 0 ) = error_mark_node;
132
+ if (DECL_INITIAL (lhs) != NULL )
133
+ emit_error (t, lhs, lv_assign);
134
+ else
135
+ {
136
+ if (assignment_map.find (lhs) == assignment_map.end ())
137
+ {
138
+ assignment_map.insert ({lhs, 0 });
139
+ }
140
+ assignment_map[lhs]++;
141
+
142
+ if (assignment_map[lhs] > 1 )
143
+ emit_error (t, lhs, lv_assign);
144
+ }
118
145
}
119
146
}
120
147
}
121
148
122
- static tree
123
- readonly_walk_fn (tree *t, int *, void * )
149
+ static void
150
+ check_decl (tree *t)
124
151
{
125
152
switch (TREE_CODE (*t))
126
153
{
127
154
case MODIFY_EXPR:
128
- check_decl (t);
155
+ check_modify_expr (t);
129
156
break ;
130
157
131
158
default :
132
159
break ;
133
160
}
161
+ }
162
+
163
+ static tree
164
+ readonly_walk_fn (tree *t, int *, void *)
165
+ {
166
+ check_decl (t);
134
167
return NULL_TREE;
135
168
}
136
169
137
170
void
138
171
ReadonlyCheck::Lint (Compile::Context &ctx)
139
172
{
173
+ assignment_map.clear ();
140
174
for (auto &fndecl : ctx.get_func_decls ())
141
175
{
142
176
for (tree p = DECL_ARGUMENTS (fndecl); p != NULL_TREE; p = DECL_CHAIN (p))
@@ -148,12 +182,14 @@ ReadonlyCheck::Lint (Compile::Context &ctx)
148
182
&readonly_walk_fn, &ctx);
149
183
}
150
184
185
+ assignment_map.clear ();
151
186
for (auto &var : ctx.get_var_decls ())
152
187
{
153
188
tree decl = var->get_decl ();
154
189
check_decl (&decl);
155
190
}
156
191
192
+ assignment_map.clear ();
157
193
for (auto &const_decl : ctx.get_const_decls ())
158
194
{
159
195
check_decl (&const_decl);
0 commit comments