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