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