/* 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
`...`: 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++;
}
/* Check the conversion specification for unhandled flags. */
- buf.writeByte (*p);
+ obstack_1grow (&buf, *p);
p++;
Lagain:
case 'X':
/* Hex format only supports lower-case. */
- buf.writeByte ('x');
+ obstack_1grow (&buf, 'x');
p++;
break;
}
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
front-end, which does not get translated by the gcc diagnostic routines. */
static void ATTRIBUTE_GCC_DIAG(3,0)
-d_diagnostic_report_diagnostic (const Loc& loc, 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;
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);
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