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