]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/analyzer.cc
Make USES_COMDAT_LOCAL CIF_FINAL_NORMAL
[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
63} // namespace ana
64
757bf1df
DM
65/* Helper function for checkers. Is the CALL to the given function name,
66 and with the given number of arguments?
67
68 This doesn't resolve function pointers via the region model;
69 is_named_call_p should be used instead, using a fndecl from
70 get_fndecl_for_call; this function should only be used for special cases
71 where it's not practical to get at the region model, or for special
72 analyzer functions such as __analyzer_dump. */
73
74bool
75is_special_named_call_p (const gcall *call, const char *funcname,
76 unsigned int num_args)
77{
78 gcc_assert (funcname);
79
80 tree fndecl = gimple_call_fndecl (call);
81 if (!fndecl)
82 return false;
83
84 return is_named_call_p (fndecl, funcname, call, num_args);
85}
86
342e14ff
DM
87/* Helper function for checkers. Is FNDECL an extern fndecl at file scope
88 that has the given FUNCNAME?
89
90 Compare with special_function_p in calls.c. */
757bf1df
DM
91
92bool
93is_named_call_p (tree fndecl, const char *funcname)
94{
95 gcc_assert (fndecl);
96 gcc_assert (funcname);
97
182ce042 98 if (!maybe_special_function_p (fndecl))
342e14ff
DM
99 return false;
100
101 tree identifier = DECL_NAME (fndecl);
342e14ff
DM
102 const char *name = IDENTIFIER_POINTER (identifier);
103 const char *tname = name;
104
105 /* Potentially disregard prefix _ or __ in FNDECL's name, but not if
106 FUNCNAME itself has leading underscores (e.g. when looking for
107 "__analyzer_eval"). */
108 if (funcname[0] != '_' && name[0] == '_')
109 {
110 if (name[1] == '_')
111 tname += 2;
112 else
113 tname += 1;
114 }
115
116 return 0 == strcmp (tname, funcname);
757bf1df
DM
117}
118
9f00b22f
DM
119/* Return true if FNDECL is within the namespace "std".
120 Compare with cp/typeck.c: decl_in_std_namespace_p, but this doesn't
121 rely on being the C++ FE (or handle inline namespaces inside of std). */
122
123static inline bool
124is_std_function_p (const_tree fndecl)
125{
126 tree name_decl = DECL_NAME (fndecl);
127 if (!name_decl)
128 return false;
129 if (!DECL_CONTEXT (fndecl))
130 return false;
131 if (TREE_CODE (DECL_CONTEXT (fndecl)) != NAMESPACE_DECL)
132 return false;
133 tree ns = DECL_CONTEXT (fndecl);
134 if (!(DECL_CONTEXT (ns) == NULL_TREE
135 || TREE_CODE (DECL_CONTEXT (ns)) == TRANSLATION_UNIT_DECL))
136 return false;
137 if (!DECL_NAME (ns))
138 return false;
139 return id_equal ("std", DECL_NAME (ns));
140}
141
142/* Like is_named_call_p, but look for std::FUNCNAME. */
143
144bool
145is_std_named_call_p (tree fndecl, const char *funcname)
146{
147 gcc_assert (fndecl);
148 gcc_assert (funcname);
149
150 if (!is_std_function_p (fndecl))
151 return false;
152
153 tree identifier = DECL_NAME (fndecl);
154 const char *name = IDENTIFIER_POINTER (identifier);
155 const char *tname = name;
156
157 /* Don't disregard prefix _ or __ in FNDECL's name. */
158
159 return 0 == strcmp (tname, funcname);
160}
161
342e14ff
DM
162/* Helper function for checkers. Is FNDECL an extern fndecl at file scope
163 that has the given FUNCNAME, and does CALL have the given number of
164 arguments? */
757bf1df
DM
165
166bool
167is_named_call_p (tree fndecl, const char *funcname,
168 const gcall *call, unsigned int num_args)
169{
170 gcc_assert (fndecl);
171 gcc_assert (funcname);
172
173 if (!is_named_call_p (fndecl, funcname))
174 return false;
175
176 if (gimple_call_num_args (call) != num_args)
9f00b22f
DM
177 return false;
178
179 return true;
180}
181
182/* Like is_named_call_p, but check for std::FUNCNAME. */
183
184bool
185is_std_named_call_p (tree fndecl, const char *funcname,
186 const gcall *call, unsigned int num_args)
187{
188 gcc_assert (fndecl);
189 gcc_assert (funcname);
190
191 if (!is_std_named_call_p (fndecl, funcname))
192 return false;
193
194 if (gimple_call_num_args (call) != num_args)
757bf1df
DM
195 return false;
196
197 return true;
198}
199
342e14ff 200/* Return true if stmt is a setjmp or sigsetjmp call. */
757bf1df
DM
201
202bool
342e14ff 203is_setjmp_call_p (const gcall *call)
757bf1df 204{
342e14ff
DM
205 if (is_special_named_call_p (call, "setjmp", 1)
206 || is_special_named_call_p (call, "sigsetjmp", 2))
35e3f082
DM
207 /* region_model::on_setjmp requires a pointer. */
208 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
209 return true;
757bf1df
DM
210
211 return false;
212}
213
342e14ff 214/* Return true if stmt is a longjmp or siglongjmp call. */
757bf1df
DM
215
216bool
217is_longjmp_call_p (const gcall *call)
218{
342e14ff
DM
219 if (is_special_named_call_p (call, "longjmp", 2)
220 || is_special_named_call_p (call, "siglongjmp", 2))
01eabbea
DM
221 /* exploded_node::on_longjmp requires a pointer for the initial
222 argument. */
223 if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
224 return true;
757bf1df
DM
225
226 return false;
227}
228
342e14ff
DM
229/* For a CALL that matched is_special_named_call_p or is_named_call_p for
230 some name, return a name for the called function suitable for use in
231 diagnostics (stripping the leading underscores). */
232
233const char *
234get_user_facing_name (const gcall *call)
235{
236 tree fndecl = gimple_call_fndecl (call);
237 gcc_assert (fndecl);
238
239 tree identifier = DECL_NAME (fndecl);
240 gcc_assert (identifier);
241
242 const char *name = IDENTIFIER_POINTER (identifier);
243
244 /* Strip prefix _ or __ in FNDECL's name. */
245 if (name[0] == '_')
246 {
247 if (name[1] == '_')
248 return name + 2;
249 else
250 return name + 1;
251 }
252
253 return name;
254}
255
757bf1df
DM
256/* Generate a label_text instance by formatting FMT, using a
257 temporary clone of the global_dc's printer (thus using its
258 formatting callbacks).
259
260 Colorize if the global_dc supports colorization and CAN_COLORIZE is
261 true. */
262
263label_text
264make_label_text (bool can_colorize, const char *fmt, ...)
265{
266 pretty_printer *pp = global_dc->printer->clone ();
267 pp_clear_output_area (pp);
268
269 if (!can_colorize)
270 pp_show_color (pp) = false;
271
272 text_info ti;
273 rich_location rich_loc (line_table, UNKNOWN_LOCATION);
274
275 va_list ap;
276
277 va_start (ap, fmt);
278
279 ti.format_spec = _(fmt);
280 ti.args_ptr = &ap;
281 ti.err_no = 0;
282 ti.x_data = NULL;
283 ti.m_richloc = &rich_loc;
284
285 pp_format (pp, &ti);
286 pp_output_formatted_text (pp);
287
288 va_end (ap);
289
290 label_text result = label_text::take (xstrdup (pp_formatted_text (pp)));
291 delete pp;
292 return result;
293}
294
295#endif /* #if ENABLE_ANALYZER */