d-diagnostic.cc revision 1.1.1.2 1 1.1 mrg /* d-diagnostics.cc -- D frontend interface to gcc diagnostics.
2 1.1.1.2 mrg Copyright (C) 2017-2020 Free Software Foundation, Inc.
3 1.1 mrg
4 1.1 mrg GCC is free software; you can redistribute it and/or modify
5 1.1 mrg it under the terms of the GNU General Public License as published by
6 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
7 1.1 mrg any later version.
8 1.1 mrg
9 1.1 mrg GCC is distributed in the hope that it will be useful,
10 1.1 mrg but WITHOUT ANY WARRANTY; without even the implied warranty of
11 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 1.1 mrg GNU General Public License for more details.
13 1.1 mrg
14 1.1 mrg You should have received a copy of the GNU General Public License
15 1.1 mrg along with GCC; see the file COPYING3. If not see
16 1.1 mrg <http://www.gnu.org/licenses/>. */
17 1.1 mrg
18 1.1 mrg #include "config.h"
19 1.1 mrg #include "system.h"
20 1.1 mrg #include "coretypes.h"
21 1.1 mrg
22 1.1 mrg #include "dmd/globals.h"
23 1.1 mrg #include "dmd/errors.h"
24 1.1 mrg
25 1.1 mrg #include "tree.h"
26 1.1 mrg #include "options.h"
27 1.1 mrg #include "diagnostic.h"
28 1.1 mrg
29 1.1 mrg #include "d-tree.h"
30 1.1 mrg
31 1.1 mrg
32 1.1 mrg /* Rewrite the format string FORMAT to deal with any format extensions not
33 1.1 mrg supported by pp_format().
34 1.1 mrg
35 1.1 mrg The following format specifiers are handled:
36 1.1 mrg `...`: text within backticks gets quoted as '%<...%>'.
37 1.1 mrg %-10s: left-justify format flag is removed leaving '%s' remaining.
38 1.1 mrg %02x: zero-padding format flag is removed leaving '%x' remaining.
39 1.1 mrg %X: uppercase unsigned hexadecimals are rewritten as '%x'.
40 1.1 mrg
41 1.1 mrg The result should be freed by the caller. */
42 1.1 mrg
43 1.1 mrg static char *
44 1.1 mrg expand_d_format (const char *format)
45 1.1 mrg {
46 1.1 mrg OutBuffer buf;
47 1.1 mrg bool inbacktick = false;
48 1.1 mrg
49 1.1 mrg for (const char *p = format; *p;)
50 1.1 mrg {
51 1.1.1.2 mrg while (*p != '\0' && *p != '\\' && *p != '%' && *p != '`')
52 1.1 mrg {
53 1.1 mrg buf.writeByte (*p);
54 1.1 mrg p++;
55 1.1 mrg }
56 1.1 mrg
57 1.1 mrg if (*p == '\0')
58 1.1 mrg break;
59 1.1 mrg
60 1.1.1.2 mrg if (*p == '\\')
61 1.1.1.2 mrg {
62 1.1.1.2 mrg if (p[1] == '`')
63 1.1.1.2 mrg {
64 1.1.1.2 mrg /* Escaped backtick, don't expand it as a quoted string. */
65 1.1.1.2 mrg buf.writeByte ('`');
66 1.1.1.2 mrg p++;;
67 1.1.1.2 mrg }
68 1.1.1.2 mrg else
69 1.1.1.2 mrg buf.writeByte (*p);
70 1.1.1.2 mrg
71 1.1.1.2 mrg p++;
72 1.1.1.2 mrg continue;
73 1.1.1.2 mrg }
74 1.1.1.2 mrg
75 1.1 mrg if (*p == '`')
76 1.1 mrg {
77 1.1 mrg /* Text enclosed by `...` are translated as a quoted string. */
78 1.1 mrg if (inbacktick)
79 1.1 mrg {
80 1.1 mrg buf.writestring ("%>");
81 1.1 mrg inbacktick = false;
82 1.1 mrg }
83 1.1 mrg else
84 1.1 mrg {
85 1.1 mrg buf.writestring ("%<");
86 1.1 mrg inbacktick = true;
87 1.1 mrg }
88 1.1 mrg p++;
89 1.1 mrg continue;
90 1.1 mrg }
91 1.1 mrg
92 1.1 mrg /* Check the conversion specification for unhandled flags. */
93 1.1 mrg buf.writeByte (*p);
94 1.1 mrg p++;
95 1.1 mrg
96 1.1 mrg Lagain:
97 1.1 mrg switch (*p)
98 1.1 mrg {
99 1.1 mrg case '\0':
100 1.1 mrg /* Malformed format string. */
101 1.1 mrg gcc_unreachable ();
102 1.1 mrg
103 1.1 mrg case '-':
104 1.1 mrg /* Remove whitespace formatting. */
105 1.1 mrg p++;
106 1.1 mrg while (ISDIGIT (*p))
107 1.1 mrg p++;
108 1.1 mrg goto Lagain;
109 1.1 mrg
110 1.1 mrg case '0':
111 1.1 mrg /* Remove zero padding from format string. */
112 1.1 mrg while (ISDIGIT (*p))
113 1.1 mrg p++;
114 1.1 mrg goto Lagain;
115 1.1 mrg
116 1.1 mrg case 'X':
117 1.1 mrg /* Hex format only supports lower-case. */
118 1.1 mrg buf.writeByte ('x');
119 1.1 mrg p++;
120 1.1 mrg break;
121 1.1 mrg
122 1.1 mrg default:
123 1.1 mrg break;
124 1.1 mrg }
125 1.1 mrg }
126 1.1 mrg
127 1.1 mrg gcc_assert (!inbacktick);
128 1.1 mrg return buf.extractString ();
129 1.1 mrg }
130 1.1 mrg
131 1.1.1.2 mrg /* Rewrite the format string FORMAT to deal with any characters that require
132 1.1.1.2 mrg escaping before expand_d_format expands it. */
133 1.1.1.2 mrg
134 1.1.1.2 mrg static char *
135 1.1.1.2 mrg escape_d_format (const char *format)
136 1.1.1.2 mrg {
137 1.1.1.2 mrg obstack buf;
138 1.1.1.2 mrg
139 1.1.1.2 mrg gcc_obstack_init (&buf);
140 1.1.1.2 mrg
141 1.1.1.2 mrg for (const char *p = format; *p; p++)
142 1.1.1.2 mrg {
143 1.1.1.2 mrg switch (*p)
144 1.1.1.2 mrg {
145 1.1.1.2 mrg case '%':
146 1.1.1.2 mrg /* Escape `%' characters so that pp_format does not confuse them
147 1.1.1.2 mrg for actual format specifiers. */
148 1.1.1.2 mrg obstack_1grow (&buf, '%');
149 1.1.1.2 mrg break;
150 1.1.1.2 mrg
151 1.1.1.2 mrg case '`':
152 1.1.1.2 mrg /* Escape '`' characters so that expand_d_format does not confuse them
153 1.1.1.2 mrg for a quoted string. */
154 1.1.1.2 mrg obstack_1grow (&buf, '\\');
155 1.1.1.2 mrg break;
156 1.1.1.2 mrg
157 1.1.1.2 mrg default:
158 1.1.1.2 mrg break;
159 1.1.1.2 mrg }
160 1.1.1.2 mrg
161 1.1.1.2 mrg obstack_1grow (&buf, *p);
162 1.1.1.2 mrg }
163 1.1.1.2 mrg
164 1.1.1.2 mrg obstack_1grow (&buf, '\0');
165 1.1.1.2 mrg return (char *) obstack_finish (&buf);
166 1.1.1.2 mrg }
167 1.1.1.2 mrg
168 1.1 mrg /* Helper routine for all error routines. Reports a diagnostic specified by
169 1.1 mrg KIND at the explicit location LOC. The message FORMAT comes from the dmd
170 1.1 mrg front-end, which does not get translated by the gcc diagnostic routines. */
171 1.1 mrg
172 1.1 mrg static void ATTRIBUTE_GCC_DIAG(3,0)
173 1.1 mrg d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format,
174 1.1 mrg va_list ap, diagnostic_t kind, bool verbatim)
175 1.1 mrg {
176 1.1 mrg va_list argp;
177 1.1 mrg va_copy (argp, ap);
178 1.1 mrg
179 1.1 mrg if (loc.filename || !verbatim)
180 1.1 mrg {
181 1.1 mrg rich_location rich_loc (line_table, make_location_t (loc));
182 1.1 mrg diagnostic_info diagnostic;
183 1.1 mrg char *xformat = expand_d_format (format);
184 1.1 mrg
185 1.1 mrg diagnostic_set_info_translated (&diagnostic, xformat, &argp,
186 1.1 mrg &rich_loc, kind);
187 1.1 mrg if (opt != 0)
188 1.1 mrg diagnostic.option_index = opt;
189 1.1 mrg
190 1.1 mrg diagnostic_report_diagnostic (global_dc, &diagnostic);
191 1.1 mrg free (xformat);
192 1.1 mrg }
193 1.1 mrg else
194 1.1 mrg {
195 1.1 mrg /* Write verbatim messages with no location direct to stream. */
196 1.1 mrg text_info text;
197 1.1 mrg text.err_no = errno;
198 1.1 mrg text.args_ptr = &argp;
199 1.1 mrg text.format_spec = expand_d_format (format);
200 1.1 mrg text.x_data = NULL;
201 1.1 mrg
202 1.1 mrg pp_format_verbatim (global_dc->printer, &text);
203 1.1 mrg pp_newline_and_flush (global_dc->printer);
204 1.1 mrg }
205 1.1 mrg
206 1.1 mrg va_end (argp);
207 1.1 mrg }
208 1.1 mrg
209 1.1 mrg /* Print a hard error message with explicit location LOC with an optional
210 1.1 mrg message prefix PREFIX1 and PREFIX2, increasing the global or gagged
211 1.1 mrg error count. */
212 1.1 mrg
213 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,3)
214 1.1 mrg error (const Loc& loc, const char *format, ...)
215 1.1 mrg {
216 1.1 mrg va_list ap;
217 1.1 mrg va_start (ap, format);
218 1.1 mrg verror (loc, format, ap);
219 1.1 mrg va_end (ap);
220 1.1 mrg }
221 1.1 mrg
222 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,0)
223 1.1 mrg verror (const Loc& loc, const char *format, va_list ap,
224 1.1 mrg const char *prefix1, const char *prefix2, const char *)
225 1.1 mrg {
226 1.1 mrg if (!global.gag || global.params.showGaggedErrors)
227 1.1 mrg {
228 1.1 mrg char *xformat;
229 1.1 mrg
230 1.1 mrg /* Build string and emit. */
231 1.1 mrg if (prefix2 != NULL)
232 1.1.1.2 mrg xformat = xasprintf ("%s %s %s", escape_d_format (prefix1),
233 1.1.1.2 mrg escape_d_format (prefix2), format);
234 1.1 mrg else if (prefix1 != NULL)
235 1.1.1.2 mrg xformat = xasprintf ("%s %s", escape_d_format (prefix1), format);
236 1.1 mrg else
237 1.1 mrg xformat = xasprintf ("%s", format);
238 1.1 mrg
239 1.1 mrg d_diagnostic_report_diagnostic (loc, 0, xformat, ap,
240 1.1 mrg global.gag ? DK_ANACHRONISM : DK_ERROR,
241 1.1 mrg false);
242 1.1 mrg free (xformat);
243 1.1 mrg }
244 1.1 mrg
245 1.1 mrg if (global.gag)
246 1.1 mrg global.gaggedErrors++;
247 1.1 mrg
248 1.1 mrg global.errors++;
249 1.1 mrg }
250 1.1 mrg
251 1.1 mrg /* Print supplementary message about the last error with explicit location LOC.
252 1.1 mrg This doesn't increase the global error count. */
253 1.1 mrg
254 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,3)
255 1.1 mrg errorSupplemental (const Loc& loc, const char *format, ...)
256 1.1 mrg {
257 1.1 mrg va_list ap;
258 1.1 mrg va_start (ap, format);
259 1.1 mrg verrorSupplemental (loc, format, ap);
260 1.1 mrg va_end (ap);
261 1.1 mrg }
262 1.1 mrg
263 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,0)
264 1.1 mrg verrorSupplemental (const Loc& loc, const char *format, va_list ap)
265 1.1 mrg {
266 1.1 mrg if (global.gag && !global.params.showGaggedErrors)
267 1.1 mrg return;
268 1.1 mrg
269 1.1 mrg d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
270 1.1 mrg }
271 1.1 mrg
272 1.1 mrg /* Print a warning message with explicit location LOC, increasing the
273 1.1 mrg global warning count. */
274 1.1 mrg
275 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,3)
276 1.1 mrg warning (const Loc& loc, const char *format, ...)
277 1.1 mrg {
278 1.1 mrg va_list ap;
279 1.1 mrg va_start (ap, format);
280 1.1 mrg vwarning (loc, format, ap);
281 1.1 mrg va_end (ap);
282 1.1 mrg }
283 1.1 mrg
284 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,0)
285 1.1 mrg vwarning (const Loc& loc, const char *format, va_list ap)
286 1.1 mrg {
287 1.1 mrg if (!global.gag && global.params.warnings != DIAGNOSTICoff)
288 1.1 mrg {
289 1.1 mrg /* Warnings don't count if not treated as errors. */
290 1.1 mrg if (global.params.warnings == DIAGNOSTICerror)
291 1.1 mrg global.warnings++;
292 1.1 mrg
293 1.1 mrg d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false);
294 1.1 mrg }
295 1.1 mrg }
296 1.1 mrg
297 1.1 mrg /* Print supplementary message about the last warning with explicit location
298 1.1 mrg LOC. This doesn't increase the global warning count. */
299 1.1 mrg
300 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,3)
301 1.1 mrg warningSupplemental (const Loc& loc, const char *format, ...)
302 1.1 mrg {
303 1.1 mrg va_list ap;
304 1.1 mrg va_start (ap, format);
305 1.1 mrg vwarningSupplemental (loc, format, ap);
306 1.1 mrg va_end (ap);
307 1.1 mrg }
308 1.1 mrg
309 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,0)
310 1.1 mrg vwarningSupplemental (const Loc& loc, const char *format, va_list ap)
311 1.1 mrg {
312 1.1 mrg if (global.params.warnings == DIAGNOSTICoff || global.gag)
313 1.1 mrg return;
314 1.1 mrg
315 1.1 mrg d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
316 1.1 mrg }
317 1.1 mrg
318 1.1 mrg /* Print a deprecation message with explicit location LOC with an optional
319 1.1 mrg message prefix PREFIX1 and PREFIX2, increasing the global warning or
320 1.1 mrg error count depending on how deprecations are treated. */
321 1.1 mrg
322 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,3)
323 1.1 mrg deprecation (const Loc& loc, const char *format, ...)
324 1.1 mrg {
325 1.1 mrg va_list ap;
326 1.1 mrg va_start (ap, format);
327 1.1 mrg vdeprecation (loc, format, ap);
328 1.1 mrg va_end (ap);
329 1.1 mrg }
330 1.1 mrg
331 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,0)
332 1.1 mrg vdeprecation (const Loc& loc, const char *format, va_list ap,
333 1.1 mrg const char *prefix1, const char *prefix2)
334 1.1 mrg {
335 1.1 mrg if (global.params.useDeprecated == DIAGNOSTICerror)
336 1.1 mrg verror (loc, format, ap, prefix1, prefix2);
337 1.1 mrg else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
338 1.1 mrg {
339 1.1 mrg char *xformat;
340 1.1 mrg
341 1.1 mrg /* Build string and emit. */
342 1.1 mrg if (prefix2 != NULL)
343 1.1.1.2 mrg xformat = xasprintf ("%s %s %s", escape_d_format (prefix1),
344 1.1.1.2 mrg escape_d_format (prefix2), format);
345 1.1 mrg else if (prefix1 != NULL)
346 1.1.1.2 mrg xformat = xasprintf ("%s %s", escape_d_format (prefix1), format);
347 1.1 mrg else
348 1.1 mrg xformat = xasprintf ("%s", format);
349 1.1 mrg
350 1.1 mrg d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap,
351 1.1 mrg DK_WARNING, false);
352 1.1 mrg free (xformat);
353 1.1 mrg }
354 1.1 mrg }
355 1.1 mrg
356 1.1 mrg /* Print supplementary message about the last deprecation with explicit
357 1.1 mrg location LOC. This does not increase the global error count. */
358 1.1 mrg
359 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,3)
360 1.1 mrg deprecationSupplemental (const Loc& loc, const char *format, ...)
361 1.1 mrg {
362 1.1 mrg va_list ap;
363 1.1 mrg va_start (ap, format);
364 1.1 mrg vdeprecationSupplemental (loc, format, ap);
365 1.1 mrg va_end (ap);
366 1.1 mrg }
367 1.1 mrg
368 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,0)
369 1.1 mrg vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap)
370 1.1 mrg {
371 1.1 mrg if (global.params.useDeprecated == DIAGNOSTICerror)
372 1.1 mrg verrorSupplemental (loc, format, ap);
373 1.1 mrg else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
374 1.1 mrg d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
375 1.1 mrg }
376 1.1 mrg
377 1.1 mrg /* Print a verbose message with explicit location LOC. */
378 1.1 mrg
379 1.1 mrg void ATTRIBUTE_GCC_DIAG(2, 3)
380 1.1 mrg message (const Loc& loc, const char *format, ...)
381 1.1 mrg {
382 1.1 mrg va_list ap;
383 1.1 mrg va_start (ap, format);
384 1.1 mrg vmessage (loc, format, ap);
385 1.1 mrg va_end (ap);
386 1.1 mrg }
387 1.1 mrg
388 1.1 mrg void ATTRIBUTE_GCC_DIAG(2,0)
389 1.1 mrg vmessage (const Loc& loc, const char *format, va_list ap)
390 1.1 mrg {
391 1.1 mrg d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true);
392 1.1 mrg }
393 1.1 mrg
394 1.1 mrg /* Same as above, but doesn't take a location argument. */
395 1.1 mrg
396 1.1 mrg void ATTRIBUTE_GCC_DIAG(1, 2)
397 1.1 mrg message (const char *format, ...)
398 1.1 mrg {
399 1.1 mrg va_list ap;
400 1.1 mrg va_start (ap, format);
401 1.1 mrg vmessage (Loc (), format, ap);
402 1.1 mrg va_end (ap);
403 1.1 mrg }
404 1.1 mrg
405 1.1 mrg /* Call this after printing out fatal error messages to clean up and
406 1.1 mrg exit the compiler. */
407 1.1 mrg
408 1.1 mrg void
409 1.1 mrg fatal (void)
410 1.1 mrg {
411 1.1 mrg exit (FATAL_EXIT_CODE);
412 1.1 mrg }
413