]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/d/d-diagnostic.cc
Update copyright years.
[thirdparty/gcc.git] / gcc / d / d-diagnostic.cc
index 95a008d1b6f525fb4b21a8fca0b62a1496137887..b2accf911d424e5347aca46f1fa5259ffbe61975 100644 (file)
@@ -1,5 +1,5 @@
 /* d-diagnostics.cc -- D frontend interface to gcc diagnostics.
-   Copyright (C) 2017-2019 Free Software Foundation, Inc.
+   Copyright (C) 2017-2024 Free Software Foundation, Inc.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -36,38 +36,53 @@ along with GCC; see the file COPYING3.  If not see
    `...`: text within backticks gets quoted as '%<...%>'.
    %-10s: left-justify format flag is removed leaving '%s' remaining.
    %02x: zero-padding format flag is removed leaving '%x' remaining.
-   %X: uppercase unsigned hexadecimals are rewritten as '%x'.
-
-   The result should be freed by the caller.  */
+   %X: uppercase unsigned hexadecimals are rewritten as '%x'.  */
 
 static char *
 expand_d_format (const char *format)
 {
-  OutBuffer buf;
+  obstack buf;
   bool inbacktick = false;
 
+  gcc_obstack_init (&buf);
+
   for (const char *p = format; *p;)
     {
-      while (*p != '\0' && *p != '%' && *p != '`')
+      while (*p != '\0' && *p != '\\' && *p != '%' && *p != '`')
        {
-         buf.writeByte (*p);
+         obstack_1grow (&buf, *p);
          p++;
        }
 
       if (*p == '\0')
        break;
 
+      if (*p == '\\')
+       {
+         if (p[1] == '`')
+           {
+             /* Escaped backtick, don't expand it as a quoted string.  */
+             obstack_1grow (&buf, '`');
+             p++;;
+           }
+         else
+           obstack_1grow (&buf, *p);
+
+         p++;
+         continue;
+       }
+
       if (*p == '`')
        {
          /* Text enclosed by `...` are translated as a quoted string.  */
          if (inbacktick)
            {
-             buf.writestring ("%>");
+             obstack_grow (&buf, "%>", 2);
              inbacktick = false;
            }
          else
            {
-             buf.writestring ("%<");
+             obstack_grow (&buf, "%<", 2);
              inbacktick = true;
            }
          p++;
@@ -75,7 +90,7 @@ expand_d_format (const char *format)
        }
 
       /* Check the conversion specification for unhandled flags.  */
-      buf.writeByte (*p);
+      obstack_1grow (&buf, *p);
       p++;
 
     Lagain:
@@ -100,7 +115,7 @@ expand_d_format (const char *format)
 
        case 'X':
          /* Hex format only supports lower-case.  */
-         buf.writeByte ('x');
+         obstack_1grow (&buf, 'x');
          p++;
          break;
 
@@ -110,7 +125,57 @@ expand_d_format (const char *format)
     }
 
   gcc_assert (!inbacktick);
-  return buf.extractString ();
+  obstack_1grow (&buf, '\0');
+  return (char *) obstack_finish (&buf);
+}
+
+/* Rewrite the format string FORMAT to deal with any characters that require
+   escaping before expand_d_format expands it.  */
+
+static char *
+escape_d_format (const char *format)
+{
+  bool quoted = false;
+  size_t format_len = 0;
+  obstack buf;
+
+  gcc_obstack_init (&buf);
+
+  /* If the format string is enclosed by two '`' characters, then don't escape
+     the first and last characters.  */
+  if (*format == '`')
+    {
+      format_len = strlen (format) - 1;
+      if (format_len && format[format_len] == '`')
+       quoted = true;
+    }
+
+  for (const char *p = format; *p; p++)
+    {
+      switch (*p)
+       {
+       case '%':
+         /* Escape `%' characters so that pp_format does not confuse them
+            for actual format specifiers.  */
+         obstack_1grow (&buf, '%');
+         break;
+
+       case '`':
+         /* Escape '`' characters so that expand_d_format does not confuse them
+            for a quoted string.  */
+         if (!quoted || (p != format && p != (format + format_len)))
+           obstack_1grow (&buf, '\\');
+         break;
+
+       default:
+         break;
+       }
+
+      obstack_1grow (&buf, *p);
+    }
+
+  obstack_1grow (&buf, '\0');
+  return (char *) obstack_finish (&buf);
 }
 
 /* Helper routine for all error routines.  Reports a diagnostic specified by
@@ -118,13 +183,13 @@ expand_d_format (const char *format)
    front-end, which does not get translated by the gcc diagnostic routines.  */
 
 static void ATTRIBUTE_GCC_DIAG(3,0)
