Home | History | Annotate | Line # | Download | only in d
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