Branch data Line data Source code
1 : : /* Language-independent diagnostic subroutines for the GNU Compiler
2 : : Collection that are only for use in the compilers proper and not
3 : : the driver or other programs.
4 : : Copyright (C) 1999-2024 Free Software Foundation, Inc.
5 : :
6 : : This file is part of GCC.
7 : :
8 : : GCC is free software; you can redistribute it and/or modify it under
9 : : the terms of the GNU General Public License as published by the Free
10 : : Software Foundation; either version 3, or (at your option) any later
11 : : version.
12 : :
13 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 : : for more details.
17 : :
18 : : You should have received a copy of the GNU General Public License
19 : : along with GCC; see the file COPYING3. If not see
20 : : <http://www.gnu.org/licenses/>. */
21 : :
22 : : #include "config.h"
23 : : #include "system.h"
24 : : #include "coretypes.h"
25 : : #include "tree.h"
26 : : #include "diagnostic.h"
27 : : #include "tree-pretty-print.h"
28 : : #include "gimple-pretty-print.h"
29 : : #include "tree-diagnostic.h"
30 : : #include "diagnostic-client-data-hooks.h"
31 : : #include "langhooks.h"
32 : : #include "intl.h"
33 : :
34 : : /* Prints out, if necessary, the name of the current function
35 : : that caused an error. Called from all error and warning functions. */
36 : : void
37 : 95166 : diagnostic_report_current_function (diagnostic_context *context,
38 : : const diagnostic_info *diagnostic)
39 : : {
40 : 95166 : location_t loc = diagnostic_location (diagnostic);
41 : 95166 : diagnostic_report_current_module (context, loc);
42 : 95166 : lang_hooks.print_error_function (context, LOCATION_FILE (loc), diagnostic);
43 : 95166 : }
44 : :
45 : : static void
46 : 95166 : default_tree_diagnostic_starter (diagnostic_context *context,
47 : : const diagnostic_info *diagnostic)
48 : : {
49 : 95166 : diagnostic_report_current_function (context, diagnostic);
50 : 95166 : pp_set_prefix (context->printer, diagnostic_build_prefix (context,
51 : : diagnostic));
52 : 95166 : }
53 : :
54 : : /* This is a pair made of a location and the line map it originated
55 : : from. It's used in the maybe_unwind_expanded_macro_loc function
56 : : below. */
57 : : struct loc_map_pair
58 : : {
59 : : const line_map_macro *map;
60 : : location_t where;
61 : : };
62 : :
63 : :
64 : : /* Unwind the different macro expansions that lead to the token which
65 : : location is WHERE and emit diagnostics showing the resulting
66 : : unwound macro expansion trace. Let's look at an example to see how
67 : : the trace looks like. Suppose we have this piece of code,
68 : : artificially annotated with the line numbers to increase
69 : : legibility:
70 : :
71 : : $ cat -n test.c
72 : : 1 #define OPERATE(OPRD1, OPRT, OPRD2) \
73 : : 2 OPRD1 OPRT OPRD2;
74 : : 3
75 : : 4 #define SHIFTL(A,B) \
76 : : 5 OPERATE (A,<<,B)
77 : : 6
78 : : 7 #define MULT(A) \
79 : : 8 SHIFTL (A,1)
80 : : 9
81 : : 10 void
82 : : 11 g ()
83 : : 12 {
84 : : 13 MULT (1.0);// 1.0 << 1; <-- so this is an error.
85 : : 14 }
86 : :
87 : : Here is the diagnostic that we want the compiler to generate:
88 : :
89 : : test.c: In function ‘g’:
90 : : test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
91 : : test.c:2:9: note: in definition of macro 'OPERATE'
92 : : test.c:8:3: note: in expansion of macro 'SHIFTL'
93 : : test.c:13:3: note: in expansion of macro 'MULT'
94 : :
95 : : The part that goes from the third to the fifth line of this
96 : : diagnostic (the lines containing the 'note:' string) is called the
97 : : unwound macro expansion trace. That's the part generated by this
98 : : function. */
99 : :
100 : : void
101 : 292368 : maybe_unwind_expanded_macro_loc (diagnostic_context *context,
102 : : location_t where)
103 : : {
104 : 292368 : const struct line_map *map;
105 : 292368 : auto_vec<loc_map_pair> loc_vec;
106 : 292368 : unsigned ix;
107 : 292368 : loc_map_pair loc, *iter;
108 : :
109 : 292368 : const location_t original_loc = where;
110 : :
111 : 292368 : map = linemap_lookup (line_table, where);
112 : 292368 : if (!linemap_macro_expansion_map_p (map))
113 : 287029 : return;
114 : :
115 : : /* Let's unwind the macros that got expanded and led to the token
116 : : which location is WHERE. We are going to store these macros into
117 : : LOC_VEC, so that we can later walk it at our convenience to
118 : : display a somewhat meaningful trace of the macro expansion
119 : : history to the user. Note that the first macro of the trace
120 : : (which is OPERATE in the example above) is going to be stored at
121 : : the beginning of LOC_VEC. */
122 : :
123 : 8472 : do
124 : : {
125 : 8472 : loc.where = where;
126 : 8472 : loc.map = linemap_check_macro (map);
127 : :
128 : 8472 : loc_vec.safe_push (loc);
129 : :
130 : : /* WHERE is the location of a token inside the expansion of a
131 : : macro. MAP is the map holding the locations of that macro
132 : : expansion. Let's get the location of the token inside the
133 : : context that triggered the expansion of this macro.
134 : : This is basically how we go "down" in the trace of macro
135 : : expansions that led to WHERE. */
136 : 8472 : where = linemap_unwind_toward_expansion (line_table, where, &map);
137 : 8472 : } while (linemap_macro_expansion_map_p (map));
138 : :
139 : : /* Now map is set to the map of the location in the source that
140 : : first triggered the macro expansion. This must be an ordinary map. */
141 : 5339 : const line_map_ordinary *ord_map = linemap_check_ordinary (map);
142 : :
143 : : /* Walk LOC_VEC and print the macro expansion trace, unless the
144 : : first macro which expansion triggered this trace was expanded
145 : : inside a system header. */
146 : 5339 : int saved_location_line =
147 : 5339 : expand_location_to_spelling_point (original_loc).line;
148 : :
149 : 5339 : if (!LINEMAP_SYSP (ord_map))
150 : 12642 : FOR_EACH_VEC_ELT (loc_vec, ix, iter)
151 : : {
152 : : /* Sometimes, in the unwound macro expansion trace, we want to
153 : : print a part of the context that shows where, in the
154 : : definition of the relevant macro, is the token (we are
155 : : looking at) used. That is the case in the introductory
156 : : comment of this function, where we print:
157 : :
158 : : test.c:2:9: note: in definition of macro 'OPERATE'.
159 : :
160 : : We print that "macro definition context" because the
161 : : diagnostic line (emitted by the call to
162 : : pp_ouput_formatted_text in diagnostic_report_diagnostic):
163 : :
164 : : test.c:5:14: error: invalid operands to binary << (have ‘double’ and ‘int’)
165 : :
166 : : does not point into the definition of the macro where the
167 : : token '<<' (that is an argument to the function-like macro
168 : : OPERATE) is used. So we must "display" the line of that
169 : : macro definition context to the user somehow.
170 : :
171 : : A contrario, when the first interesting diagnostic line
172 : : points into the definition of the macro, we don't need to
173 : : display any line for that macro definition in the trace
174 : : anymore, otherwise it'd be redundant. */
175 : :
176 : : /* Okay, now here is what we want. For each token resulting
177 : : from macro expansion we want to show: 1/ where in the
178 : : definition of the macro the token comes from; 2/ where the
179 : : macro got expanded. */
180 : :
181 : : /* Resolve the location iter->where into the locus 1/ of the
182 : : comment above. */
183 : 4241 : location_t resolved_def_loc =
184 : 4241 : linemap_resolve_location (line_table, iter->where,
185 : : LRK_MACRO_DEFINITION_LOCATION, NULL);
186 : :
187 : : /* Don't print trace for locations that are reserved or from
188 : : within a system header. */
189 : 4241 : const line_map_ordinary *m = NULL;
190 : 4241 : location_t l =
191 : 4241 : linemap_resolve_location (line_table, resolved_def_loc,
192 : : LRK_SPELLING_LOCATION, &m);
193 : 4241 : location_t l0 = l;
194 : 4241 : if (IS_ADHOC_LOC (l0))
195 : 122 : l0 = get_location_from_adhoc_loc (line_table, l0);
196 : 4241 : if (l0 < RESERVED_LOCATION_COUNT || LINEMAP_SYSP (m))
197 : 2373 : continue;
198 : :
199 : : /* We need to print the context of the macro definition only
200 : : when the locus of the first displayed diagnostic (displayed
201 : : before this trace) was inside the definition of the
202 : : macro. */
203 : 3134 : const int resolved_def_loc_line = SOURCE_LINE (m, l0);
204 : 3134 : if (ix == 0 && saved_location_line != resolved_def_loc_line)
205 : : {
206 : 1266 : diagnostic_append_note (context, resolved_def_loc,
207 : : "in definition of macro %qs",
208 : : linemap_map_get_macro_name (iter->map));
209 : : /* At this step, as we've printed the context of the macro
210 : : definition, we don't want to print the context of its
211 : : expansion, otherwise, it'd be redundant. */
212 : 1266 : continue;
213 : : }
214 : :
215 : : /* Resolve the location of the expansion point of the macro
216 : : which expansion gave the token represented by def_loc.
217 : : This is the locus 2/ of the earlier comment. */
218 : 1868 : location_t resolved_exp_loc =
219 : 1868 : linemap_resolve_location (line_table,
220 : 1868 : iter->map->get_expansion_point_location (),
221 : : LRK_MACRO_DEFINITION_LOCATION, NULL);
222 : :
223 : 1868 : diagnostic_append_note (context, resolved_exp_loc,
224 : : "in expansion of macro %qs",
225 : : linemap_map_get_macro_name (iter->map));
226 : : }
227 : 292368 : }
228 : :
229 : : /* This is a diagnostic finalizer implementation that is aware of
230 : : virtual locations produced by libcpp.
231 : :
232 : : It has to be called by the diagnostic finalizer of front ends that
233 : : uses libcpp and wish to get diagnostics involving tokens resulting
234 : : from macro expansion.
235 : :
236 : : For a given location, if said location belongs to a token
237 : : resulting from a macro expansion, this starter prints the context
238 : : of the token. E.g, for multiply nested macro expansion, it
239 : : unwinds the nested macro expansions and prints them in a manner
240 : : that is similar to what is done for function call stacks, or
241 : : template instantiation contexts. */
242 : : void
243 : 292316 : virt_loc_aware_diagnostic_finalizer (diagnostic_context *context,
244 : : const diagnostic_info *diagnostic)
245 : : {
246 : 292316 : maybe_unwind_expanded_macro_loc (context, diagnostic_location (diagnostic));
247 : 292316 : }
248 : :
249 : : /* Default tree printer. Handles declarations only. */
250 : : bool
251 : 42282 : default_tree_printer (pretty_printer *pp, text_info *text, const char *spec,
252 : : int precision, bool wide, bool set_locus, bool hash,
253 : : bool *, const char **)
254 : : {
255 : 42282 : tree t;
256 : :
257 : : /* FUTURE: %+x should set the locus. */
258 : 42282 : if (precision != 0 || wide || hash)
259 : : return false;
260 : :
261 : 42282 : switch (*spec)
262 : : {
263 : 37456 : case 'E':
264 : 37456 : t = va_arg (*text->m_args_ptr, tree);
265 : 37456 : if (TREE_CODE (t) == IDENTIFIER_NODE)
266 : : {
267 : 130 : pp_identifier (pp, IDENTIFIER_POINTER (t));
268 : 130 : return true;
269 : : }
270 : : break;
271 : :
272 : 4634 : case 'D':
273 : 4634 : t = va_arg (*text->m_args_ptr, tree);
274 : 4634 : if (VAR_P (t) && DECL_HAS_DEBUG_EXPR_P (t))
275 : 24 : t = DECL_DEBUG_EXPR (t);
276 : : break;
277 : :
278 : 192 : case 'F':
279 : 192 : case 'T':
280 : 192 : t = va_arg (*text->m_args_ptr, tree);
281 : 192 : break;
282 : :
283 : : default:
284 : : return false;
285 : : }
286 : :
287 : 42152 : if (set_locus)
288 : 19 : text->set_location (0, DECL_SOURCE_LOCATION (t), SHOW_RANGE_WITH_CARET);
289 : :
290 : 42152 : if (DECL_P (t))
291 : : {
292 : 21032 : const char *n = DECL_NAME (t)
293 : 21032 : ? identifier_to_locale (lang_hooks.decl_printable_name (t, 2))
294 : 322 : : _("<anonymous>");
295 : 21032 : pp_string (pp, n);
296 : : }
297 : : else
298 : 21120 : dump_generic_node (pp, t, 0, TDF_SLIM, 0);
299 : :
300 : : return true;
301 : : }
302 : :
303 : : /* Set the locations of call sites along the inlining stack corresponding
304 : : to the DIAGNOSTIC location. */
305 : :
306 : : static void
307 : 87159677 : set_inlining_locations (diagnostic_context *,
308 : : diagnostic_info *diagnostic)
309 : : {
310 : 87159677 : location_t loc = diagnostic_location (diagnostic);
311 : 87159677 : tree block = LOCATION_BLOCK (loc);
312 : :
313 : : /* Count the number of locations in system headers. When all are,
314 : : warnings are suppressed by -Wno-system-headers. Otherwise, they
315 : : involve some user code, possibly inlined into a function in a system
316 : : header, and are not treated as coming from system headers. */
317 : : unsigned nsyslocs = 0;
318 : :
319 : : /* Use a reference to the vector of locations for convenience. */
320 : : auto &ilocs = diagnostic->m_iinfo.m_ilocs;
321 : :
322 : 785558 : while (block && TREE_CODE (block) == BLOCK
323 : 88298963 : && BLOCK_ABSTRACT_ORIGIN (block))
324 : : {
325 : 366905 : tree ao = BLOCK_ABSTRACT_ORIGIN (block);
326 : 366905 : if (TREE_CODE (ao) == FUNCTION_DECL)
327 : : {
328 : 124956 : if (!diagnostic->m_iinfo.m_ao)
329 : 78474 : diagnostic->m_iinfo.m_ao = block;
330 : :
331 : 124956 : location_t bsloc = BLOCK_SOURCE_LOCATION (block);
332 : 124956 : ilocs.safe_push (bsloc);
333 : 124956 : if (in_system_header_at (bsloc))
334 : 60279 : ++nsyslocs;
335 : : }
336 : 241949 : else if (TREE_CODE (ao) != BLOCK)
337 : : break;
338 : :
339 : 366905 : block = BLOCK_SUPERCONTEXT (block);
340 : : }
341 : :
342 : 87159677 : if (ilocs.length ())
343 : : {
344 : : /* When there is an inlining context use the macro expansion
345 : : location for the original location and bump up NSYSLOCS if
346 : : it's in a system header since it's not counted above. */
347 : 78474 : location_t sysloc = expansion_point_location_if_in_system_header (loc);
348 : 78474 : if (sysloc != loc)
349 : : {
350 : 0 : loc = sysloc;
351 : 0 : ++nsyslocs;
352 : : }
353 : : }
354 : : else
355 : : {
356 : : /* When there's no inlining context use the original location
357 : : and set NSYSLOCS accordingly. */
358 : 87081203 : nsyslocs = in_system_header_at (loc) != 0;
359 : : }
360 : :
361 : 87159677 : ilocs.safe_push (loc);
362 : :
363 : : /* Set if all locations are in a system header. */
364 : 87159677 : diagnostic->m_iinfo.m_allsyslocs = nsyslocs == ilocs.length ();
365 : :
366 : 87159677 : if (tree *ao = pp_ti_abstract_origin (&diagnostic->message))
367 : 87141145 : *ao = (tree)diagnostic->m_iinfo.m_ao;
368 : 87159677 : }
369 : :
370 : : /* Sets CONTEXT to use language independent diagnostics. */
371 : : void
372 : 333843 : tree_diagnostics_defaults (diagnostic_context *context)
373 : : {
374 : 333843 : diagnostic_starter (context) = default_tree_diagnostic_starter;
375 : 333843 : diagnostic_finalizer (context) = default_diagnostic_finalizer;
376 : 333843 : diagnostic_format_decoder (context) = default_tree_printer;
377 : 333843 : context->m_print_path = default_tree_diagnostic_path_printer;
378 : 333843 : context->m_make_json_for_path = default_tree_make_json_for_path;
379 : 333843 : context->set_set_locations_callback (set_inlining_locations);
380 : 333843 : context->set_client_data_hooks (make_compiler_data_hooks ());
381 : 333843 : }
|