]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/testsuite/gcc.dg/plugin/selfassign.c
switch from gimple to gimple*
[thirdparty/gcc.git] / gcc / testsuite / gcc.dg / plugin / selfassign.c
CommitLineData
8ba50c2c
LCW
1/* This plugin contains an analysis pass that detects and warns about
2 self-assignment statements. */
3/* { dg-options "-O" } */
4
3e17e31d 5#include "gcc-plugin.h"
8ba50c2c
LCW
6#include "config.h"
7#include "system.h"
8#include "coretypes.h"
9#include "tm.h"
4d648807 10#include "tree.h"
d8a2d370 11#include "stringpool.h"
8ba50c2c
LCW
12#include "toplev.h"
13#include "basic-block.h"
2fb9a547
AM
14#include "hash-table.h"
15#include "vec.h"
16#include "ggc.h"
17#include "basic-block.h"
18#include "tree-ssa-alias.h"
19#include "internal-fn.h"
20#include "gimple-fold.h"
21#include "tree-eh.h"
22#include "gimple-expr.h"
23#include "is-a.h"
8ba50c2c 24#include "gimple.h"
5be5c238 25#include "gimple-iterator.h"
8ba50c2c
LCW
26#include "tree.h"
27#include "tree-pass.h"
28#include "intl.h"
e4d5031c 29#include "plugin-version.h"
ba2dc63d 30#include "diagnostic.h"
f7695dbf 31#include "context.h"
8ba50c2c 32
fca5bb5c
DN
33int plugin_is_GPL_compatible;
34
8ba50c2c
LCW
35/* Indicate whether to check overloaded operator '=', which is performed by
36 default. To disable it, use -fplugin-arg-NAME-no-check-operator-eq. */
37bool check_operator_eq = true;
38
39/* Given a rhs EXPR of a gimple assign statement, if it is
40 - SSA_NAME : returns its var decl, or, if it is a temp variable,
41 returns the rhs of its SSA def statement.
42 - VAR_DECL, PARM_DECL, FIELD_DECL, or a reference expression :
43 returns EXPR itself.
44 - any other expression : returns NULL_TREE. */
45
46static tree
47get_real_ref_rhs (tree expr)
48{
49 switch (TREE_CODE (expr))
50 {
51 case SSA_NAME:
52 {
53 /* Given a self-assign statement, say foo.x = foo.x,
54 the IR (after SSA) looks like:
55
56 D.1797_14 = foo.x;
57 foo.x ={v} D.1797_14;
58
59 So if the rhs EXPR is an SSA_NAME of a temp variable,
60 e.g. D.1797_14, we need to grab the rhs of its SSA def
61 statement (i.e. foo.x). */
62 tree vdecl = SSA_NAME_VAR (expr);
70b5e7dc 63 if ((!vdecl || DECL_ARTIFICIAL (vdecl))
8ba50c2c
LCW
64 && !gimple_nop_p (SSA_NAME_DEF_STMT (expr)))
65 {
355fe088 66 gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
8ba50c2c
LCW
67 /* We are only interested in an assignment with a single
68 rhs operand because if it is not, the original assignment
69 will not possibly be a self-assignment. */
70f34814 70 if (gimple_assign_single_p (def_stmt))
8ba50c2c
LCW
71 return get_real_ref_rhs (gimple_assign_rhs1 (def_stmt));
72 else
73 return NULL_TREE;
74 }
75 else
76 return vdecl;
77 }
78 case VAR_DECL:
79 case PARM_DECL:
80 case FIELD_DECL:
81 case COMPONENT_REF:
70f34814 82 case MEM_REF:
8ba50c2c
LCW
83 case ARRAY_REF:
84 return expr;
85 default:
86 return NULL_TREE;
87 }
88}
89
90/* Given an expression tree, EXPR, that may contains SSA names, returns an
91 equivalent tree with the SSA names converted to var/parm/field decls
92 so that it can be used with '%E' format modifier when emitting warning
93 messages.
94
95 This function currently only supports VAR/PARM/FIELD_DECL, reference
96 expressions (COMPONENT_REF, INDIRECT_REF, ARRAY_REF), integer constant,
97 and SSA_NAME. If EXPR contains any other tree nodes (e.g. an arithmetic
98 expression appears in array index), NULL_TREE is returned. */
99
100static tree
101get_non_ssa_expr (tree expr)
102{
70b5e7dc
RG
103 if (!expr)
104 return NULL_TREE;
8ba50c2c
LCW
105 switch (TREE_CODE (expr))
106 {
107 case VAR_DECL:
108 case PARM_DECL:
109 case FIELD_DECL:
110 {
111 if (DECL_NAME (expr))
112 return expr;
113 else
114 return NULL_TREE;
115 }
116 case COMPONENT_REF:
117 {
118 tree base, orig_base = TREE_OPERAND (expr, 0);
119 tree component, orig_component = TREE_OPERAND (expr, 1);
120 base = get_non_ssa_expr (orig_base);
121 if (!base)
122 return NULL_TREE;
123 component = get_non_ssa_expr (orig_component);
124 if (!component)
125 return NULL_TREE;
126 /* If either BASE or COMPONENT is converted, build a new
127 component reference tree. */
128 if (base != orig_base || component != orig_component)
129 return build3 (COMPONENT_REF, TREE_TYPE (component),
130 base, component, NULL_TREE);
131 else
132 return expr;
133 }
70f34814 134 case MEM_REF:
8ba50c2c
LCW
135 {
136 tree orig_base = TREE_OPERAND (expr, 0);
70f34814
RG
137 if (TREE_CODE (orig_base) == SSA_NAME)
138 {
139 tree base = get_non_ssa_expr (orig_base);
140 if (!base)
141 return NULL_TREE;
142 return fold_build2 (MEM_REF, TREE_TYPE (expr),
143 base, TREE_OPERAND (expr, 1));
144 }
145 return expr;
8ba50c2c
LCW
146 }
147 case ARRAY_REF:
148 {
149 tree array, orig_array = TREE_OPERAND (expr, 0);
150 tree index, orig_index = TREE_OPERAND (expr, 1);
151 array = get_non_ssa_expr (orig_array);
152 if (!array)
153 return NULL_TREE;
154 index = get_non_ssa_expr (orig_index);
155 if (!index)
156 return NULL_TREE;
157 /* If either ARRAY or INDEX is converted, build a new array
158 reference tree. */
159 if (array != orig_array || index != orig_index)
160 return build4 (ARRAY_REF, TREE_TYPE (expr), array, index,
161 TREE_OPERAND (expr, 2), TREE_OPERAND (expr, 3));
162 else
163 return expr;
164 }
165 case SSA_NAME:
166 {
167 tree vdecl = SSA_NAME_VAR (expr);
70b5e7dc 168 if ((!vdecl || DECL_ARTIFICIAL (vdecl))
8ba50c2c
LCW
169 && !gimple_nop_p (SSA_NAME_DEF_STMT (expr)))
170 {
355fe088 171 gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
70f34814 172 if (gimple_assign_single_p (def_stmt))
8ba50c2c
LCW
173 vdecl = gimple_assign_rhs1 (def_stmt);
174 }
175 return get_non_ssa_expr (vdecl);
176 }
177 case INTEGER_CST:
178 return expr;
179 default:
180 /* Return NULL_TREE for any other kind of tree nodes. */
181 return NULL_TREE;
182 }
183}
184
185/* Given the LHS and (real) RHS of a gimple assign statement, STMT, check if
186 they are the same. If so, print a warning message about self-assignment. */
187
188static void
355fe088 189compare_and_warn (gimple *stmt, tree lhs, tree rhs)
8ba50c2c
LCW
190{
191 if (operand_equal_p (lhs, rhs, OEP_PURE_SAME))
192 {
193 location_t location;
194 location = (gimple_has_location (stmt)
195 ? gimple_location (stmt)
196 : (DECL_P (lhs)
197 ? DECL_SOURCE_LOCATION (lhs)
198 : input_location));
199 /* If LHS contains any tree node not currently supported by
200 get_non_ssa_expr, simply emit a generic warning without
201 specifying LHS in the message. */
202 lhs = get_non_ssa_expr (lhs);
203 if (lhs)
fab922b1 204 warning_at (location, 0, G_("%qE is assigned to itself"), lhs);
8ba50c2c 205 else
fab922b1 206 warning_at (location, 0, G_("self-assignment detected"));
8ba50c2c
LCW
207 }
208}
209
210/* Check and warn if STMT is a self-assign statement. */
211
212static void
355fe088 213warn_self_assign (gimple *stmt)
8ba50c2c
LCW
214{
215 tree rhs, lhs;
216
217 /* Check assigment statement. */
70f34814 218 if (gimple_assign_single_p (stmt))
8ba50c2c
LCW
219 {
220 rhs = get_real_ref_rhs (gimple_assign_rhs1 (stmt));
221 if (!rhs)
222 return;
223
224 lhs = gimple_assign_lhs (stmt);
225 if (TREE_CODE (lhs) == SSA_NAME)
226 {
227 lhs = SSA_NAME_VAR (lhs);
70b5e7dc 228 if (!lhs || DECL_ARTIFICIAL (lhs))
8ba50c2c
LCW
229 return;
230 }
231
232 compare_and_warn (stmt, lhs, rhs);
233 }
234 /* Check overloaded operator '=' (if enabled). */
235 else if (check_operator_eq && is_gimple_call (stmt))
236 {
237 tree fdecl = gimple_call_fndecl (stmt);
238 if (fdecl && (DECL_NAME (fdecl) == maybe_get_identifier ("operator=")))
239 {
240 /* If 'operator=' takes reference operands, the arguments will be
241 ADDR_EXPR trees. In this case, just remove the address-taken
242 operator before we compare the lhs and rhs. */
243 lhs = gimple_call_arg (stmt, 0);
244 if (TREE_CODE (lhs) == ADDR_EXPR)
245 lhs = TREE_OPERAND (lhs, 0);
246 rhs = gimple_call_arg (stmt, 1);
247 if (TREE_CODE (rhs) == ADDR_EXPR)
248 rhs = TREE_OPERAND (rhs, 0);
249
250 compare_and_warn (stmt, lhs, rhs);
251 }
252 }
253}
254
27a4cd48
DM
255namespace {
256
257const pass_data pass_data_warn_self_assign =
8ba50c2c 258{
27a4cd48
DM
259 GIMPLE_PASS, /* type */
260 "warn_self_assign", /* name */
261 OPTGROUP_NONE, /* optinfo_flags */
27a4cd48
DM
262 TV_NONE, /* tv_id */
263 PROP_ssa, /* properties_required */
264 0, /* properties_provided */
265 0, /* properties_destroyed */
266 0, /* todo_flags_start */
267 0, /* todo_flags_finish */
8ba50c2c
LCW
268};
269
27a4cd48
DM
270class pass_warn_self_assign : public gimple_opt_pass
271{
272public:
273 pass_warn_self_assign(gcc::context *ctxt)
274 : gimple_opt_pass(pass_data_warn_self_assign, ctxt)
275 {}
276
277 /* opt_pass methods: */
be55bfe6 278 virtual unsigned int execute (function *);
27a4cd48
DM
279
280}; // class pass_warn_self_assign
281
be55bfe6
TS
282unsigned int
283pass_warn_self_assign::execute (function *fun)
284{
285 gimple_stmt_iterator gsi;
286 basic_block bb;
287
288 FOR_EACH_BB_FN (bb, fun)
289 {
290 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
291 warn_self_assign (gsi_stmt (gsi));
292 }
293
294 return 0;
295}
296
27a4cd48
DM
297} // anon namespace
298
299static gimple_opt_pass *
300make_pass_warn_self_assign (gcc::context *ctxt)
301{
302 return new pass_warn_self_assign (ctxt);
303}
304
8ba50c2c
LCW
305/* The initialization routine exposed to and called by GCC. The spec of this
306 function is defined in gcc/gcc-plugin.h.
307
308 PLUGIN_NAME - name of the plugin (useful for error reporting)
309 ARGC - the size of the ARGV array
310 ARGV - an array of key-value argument pair
311
312 Returns 0 if initialization finishes successfully.
313
314 Note that this function needs to be named exactly "plugin_init". */
315
316int
9fefa0aa
TG
317plugin_init (struct plugin_name_args *plugin_info,
318 struct plugin_gcc_version *version)
8ba50c2c 319{
8fc7e474 320 struct register_pass_info pass_info;
9fefa0aa
TG
321 const char *plugin_name = plugin_info->base_name;
322 int argc = plugin_info->argc;
323 struct plugin_argument *argv = plugin_info->argv;
8ba50c2c
LCW
324 bool enabled = true;
325 int i;
326
e4d5031c 327 if (!plugin_default_version_check (version, &gcc_version))
8ba50c2c
LCW
328 return 1;
329
330 /* Self-assign detection should happen after SSA is constructed. */
f7695dbf 331 pass_info.pass = make_pass_warn_self_assign (g);
8ba50c2c
LCW
332 pass_info.reference_pass_name = "ssa";
333 pass_info.ref_pass_instance_number = 1;
334 pass_info.pos_op = PASS_POS_INSERT_AFTER;
335
336 /* Process the plugin arguments. This plugin takes the following arguments:
337 check-operator-eq, no-check-operator-eq, enable, and disable.
338 By default, the analysis is enabled with 'operator=' checked. */
339 for (i = 0; i < argc; ++i)
340 {
341 if (!strcmp (argv[i].key, "check-operator-eq"))
342 {
343 if (argv[i].value)
344 warning (0, G_("option '-fplugin-arg-%s-check-operator-eq=%s'"
345 " ignored (superfluous '=%s')"),
346 plugin_name, argv[i].value, argv[i].value);
347 else
348 check_operator_eq = true;
349 }
350 else if (!strcmp (argv[i].key, "no-check-operator-eq"))
351 {
352 if (argv[i].value)
353 warning (0, G_("option '-fplugin-arg-%s-no-check-operator-eq=%s'"
354 " ignored (superfluous '=%s')"),
355 plugin_name, argv[i].value, argv[i].value);
356 else
357 check_operator_eq = false;
358 }
359 else if (!strcmp (argv[i].key, "enable"))
360 {
361 if (argv[i].value)
362 warning (0, G_("option '-fplugin-arg-%s-enable=%s' ignored"
363 " (superfluous '=%s')"),
364 plugin_name, argv[i].value, argv[i].value);
365 else
366 enabled = true;
367 }
368 else if (!strcmp (argv[i].key, "disable"))
369 {
370 if (argv[i].value)
371 warning (0, G_("option '-fplugin-arg-%s-disable=%s' ignored"
372 " (superfluous '=%s')"),
373 plugin_name, argv[i].value, argv[i].value);
374 else
375 enabled = false;
376 }
377 else
378 warning (0, G_("plugin %qs: unrecognized argument %qs ignored"),
379 plugin_name, argv[i].key);
380 }
381
382 /* Register this new pass with GCC if the analysis is enabled. */
383 if (enabled)
384 register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL,
385 &pass_info);
386
387 return 0;
388}