Home | History | Annotate | Line # | Download | only in d
d-diagnostic.cc revision 1.1
      1 /* d-diagnostics.cc -- D frontend interface to gcc diagnostics.
      2    Copyright (C) 2017-2019 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 != '`')
     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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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)
    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
    355 fatal (void)
    356 {
    357   exit (FATAL_EXIT_CODE);
    358 }
    359