]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/analyzer.cc
x86: Update STORE_MAX_PIECES
[thirdparty/gcc.git] / gcc / analyzer / analyzer.cc
CommitLineData
757bf1df 1/* Utility functions for the analyzer.
99dee823 2 Copyright (C) 2019-2021 Free Software Foundation, Inc.
757bf1df
DM
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#include "config.h"
22#include "system.h"
23#include "coretypes.h"
24#include "tree.h"
25#include "function.h"
26#include "basic-block.h"
27#include "gimple.h"
28#include "diagnostic.h"
29#include "intl.h"
30#include "function.h"
31#include "analyzer/analyzer.h"
32
33#if ENABLE_ANALYZER
34
808f4dfe
DM
35namespace ana {
36
37/* Workaround for missing location information for some stmts,
38 which ultimately should be solved by fixing the frontends
39 to provide the locations (TODO). */
40
41location_t
42get_stmt_location (const gimple *stmt, function *fun)
43{
44 if (get_pure_location (stmt->location) == UNKNOWN_LOCATION)
45 {
46 /* Workaround for missing location information for clobber
47 stmts, which seem to lack location information in the C frontend
48 at least. Created by gimplify_bind_expr, which uses the
49 BLOCK_SOURCE_END_LOCATION (BIND_EXPR_BLOCK (bind_expr))
50 but this is never set up when the block is created in
51 c_end_compound_stmt's pop_scope.
52 TODO: fix this missing location information.
53
54 For now, as a hackish workaround, use the location of the end of
55 the function. */
56 if (gimple_clobber_p (stmt) && fun)
57 return fun->function_end_locus;
58 }
59
60 return stmt->location;
61}
62
e4bb1bd6
DM
63static tree
64fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited);
65
33255ad3
DM
66/* Attemp to generate a tree for the LHS of ASSIGN_STMT.
67 VISITED must be non-NULL; it is used to ensure termination. */
68
69static tree
70get_diagnostic_tree_for_gassign_1 (const gassign *assign_stmt,
71 hash_set<tree> *visited)
72{
73 enum tree_code code = gimple_assign_rhs_code (assign_stmt);
74
75 /* Reverse the effect of extract_ops_from_tree during
76 gimplification. */
77 switch (get_gimple_rhs_class (code))
78 {
79 default:
80 case GIMPLE_INVALID_RHS:
81 gcc_unreachable ();
82 case GIMPLE_TERNARY_RHS:
83 case GIMPLE_BINARY_RHS:
84 case GIMPLE_UNARY_RHS:
85 {
86 tree t = make_node (code);
87 TREE_TYPE (t) = TREE_TYPE (gimple_assign_lhs (assign_stmt));
88 unsigned num_rhs_args = gimple_num_ops (assign_stmt) - 1;
89 for (unsigned i = 0; i < num_rhs_args; i++)
90 {
91 tree op = gimple_op (assign_stmt, i + 1);
92 if (op)
93 {
94 op = fixup_tree_for_diagnostic_1 (op, visited);
95 if (op == NULL_TREE)
96 return NULL_TREE;
97 }
98 TREE_OPERAND (t, i) = op;
99 }
100 return t;
101 }
102 case GIMPLE_SINGLE_RHS:
103 {
104 tree op = gimple_op (assign_stmt, 1);
105 op = fixup_tree_for_diagnostic_1 (op, visited);
106 return op;
107 }
108 }
109}
110
e4bb1bd6
DM
111/* Subroutine of fixup_tree_for_diagnostic_1, called on SSA names.
112 Attempt to reconstruct a a tree expression for SSA_NAME
113 based on its def-stmt.
114 SSA_NAME must be non-NULL.
115 VISITED must be non-NULL; it is used to ensure termination.
116
117 Return NULL_TREE if there is a problem. */
118
119static tree
120maybe_reconstruct_from_def_stmt (tree ssa_name,
121 hash_set<tree> *visited)
122{
123 /* Ensure termination. */
124 if (visited->contains (ssa_name))
125 return NULL_TREE;
126 visited->add (ssa_name);
127
128 gimple *def_stmt = SSA_NAME_DEF_STMT (ssa_name);
129
130 switch (gimple_code (def_stmt))
131 {
132 default:
133 gcc_unreachable ();
134 case GIMPLE_NOP:
135 case GIMPLE_PHI:
136 /* Can't handle these. */
137 return NULL_TREE;
138 case GIMPLE_ASSIGN:
33255ad3
DM
139 return get_diagnostic_tree_for_gassign_1
140 (as_a <const gassign *> (def_stmt), visited);
e4bb1bd6
DM
141 case GIMPLE_CALL:
142 {
143 gcall *call_stmt = as_a <gcall *> (def_stmt);
144 tree return_type = gimple_call_return_type (call_stmt);
145 tree fn = fixup_tree_for_diagnostic_1 (gimple_call_fn (call_stmt),
146 visited);
147 unsigned num_args = gimple_call_num_args (call_stmt);
148 auto_vec<tree> args (num_args);
149 for (unsigned i = 0; i < num_args; i++)
150 {
151 tree arg = gimple_call_arg (call_stmt, i);
152 arg = fixup_tree_for_diagnostic_1 (arg, visited);
153 if (arg == NULL_TREE)
154 return NULL_TREE;
155 args.quick_push (arg);
156 }
157 return build_call_array_loc (gimple_location (call_stmt),
158 return_type, fn,
7d8f4240 159 num_args, args.address ());
e4bb1bd6
DM
160 }
161 break;
162 }
163}
164
165/* Subroutine of fixup_tree_for_diagnostic: attempt to fixup EXPR,
166 which can be NULL.
167 VISITED must be non-NULL; it is used to ensure termination. */
168
169static tree
170fixup_tree_for_diagnostic_1 (tree expr, hash_set<tree> *visited)
171{
172 if (expr
173 && TREE_CODE (expr) == SSA_NAME
174 && (SSA_NAME_VAR (expr) == NULL_TREE
175 || DECL_ARTIFICIAL (SSA_NAME_VAR (expr))))
e9711fe4
DM
176 {
177 if (tree var = SSA_NAME_VAR (expr))
178 if (VAR_P (var) && DECL_HAS_DEBUG_EXPR_P (var))
179 return DECL_DEBUG_EXPR (var);
180 if (tree expr2 = maybe_reconstruct_from_def_stmt (expr, visited))
181 return expr2;
182 }
e4bb1bd6
DM
183 return expr;
184}
185
186/* We don't want to print '<unknown>' in our diagnostics (PR analyzer/99771),
187 but sometimes we generate diagnostics involving an ssa name for a
188 temporary.
189
190 Work around this by attempting to reconstruct a tree expression for
191 such temporaries based on their def-stmts.
192
193 Otherwise return EXPR.
194
195 EXPR can be NULL. */
196
197tree
198fixup_tree_for_diagnostic (tree expr)
199{
200 hash_set<tree> visited;
201 return fixup_tree_for_diagnostic_1 (expr, &visited);
202}
203
33255ad3
DM
204/* Attempt to generate a tree for the LHS of ASSIGN_STMT. */
205
206tree
207get_diagnostic_tree_for_gassign (const gassign *assign_stmt)
208{
209 hash_set<tree> visited;
210 return get_diagnostic_tree_for_gassign_1 (assign_stmt, &visited);
211}
212
808f4dfe
DM
213} // namespace ana
214
757bf1df
DM
215/* Helper function for checkers. Is the CALL to the given function name,
216 and with the given number of arguments?
217
218 This doesn't resolve function pointers via the region model;
219 is_named_call_p should be used instead, using a fndecl from
220 get_fndecl_for_call; this function should only be used for special cases
221 where it's not practical to get at the region model, or for special
222 analyzer functions such as __analyzer_dump. */
223
224bool
225is_special_named_call_p (const gcall *call, const char *funcname,
226 unsigned int num_args)
227{
228 gcc_assert (funcname);
229
230 tree fndecl = gimple_call_fndecl (call);
231 if (!fndecl)
232 return false;
233
234 return is_named_call_p (fndecl, funcname, call, num_args);
235}
236
342e14ff
DM
237/* Helper function for checkers. Is FNDECL an extern fndecl at file scope
238 that has the given FUNCNAME?
239
240 Compare with special_function_p in calls.c. */
757bf1df
DM
241
242bool
31534ac2 243is_named_call_p (const_tree fndecl, const char *funcname)
757bf1df
DM
244{
245 gcc_assert (fndecl);
246 gcc_assert (funcname);
247
182ce042 248 if (!maybe_special_function_p (fndecl))
342e14ff
DM
249 return false;
250
251 tree identifier = DECL_NAME (fndecl);
342e14ff
DM
252 const char *name = IDENTIFIER_POINTER (identifier);
253 const char *tname = name;
254
255 /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
256 FUNCNAME itself has leading underscores (e.g. when looking for
257 "__analyzer_eval"). */
258 if (funcname[0] != '_' && name[0] == '_')
259 {
260 if (name[1] == '_')
261 tname += 2;
262 else
263 tname += 1;
264 }
265
266 return 0 == strcmp (tname, funcname);
757bf1df
DM
267}
268
9f00b22f
DM
269/* Return true if FNDECL is within the namespace "std".
270 Compare with cp/typeck.c: decl_in_std_namespace_p, but this doesn't
271 rely on being the C++ FE (or handle inline namespaces inside of std). */
272
273static inline bool
274is_std_function_p (const_tree fndecl)
275{
276 tree name_decl = DECL_NAME (fndecl);
277 if (!name_decl)
278 return false;
279 if (!DECL_CONTEXT (fndecl))
280 return false;
281 if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
282 return false;
283 tree ns = DECL_CONTEXT (fndecl);
284 if (!(DECL_CONTEXT (ns) == NULL_TREE
285 || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
286 return false;
287 if (!DECL_NAME (ns))
288 return false;
289 return id_equal ("std", DECL_NAME (ns));
290}
291
292/* Like is_named_call_p, but look for std::FUNCNAME. */
293
294bool
31534ac2 295is_std_named_call_p (const_tree fndecl, const char *funcname)
9f00b22f
DM
296{
297 gcc_assert (fndecl);
298 gcc_assert (funcname);
299
300 if (!is_std_function_p (fndecl))
301 return false;
302
303 tree identifier = DECL_NAME (fndecl);
304 const char *name = IDENTIFIER_POINTER (identifier);
305 const char *tname = name;
306
307 /* Don't disregard prefix _ or __ in FNDECL's name. */
308
309 return 0 == strcmp (tname, funcname);
310}
311
342e14ff
DM
312/* Helper function for checkers. Is FNDECL an extern fndecl at file scope
313 that has the given FUNCNAME, and does CALL have the given number of
314 arguments? */
757bf1df
DM
315
316bool
31534ac2 317is_named_call_p (const_tree fndecl, const char *funcname,
757bf1df
DM
318 const gcall *call, unsigned int num_args)
319{
320 gcc_assert (fndecl);
321 gcc_assert (funcname);
322
323 if (!is_named_call_p (fndecl, funcname))
324 return false;
325
326 if (gimple_call_num_args (call) != num_args)
9f00b22f
DM
327 return false;
328
329 return true;
330}
331
332/* Like is_named_call_p, but check for std::FUNCNAME. */
333
334bool
31534ac2 335is_std_named_call_p (const_tree fndecl, const char *funcname,
9f00b22f
DM
336 const gcall *call, unsigned int num_args)
337{
338 gcc_assert (fndecl);
339 gcc_assert (funcname);
340
341 if (!is_std_named_call_p (fndecl, funcname))
342 return false;
343
344 if (gimple_call_num_args (call) != num_args)
757bf1df
DM
345 return false;
346
347 return true;
348}
349
342e14ff 350/* Return true if stmt is a setjmp or sigsetjmp call. */
757bf1df
DM
351
352bool
342e14ff 353is_setjmp_call_p (const gcall *call)
757bf1df 354{
342e14ff
DM
355 if (is_special_named_call_p (call, "setjmp", 1)
356 || is_special_named_call_p (call, "sigsetjmp", 2))
35e3f082
DM
357 /* region_model::on_setjmp requires a pointer. */
358 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
359 return true;
757bf1df
DM
360
361 return false;
362}
363
342e14ff 364/* Return true if stmt is a longjmp or siglongjmp call. */
757bf1df
DM
365
366bool
367is_longjmp_call_p (const gcall *call)
368{
342e14ff
DM
369 if (is_special_named_call_p (call, "longjmp", 2)
370 || is_special_named_call_p (call, "siglongjmp", 2))
01eabbea
DM
371 /* exploded_node::on_longjmp requires a pointer for the initial
372 argument. */
373 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
374 return true;
757bf1df
DM
375
376 return false;
377}
378
342e14ff
DM
379/* For a CALL that matched is_special_named_call_p or is_named_call_p for
380 some name, return a name for the called function suitable for use in
381 diagnostics (stripping the leading underscores). */
382
383const char *
384get_user_facing_name (const gcall *call)
385{
386 tree fndecl = gimple_call_fndecl (call);
387 gcc_assert (fndecl);
388
389 tree identifier = DECL_NAME (fndecl);
390 gcc_assert (identifier);
391
392 const char *name = IDENTIFIER_POINTER (identifier);
393
394 /* Strip prefix _ or __ in FNDECL's name. */
395 if (name[0] == '_')
396 {
397 if (name[1] == '_')
398 return name + 2;
399 else
400 return name + 1;
401 }
402
403 return name;
404}
405
757bf1df
DM
406/* Generate a label_text instance by formatting FMT, using a
407 temporary clone of the global_dc's printer (thus using its
408 formatting callbacks).
409
410 Colorize if the global_dc supports colorization and CAN_COLORIZE is
411 true. */
412
413label_text
414make_label_text (bool can_colorize, const char *fmt, ...)
415{
416 pretty_printer *pp = global_dc->printer->clone ();
417 pp_clear_output_area (pp);
418
419 if (!can_colorize)
420 pp_show_color (pp) = false;
421
422 text_info ti;
423 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
424
425 va_list ap;
426
427 va_start (ap, fmt);
428
429 ti.format_spec = _(fmt);
430 ti.args_ptr = &ap;
431 ti.err_no = 0;
432 ti.x_data = NULL;
433 ti.m_richloc = &rich_loc;
434
435 pp_format (pp, &ti);
436 pp_output_formatted_text (pp);
437
438 va_end (ap);
439
440 label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
441 delete pp;
442 return result;
443}
444
445#endif /* #if ENABLE_ANALYZER */