]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/d-diagnostic.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / d / d-diagnostic.cc
1 /* d-diagnostics.cc -- D frontend interface to gcc diagnostics.
2 Copyright (C) 2017-2022 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 static char *
42 expand_d_format (const char *format)
43 {
44 obstack buf;
45 bool inbacktick = false;
46
47 gcc_obstack_init (&buf);
48
49 for (const char *p = format; *p;)
50 {
51 while (*p != '\0' && *p != '\\' && *p != '%' && *p != '`')
52 {
53 obstack_1grow (&buf, *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 obstack_1grow (&buf, '`');
66 p++;;
67 }
68 else
69 obstack_1grow (&buf, *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 obstack_grow (&buf, "%>", 2);
81 inbacktick = false;
82 }
83 else
84 {
85 obstack_grow (&buf, "%<", 2);
86 inbacktick = true;
87 }
88 p++;
89 continue;
90 }
91
92 /* Check the conversion specification for unhandled flags. */
93 obstack_1grow (&buf, *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 obstack_1grow (&buf, 'x');
119 p++;
120 break;
121
122 default:
123 break;
124 }
125 }
126
127 gcc_assert (!inbacktick);
128 obstack_1grow (&buf, '\0');
129 return (char *) obstack_finish (&buf);
130 }
131
132 /* Rewrite the format string FORMAT to deal with any characters that require
133 escaping before expand_d_format expands it. */
134
135 static char *
136 escape_d_format (const char *format)
137 {
138 bool quoted = false;
139 size_t format_len = 0;
140 obstack buf;
141
142 gcc_obstack_init (&buf);
143
144 /* If the format string is enclosed by two '`' characters, then don't escape
145 the first and last characters. */
146 if (*format == '`')
147 {
148 format_len = strlen (format) - 1;
149 if (format_len && format[format_len] == '`')
150 quoted = true;
151 }
152
153 for (const char *p = format; *p; p++)
154 {
155 switch (*p)
156 {
157 case '%':
158 /* Escape `%' characters so that pp_format does not confuse them
159 for actual format specifiers. */
160 obstack_1grow (&buf, '%');
161 break;
162
163 case '`':
164 /* Escape '`' characters so that expand_d_format does not confuse them
165 for a quoted string. */
166 if (!quoted || (p != format && p != (format + format_len)))
167 obstack_1grow (&buf, '\\');
168 break;
169
170 default:
171 break;
172 }
173
174 obstack_1grow (&buf, *p);
175 }
176
177 obstack_1grow (&buf, '\0');
178 return (char *) obstack_finish (&buf);
179 }
180
181 /* Helper routine for all error routines. Reports a diagnostic specified by
182 KIND at the explicit location LOC. The message FORMAT comes from the dmd
183 front-end, which does not get translated by the gcc diagnostic routines. */
184
185 static void ATTRIBUTE_GCC_DIAG(3,0)
186 d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
187 va_list ap, diagnostic_t kind, bool verbatim)
188 {
189 va_list argp;
190 va_copy (argp, ap);
191
192 if (loc.filename || !verbatim)
193 {
194 rich_location rich_loc (line_table, make_location_t (loc));
195 diagnostic_info diagnostic;
196 char *xformat = expand_d_format (format);
197
198 diagnostic_set_info_translated (&diagnostic, xformat, &argp,
199 &rich_loc, kind);
200 if (opt != 0)
201 diagnostic.option_index = opt;
202
203 diagnostic_report_diagnostic (global_dc, &diagnostic);
204 }
205 else
206 {
207 /* Write verbatim messages with no location direct to stream. */
208 text_info text;
209 text.err_no = errno;
210 text.args_ptr = &argp;
211 text.format_spec = expand_d_format (format);
212 text.x_data = NULL;
213
214 pp_format_verbatim (global_dc->printer, &text);
215 pp_newline_and_flush (global_dc->printer);
216 }
217
218 va_end (argp);
219 }
220
221 /* Print a hard error message with explicit location LOC with an optional
222 message prefix PREFIX1 and PREFIX2, increasing the global or gagged
223 error count. */
224
225 void ATTRIBUTE_GCC_DIAG(2,0)
226 verror (const Loc &loc, const char *format, va_list ap,
227 const char *prefix1, const char *prefix2, const char *)
228 {
229 if (!global.gag || global.params.showGaggedErrors)
230 {
231 char *xformat;
232
233 /* Build string and emit. */
234 if (prefix2 != NULL)
235 xformat = xasprintf ("%s %s %s", escape_d_format (prefix1),
236 escape_d_format (prefix2), format);
237 else if (prefix1 != NULL)
238 xformat = xasprintf ("%s %s", escape_d_format (prefix1), format);
239 else
240 xformat = xasprintf ("%s", format);
241
242 d_diagnostic_report_diagnostic (loc, 0, xformat, ap,
243 global.gag ? DK_ANACHRONISM : DK_ERROR,
244 false);
245 free (xformat);
246 }
247
248 if (global.gag)
249 global.gaggedErrors++;
250
251 global.errors++;
252 }
253
254 /* Print supplementary message about the last error with explicit location LOC.
255 This doesn't increase the global error count. */
256
257 void ATTRIBUTE_GCC_DIAG(2,0)
258 verrorSupplemental (const Loc &loc, const char *format, va_list ap)
259 {
260 if (global.gag && !global.params.showGaggedErrors)
261 return;
262
263 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
264 }
265
266 /* Print a warning message with explicit location LOC, increasing the
267 global warning count. */
268
269 void ATTRIBUTE_GCC_DIAG(2,0)
270 vwarning (const Loc &loc, const char *format, va_list ap)
271 {
272 if (!global.gag && global.params.warnings != DIAGNOSTICoff)
273 {
274 /* Warnings don't count if not treated as errors. */
275 if (global.params.warnings == DIAGNOSTICerror)
276 global.warnings++;
277
278 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false);
279 }
280 else if (global.gag)
281 global.gaggedWarnings++;
282 }
283
284 /* Print supplementary message about the last warning with explicit location
285 LOC. This doesn't increase the global warning count. */
286
287 void ATTRIBUTE_GCC_DIAG(2,0)
288 vwarningSupplemental (const Loc &loc, const char *format, va_list ap)
289 {
290 if (global.params.warnings == DIAGNOSTICoff || global.gag)
291 return;
292
293 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
294 }
295
296 /* Print a deprecation message with explicit location LOC with an optional
297 message prefix PREFIX1 and PREFIX2, increasing the global warning or
298 error count depending on how deprecations are treated. */
299
300 void ATTRIBUTE_GCC_DIAG(2,0)
301 vdeprecation (const Loc &loc, const char *format, va_list ap,
302 const char *prefix1, const char *prefix2)
303 {
304 if (global.params.useDeprecated == DIAGNOSTICerror)
305 verror (loc, format, ap, prefix1, prefix2);
306 else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
307 {
308 char *xformat;
309
310 /* Build string and emit. */
311 if (prefix2 != NULL)
312 xformat = xasprintf ("%s %s %s", escape_d_format (prefix1),
313 escape_d_format (prefix2), format);
314 else if (prefix1 != NULL)
315 xformat = xasprintf ("%s %s", escape_d_format (prefix1), format);
316 else
317 xformat = xasprintf ("%s", format);
318
319 d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap,
320 DK_WARNING, false);
321 free (xformat);
322 }
323 else if (global.gag)
324 global.gaggedWarnings++;
325 }
326
327 /* Print supplementary message about the last deprecation with explicit
328 location LOC. This does not increase the global error count. */
329
330 void ATTRIBUTE_GCC_DIAG(2,0)
331 vdeprecationSupplemental (const Loc &loc, const char *format, va_list ap)
332 {
333 if (global.params.useDeprecated == DIAGNOSTICerror)
334 verrorSupplemental (loc, format, ap);
335 else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
336 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
337 }
338
339 /* Print a verbose message with explicit location LOC. */
340
341 void ATTRIBUTE_GCC_DIAG(2,0)
342 vmessage (const Loc &loc, const char *format, va_list ap)
343 {
344 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true);
345 }
346
347 /* Print a tip message with prefix and highlighing. */
348
349 void ATTRIBUTE_GCC_DIAG(1,0)
350 vtip (const char *format, va_list ap)
351 {
352 if (!global.gag)
353 d_diagnostic_report_diagnostic (Loc (), 0, format, ap, DK_DEBUG, true);
354 }
355
356 /* Call this after printing out fatal error messages to clean up and
357 exit the compiler. */
358
359 void
360 fatal (void)
361 {
362 exit (FATAL_EXIT_CODE);
363 }