-d_diagnostic_report_diagnostic (const Locloc, int opt, const char *format,
+d_diagnostic_report_diagnostic (const Loc &loc, int opt, const char *format,
                                va_list ap, diagnostic_t kind, bool verbatim)
 {
   va_list argp;
   va_copy (argp, ap);
 
-  if (loc.filename || !verbatim)
+  if (loc.filename () || !verbatim)
     {
       rich_location rich_loc (line_table, make_location_t (loc));
       diagnostic_info diagnostic;
@@ -136,16 +201,11 @@ d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format,
        diagnostic.option_index = opt;
 
       diagnostic_report_diagnostic (global_dc, &diagnostic);
-      free (xformat);
     }
   else
     {
       /* Write verbatim messages with no location direct to stream.  */
-      text_info text;
-      text.err_no = errno;
-      text.args_ptr = &argp;
-      text.format_spec = expand_d_format (format);
-      text.x_data = NULL;
+      text_info text (expand_d_format (format), &argp, errno, nullptr);
 
       pp_format_verbatim (global_dc->printer, &text);
       pp_newline_and_flush (global_dc->printer);
@@ -154,198 +214,119 @@ d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format,
   va_end (argp);
 }
 
-/* Print a hard error message with explicit location LOC with an optional
-   message prefix PREFIX1 and PREFIX2, increasing the global or gagged
-   error count.  */
+/* Print a diagnostic message of type KIND with explicit location LOC with an
+   optional message prefix PREFIX1 and PREFIX2, increasing the global or gagged
+   error count depending on how KIND is treated.  */
 
-void ATTRIBUTE_GCC_DIAG(2,3)
-error (const Loc& loc, const char *format, ...)
+void D_ATTRIBUTE_FORMAT(2,0) ATTRIBUTE_GCC_DIAG(2,0)
+verrorReport (const Loc& loc, const char *format, va_list ap, ErrorKind kind,
+             const char *prefix1, const char *prefix2)
 {
-  va_list ap;
-  va_start (ap, format);
-  verror (loc, format, ap);
-  va_end (ap);
-}
+  diagnostic_t diag_kind = DK_UNSPECIFIED;
+  int opt = 0;
+  bool verbatim = false;
+  char *xformat;
 
-void ATTRIBUTE_GCC_DIAG(2,0)
-verror (const Loc& loc, const char *format, va_list ap,
-       const char *prefix1, const char *prefix2, const char *)
-{
-  if (!global.gag || global.params.showGaggedErrors)
+  if (kind == ErrorKind::error)
     {
-      char *xformat;
-
-      /* Build string and emit.  */
-      if (prefix2 != NULL)
-       xformat = xasprintf ("%s %s %s", prefix1, prefix2, format);
-      else if (prefix1 != NULL)
-       xformat = xasprintf ("%s %s", prefix1, format);
-      else
-       xformat = xasprintf ("%s", format);
-
-      d_diagnostic_report_diagnostic (loc, 0, xformat, ap,
-                                     global.gag ? DK_ANACHRONISM : DK_ERROR,
-                                     false);
-      free (xformat);
-    }
+      global.errors++;
+      if (global.gag)
+       global.gaggedErrors++;
 
-  if (global.gag)
-    global.gaggedErrors++;
+      if (global.gag && !global.params.v.showGaggedErrors)
+       return;
 
-  global.errors++;
-}
-
-/* Print supplementary message about the last error with explicit location LOC.
-   This doesn't increase the global error count.  */
-
-void ATTRIBUTE_GCC_DIAG(2,3)
-errorSupplemental (const Loc& loc, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  verrorSupplemental (loc, format, ap);
-  va_end (ap);
-}
-
-void ATTRIBUTE_GCC_DIAG(2,0)
-verrorSupplemental (const Loc& loc, const char *format, va_list ap)
-{
-  if (global.gag && !global.params.showGaggedErrors)
-    return;
-
-  d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
-}
-
-/* Print a warning message with explicit location LOC, increasing the
-   global warning count.  */
+      diag_kind = global.gag ? DK_ANACHRONISM : DK_ERROR;
+    }
+  else if (kind == ErrorKind::warning)
+    {
+      if (global.gag || global.params.warnings == DIAGNOSTICoff)
+       {
+         if (global.gag)
+           global.gaggedWarnings++;
 
-void ATTRIBUTE_GCC_DIAG(2,3)
-warning (const Loc& loc, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  vwarning (loc, format, ap);
-  va_end (ap);
-}
+         return;
+       }
 
-void ATTRIBUTE_GCC_DIAG(2,0)
-vwarning (const Loc& loc, const char *format, va_list ap)
-{
-  if (!global.gag && global.params.warnings != DIAGNOSTICoff)
-    {
       /* Warnings don't count if not treated as errors.  */
       if (global.params.warnings == DIAGNOSTICerror)
        global.warnings++;
 
-      d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false);
+      diag_kind = DK_WARNING;
     }
-}
-
-/* Print supplementary message about the last warning with explicit location
-   LOC.  This doesn't increase the global warning count.  */
-
-void ATTRIBUTE_GCC_DIAG(2,3)
-warningSupplemental (const Loc& loc, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  vwarningSupplemental (loc, format, ap);
-  va_end (ap);
-}
-
-void ATTRIBUTE_GCC_DIAG(2,0)
-vwarningSupplemental (const Loc& loc, const char *format, va_list ap)
-{
-  if (global.params.warnings == DIAGNOSTICoff || global.gag)
-    return;
-
-  d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
-}
-
-/* Print a deprecation message with explicit location LOC with an optional
-   message prefix PREFIX1 and PREFIX2, increasing the global warning or
-   error count depending on how deprecations are treated.  */
+  else if (kind == ErrorKind::deprecation)
+    {
+      if (global.params.useDeprecated == DIAGNOSTICerror)
+       return verrorReport (loc, format, ap, ErrorKind::error, prefix1,
+                            prefix2);
+      else if (global.gag || global.params.useDeprecated != DIAGNOSTICinform)
+       {
+         if (global.gag)
+           global.gaggedWarnings++;
 
-void ATTRIBUTE_GCC_DIAG(2,3)
-deprecation (const Loc& loc, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  vdeprecation (loc, format, ap);
-  va_end (ap);
-}
+         return;
+       }
 
-void ATTRIBUTE_GCC_DIAG(2,0)
-vdeprecation (const Loc& loc, const char *format, va_list ap,
-             const char *prefix1, const char *prefix2)
-{
-  if (global.params.useDeprecated == DIAGNOSTICerror)
-    verror (loc, format, ap, prefix1, prefix2);
-  else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
+      opt = OPT_Wdeprecated;
+      diag_kind = DK_WARNING;
+    }
+  else if (kind == ErrorKind::message)
     {
-      char *xformat;
-
-      /* Build string and emit.  */
-      if (prefix2 != NULL)
-       xformat = xasprintf ("%s %s %s", prefix1, prefix2, format);
-      else if (prefix1 != NULL)
-       xformat = xasprintf ("%s %s", prefix1, format);
-      else
-       xformat = xasprintf ("%s", format);
-
-      d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap,
-                                     DK_WARNING, false);
-      free (xformat);
+      diag_kind = DK_NOTE;
+      verbatim = true;
     }
-}
-
-/* Print supplementary message about the last deprecation with explicit
-   location LOC.  This does not increase the global error count.  */
+  else if (kind == ErrorKind::tip)
+    {
+      if (global.gag)
+       return;
 
-void ATTRIBUTE_GCC_DIAG(2,3)
-deprecationSupplemental (const Loc& loc, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  vdeprecationSupplemental (loc, format, ap);
-  va_end (ap);
-}
+      diag_kind = DK_DEBUG;
+      verbatim = true;
+    }
+  else
+    gcc_unreachable ();
+
+  /* Build string and emit.  */
+  if (prefix2 != NULL)
+    xformat = xasprintf ("%s %s %s", escape_d_format (prefix1),
+                        escape_d_format (prefix2), format);
+  else if (prefix1 != NULL)
+    xformat = xasprintf ("%s %s", escape_d_format (prefix1), format);
+  else
+    xformat = xasprintf ("%s", format);
 
