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