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 *
expand_d_format(const char * format)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 != '`')
52 	{
53 	  buf.writeByte (*p);
54 	  p++;
55 	}
56 
57       if (*p == '\0')
58 	break;
59 
60       if (*p == '`')
61 	{
62 	  /* Text enclosed by `...` are translated as a quoted string.  */
63 	  if (inbacktick)
64 	    {
65 	      buf.writestring ("%>");
66 	      inbacktick = false;
67 	    }
68 	  else
69 	    {
70 	      buf.writestring ("%<");
71 	      inbacktick = true;
72 	    }
73 	  p++;
74 	  continue;
75 	}
76 
77       /* Check the conversion specification for unhandled flags.  */
78       buf.writeByte (*p);
79       p++;
80 
81     Lagain:
82       switch (*p)
83 	{
84 	case '\0':
85 	  /* Malformed format string.  */
86 	  gcc_unreachable ();
87 
88 	case '-':
89 	  /* Remove whitespace formatting.  */
90 	  p++;
91 	  while (ISDIGIT (*p))
92 	    p++;
93 	  goto Lagain;
94 
95 	case '0':
96 	  /* Remove zero padding from format string.  */
97 	  while (ISDIGIT (*p))
98 	    p++;
99 	  goto Lagain;
100 
101 	case 'X':
102 	  /* Hex format only supports lower-case.  */
103 	  buf.writeByte ('x');
104 	  p++;
105 	  break;
106 
107 	default:
108 	  break;
109 	}
110     }
111 
112   gcc_assert (!inbacktick);
113   return buf.extractString ();
114 }
115 
116 /* Helper routine for all error routines.  Reports a diagnostic specified by
117    KIND at the explicit location LOC.  The message FORMAT comes from the dmd
118    front-end, which does not get translated by the gcc diagnostic routines.  */
119 
120 static void ATTRIBUTE_GCC_DIAG(3,0)
d_diagnostic_report_diagnostic(const Loc & loc,int opt,const char * format,va_list ap,diagnostic_t kind,bool verbatim)121 d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format,
122 				va_list ap, diagnostic_t kind, bool verbatim)
123 {
124   va_list argp;
125   va_copy (argp, ap);
126 
127   if (loc.filename || !verbatim)
128     {
129       rich_location rich_loc (line_table, make_location_t (loc));
130       diagnostic_info diagnostic;
131       char *xformat = expand_d_format (format);
132 
133       diagnostic_set_info_translated (&diagnostic, xformat, &argp,
134 				      &rich_loc, kind);
135       if (opt != 0)
136 	diagnostic.option_index = opt;
137 
138       diagnostic_report_diagnostic (global_dc, &diagnostic);
139       free (xformat);
140     }
141   else
142     {
143       /* Write verbatim messages with no location direct to stream.  */
144       text_info text;
145       text.err_no = errno;
146       text.args_ptr = &argp;
147       text.format_spec = expand_d_format (format);
148       text.x_data = NULL;
149 
150       pp_format_verbatim (global_dc->printer, &text);
151       pp_newline_and_flush (global_dc->printer);
152     }
153 
154   va_end (argp);
155 }
156 
157 /* Print a hard error message with explicit location LOC with an optional
158    message prefix PREFIX1 and PREFIX2, increasing the global or gagged
159    error count.  */
160 
161 void ATTRIBUTE_GCC_DIAG(2,3)
error(const Loc & loc,const char * format,...)162 error (const Loc& loc, const char *format, ...)
163 {
164   va_list ap;
165   va_start (ap, format);
166   verror (loc, format, ap);
167   va_end (ap);
168 }
169 
170 void ATTRIBUTE_GCC_DIAG(2,0)
verror(const Loc & loc,const char * format,va_list ap,const char * prefix1,const char * prefix2,const char *)171 verror (const Loc& loc, const char *format, va_list ap,
172 	const char *prefix1, const char *prefix2, const char *)
173 {
174   if (!global.gag || global.params.showGaggedErrors)
175     {
176       char *xformat;
177 
178       /* Build string and emit.  */
179       if (prefix2 != NULL)
180 	xformat = xasprintf ("%s %s %s", prefix1, prefix2, format);
181       else if (prefix1 != NULL)
182 	xformat = xasprintf ("%s %s", prefix1, format);
183       else
184 	xformat = xasprintf ("%s", format);
185 
186       d_diagnostic_report_diagnostic (loc, 0, xformat, ap,
187 				      global.gag ? DK_ANACHRONISM : DK_ERROR,
188 				      false);
189       free (xformat);
190     }
191 
192   if (global.gag)
193     global.gaggedErrors++;
194 
195   global.errors++;
196 }
197 
198 /* Print supplementary message about the last error with explicit location LOC.
199    This doesn't increase the global error count.  */
200 
201 void ATTRIBUTE_GCC_DIAG(2,3)
errorSupplemental(const Loc & loc,const char * format,...)202 errorSupplemental (const Loc& loc, const char *format, ...)
203 {
204   va_list ap;
205   va_start (ap, format);
206   verrorSupplemental (loc, format, ap);
207   va_end (ap);
208 }
209 
210 void ATTRIBUTE_GCC_DIAG(2,0)
verrorSupplemental(const Loc & loc,const char * format,va_list ap)211 verrorSupplemental (const Loc& loc, const char *format, va_list ap)
212 {
213   if (global.gag && !global.params.showGaggedErrors)
214     return;
215 
216   d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
217 }
218 
219 /* Print a warning message with explicit location LOC, increasing the
220    global warning count.  */
221 
222 void ATTRIBUTE_GCC_DIAG(2,3)
warning(const Loc & loc,const char * format,...)223 warning (const Loc& loc, const char *format, ...)
224 {
225   va_list ap;
226   va_start (ap, format);
227   vwarning (loc, format, ap);
228   va_end (ap);
229 }
230 
231 void ATTRIBUTE_GCC_DIAG(2,0)
vwarning(const Loc & loc,const char * format,va_list ap)232 vwarning (const Loc& loc, const char *format, va_list ap)
233 {
234   if (!global.gag && global.params.warnings != DIAGNOSTICoff)
235     {
236       /* Warnings don't count if not treated as errors.  */
237       if (global.params.warnings == DIAGNOSTICerror)
238 	global.warnings++;
239 
240       d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false);
241     }
242 }
243 
244 /* Print supplementary message about the last warning with explicit location
245    LOC.  This doesn't increase the global warning count.  */
246 
247 void ATTRIBUTE_GCC_DIAG(2,3)
warningSupplemental(const Loc & loc,const char * format,...)248 warningSupplemental (const Loc& loc, const char *format, ...)
249 {
250   va_list ap;
251   va_start (ap, format);
252   vwarningSupplemental (loc, format, ap);
253   va_end (ap);
254 }
255 
256 void ATTRIBUTE_GCC_DIAG(2,0)
vwarningSupplemental(const Loc & loc,const char * format,va_list ap)257 vwarningSupplemental (const Loc& loc, const char *format, va_list ap)
258 {
259   if (global.params.warnings == DIAGNOSTICoff || global.gag)
260     return;
261 
262   d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
263 }
264 
265 /* Print a deprecation message with explicit location LOC with an optional
266    message prefix PREFIX1 and PREFIX2, increasing the global warning or
267    error count depending on how deprecations are treated.  */
268 
269 void ATTRIBUTE_GCC_DIAG(2,3)
deprecation(const Loc & loc,const char * format,...)270 deprecation (const Loc& loc, const char *format, ...)
271 {
272   va_list ap;
273   va_start (ap, format);
274   vdeprecation (loc, format, ap);
275   va_end (ap);
276 }
277 
278 void ATTRIBUTE_GCC_DIAG(2,0)
vdeprecation(const Loc & loc,const char * format,va_list ap,const char * prefix1,const char * prefix2)279 vdeprecation (const Loc& loc, const char *format, va_list ap,
280 	      const char *prefix1, const char *prefix2)
281 {
282   if (global.params.useDeprecated == DIAGNOSTICerror)
283     verror (loc, format, ap, prefix1, prefix2);
284   else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
285     {
286       char *xformat;
287 
288       /* Build string and emit.  */
289       if (prefix2 != NULL)
290 	xformat = xasprintf ("%s %s %s", prefix1, prefix2, format);
291       else if (prefix1 != NULL)
292 	xformat = xasprintf ("%s %s", prefix1, format);
293       else
294 	xformat = xasprintf ("%s", format);
295 
296       d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap,
297 				      DK_WARNING, false);
298       free (xformat);
299     }
300 }
301 
302 /* Print supplementary message about the last deprecation with explicit
303    location LOC.  This does not increase the global error count.  */
304 
305 void ATTRIBUTE_GCC_DIAG(2,3)
deprecationSupplemental(const Loc & loc,const char * format,...)306 deprecationSupplemental (const Loc& loc, const char *format, ...)
307 {
308   va_list ap;
309   va_start (ap, format);
310   vdeprecationSupplemental (loc, format, ap);
311   va_end (ap);
312 }
313 
314 void ATTRIBUTE_GCC_DIAG(2,0)
vdeprecationSupplemental(const Loc & loc,const char * format,va_list ap)315 vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap)
316 {
317   if (global.params.useDeprecated == DIAGNOSTICerror)
318     verrorSupplemental (loc, format, ap);
319   else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
320     d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
321 }
322 
323 /* Print a verbose message with explicit location LOC.  */
324 
325 void ATTRIBUTE_GCC_DIAG(2, 3)
message(const Loc & loc,const char * format,...)326 message (const Loc& loc, const char *format, ...)
327 {
328   va_list ap;
329   va_start (ap, format);
330   vmessage (loc, format, ap);
331   va_end (ap);
332 }
333 
334 void ATTRIBUTE_GCC_DIAG(2,0)
vmessage(const Loc & loc,const char * format,va_list ap)335 vmessage (const Loc& loc, const char *format, va_list ap)
336 {
337   d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true);
338 }
339 
340 /* Same as above, but doesn't take a location argument.  */
341 
342 void ATTRIBUTE_GCC_DIAG(1, 2)
message(const char * format,...)343 message (const char *format, ...)
344 {
345   va_list ap;
346   va_start (ap, format);
347   vmessage (Loc (), format, ap);
348   va_end (ap);
349 }
350 
351 /* Call this after printing out fatal error messages to clean up and
352    exit the compiler.  */
353 
354 void
fatal(void)355 fatal (void)
356 {
357   exit (FATAL_EXIT_CODE);
358 }
359