-void ATTRIBUTE_GCC_DIAG(2,0)
-vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap)
-{
-  if (global.params.useDeprecated == DIAGNOSTICerror)
-    verrorSupplemental (loc, format, ap);
-  else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag)
-    d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
+  d_diagnostic_report_diagnostic (loc, opt, xformat, ap, diag_kind, verbatim);
+  free (xformat);
 }
 
-/* Print a verbose message with explicit location LOC.  */
-
-void ATTRIBUTE_GCC_DIAG(2, 3)
-message (const Loc& loc, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  vmessage (loc, format, ap);
-  va_end (ap);
-}
+/* Print supplementary message about the last diagnostic of type KIND, with
+   explicit location LOC.  This doesn't increase the global error count.  */
 
-void ATTRIBUTE_GCC_DIAG(2,0)
-vmessage (const Loc& loc, const char *format, va_list ap)
+void D_ATTRIBUTE_FORMAT(2,0) ATTRIBUTE_GCC_DIAG(2,0)
+verrorReportSupplemental (const Loc& loc, const char* format, va_list ap,
+                         ErrorKind kind)
 {
-  d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true);
-}
-
-/* Same as above, but doesn't take a location argument.  */
+  if (kind == ErrorKind::error)
+    {
+      if (global.gag && !global.params.v.showGaggedErrors)
+       return;
+    }
+  else if (kind == ErrorKind::warning)
+    {
+      if (global.params.warnings == DIAGNOSTICoff || global.gag)
+       return;
+    }
+  else if (kind == ErrorKind::deprecation)
+    {
+      if (global.params.useDeprecated == DIAGNOSTICerror)
+       return verrorReportSupplemental (loc, format, ap, ErrorKind::error);
+      else if (global.params.useDeprecated != DIAGNOSTICinform || global.gag)
+       return;
+    }
+  else
+    gcc_unreachable ();
 
-void ATTRIBUTE_GCC_DIAG(1, 2)
-message (const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  vmessage (Loc (), format, ap);
-  va_end (ap);
+  d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false);
 }
 
 /* Call this after printing out fatal error messages to clean up and