1/* d-diagnostics.cc -- D frontend interface to gcc diagnostics. 2 Copyright (C) 2017-2020 Free Software Foundation, Inc. 3 4GCC is free software; you can redistribute it and/or modify 5it under the terms of the GNU General Public License as published by 6the Free Software Foundation; either version 3, or (at your option) 7any later version. 8 9GCC is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12GNU General Public License for more details. 13 14You should have received a copy of the GNU General Public License 15along with GCC; see the file COPYING3. If not see 16<http://www.gnu.org/licenses/>. */ 17 18#include "config.h" 19#include "system.h" 20#include "coretypes.h" 21 22#include "dmd/globals.h" 23#include "dmd/errors.h" 24 25#include "tree.h" 26#include "options.h" 27#include "diagnostic.h" 28 29#include "d-tree.h" 30 31 32/* Rewrite the format string FORMAT to deal with any format extensions not 33 supported by pp_format(). 34 35 The following format specifiers are handled: 36 `...`: text within backticks gets quoted as '%<...%>'. 37 %-10s: left-justify format flag is removed leaving '%s' remaining. 38 %02x: zero-padding format flag is removed leaving '%x' remaining. 39 %X: uppercase unsigned hexadecimals are rewritten as '%x'. 40 41 The result should be freed by the caller. */ 42 43static char * 44expand_d_format (const char *format) 45{ 46 OutBuffer buf; 47 bool inbacktick = false; 48 49 for (const char *p = format; *p;) 50 { 51 while (*p != '\0' && *p != '\\' && *p != '%' && *p != '`') 52 { 53 buf.writeByte (*p); 54 p++; 55 } 56 57 if (*p == '\0') 58 break; 59 60 if (*p == '\\') 61 { 62 if (p[1] == '`') 63 { 64 /* Escaped backtick, don't expand it as a quoted string. */ 65 buf.writeByte ('`'); 66 p++;; 67 } 68 else 69 buf.writeByte (*p); 70 71 p++; 72 continue; 73 } 74 75 if (*p == '`') 76 { 77 /* Text enclosed by `...` are translated as a quoted string. */ 78 if (inbacktick) 79 { 80 buf.writestring ("%>"); 81 inbacktick = false; 82 } 83 else 84 { 85 buf.writestring ("%<"); 86 inbacktick = true; 87 } 88 p++; 89 continue; 90 } 91 92 /* Check the conversion specification for unhandled flags. */ 93 buf.writeByte (*p); 94 p++; 95 96 Lagain: 97 switch (*p) 98 { 99 case '\0': 100 /* Malformed format string. */ 101 gcc_unreachable (); 102 103 case '-': 104 /* Remove whitespace formatting. */ 105 p++; 106 while (ISDIGIT (*p)) 107 p++; 108 goto Lagain; 109 110 case '0': 111 /* Remove zero padding from format string. */ 112 while (ISDIGIT (*p)) 113 p++; 114 goto Lagain; 115 116 case 'X': 117 /* Hex format only supports lower-case. */ 118 buf.writeByte ('x'); 119 p++; 120 break; 121 122 default: 123 break; 124 } 125 } 126 127 gcc_assert (!inbacktick); 128 return buf.extractString (); 129} 130 131/* Rewrite the format string FORMAT to deal with any characters that require 132 escaping before expand_d_format expands it. */ 133 134static char * 135escape_d_format (const char *format) 136{ 137 obstack buf; 138 139 gcc_obstack_init (&buf); 140 141 for (const char *p = format; *p; p++) 142 { 143 switch (*p) 144 { 145 case '%': 146 /* Escape `%' characters so that pp_format does not confuse them 147 for actual format specifiers. */ 148 obstack_1grow (&buf, '%'); 149 break; 150 151 case '`': 152 /* Escape '`' characters so that expand_d_format does not confuse them 153 for a quoted string. */ 154 obstack_1grow (&buf, '\\'); 155 break; 156 157 default: 158 break; 159 } 160 161 obstack_1grow (&buf, *p); 162 } 163 164 obstack_1grow (&buf, '\0'); 165 return (char *) obstack_finish (&buf); 166} 167 168/* Helper routine for all error routines. Reports a diagnostic specified by 169 KIND at the explicit location LOC. The message FORMAT comes from the dmd 170 front-end, which does not get translated by the gcc diagnostic routines. */ 171 172static void ATTRIBUTE_GCC_DIAG(3,0) 173d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format, 174 va_list ap, diagnostic_t kind, bool verbatim) 175{ 176 va_list argp; 177 va_copy (argp, ap); 178 179 if (loc.filename || !verbatim) 180 { 181 rich_location rich_loc (line_table, make_location_t (loc)); 182 diagnostic_info diagnostic; 183 char *xformat = expand_d_format (format); 184 185 diagnostic_set_info_translated (&diagnostic, xformat, &argp, 186 &rich_loc, kind); 187 if (opt != 0) 188 diagnostic.option_index = opt; 189 190 diagnostic_report_diagnostic (global_dc, &diagnostic); 191 free (xformat); 192 } 193 else 194 { 195 /* Write verbatim messages with no location direct to stream. */ 196 text_info text; 197 text.err_no = errno; 198 text.args_ptr = &argp; 199 text.format_spec = expand_d_format (format); 200 text.x_data = NULL; 201 202 pp_format_verbatim (global_dc->printer, &text); 203 pp_newline_and_flush (global_dc->printer); 204 } 205 206 va_end (argp); 207} 208 209/* Print a hard error message with explicit location LOC with an optional 210 message prefix PREFIX1 and PREFIX2, increasing the global or gagged 211 error count. */ 212 213void ATTRIBUTE_GCC_DIAG(2,3) 214error (const Loc& loc, const char *format, ...) 215{ 216 va_list ap; 217 va_start (ap, format); 218 verror (loc, format, ap); 219 va_end (ap); 220} 221 222void ATTRIBUTE_GCC_DIAG(2,0) 223verror (const Loc& loc, const char *format, va_list ap, 224 const char *prefix1, const char *prefix2, const char *) 225{ 226 if (!global.gag || global.params.showGaggedErrors) 227 { 228 char *xformat; 229 230 /* Build string and emit. */ 231 if (prefix2 != NULL) 232 xformat = xasprintf ("%s %s %s", escape_d_format (prefix1), 233 escape_d_format (prefix2), format); 234 else if (prefix1 != NULL) 235 xformat = xasprintf ("%s %s", escape_d_format (prefix1), format); 236 else 237 xformat = xasprintf ("%s", format); 238 239 d_diagnostic_report_diagnostic (loc, 0, xformat, ap, 240 global.gag ? DK_ANACHRONISM : DK_ERROR, 241 false); 242 free (xformat); 243 } 244 245 if (global.gag) 246 global.gaggedErrors++; 247 248 global.errors++; 249} 250 251/* Print supplementary message about the last error with explicit location LOC. 252 This doesn't increase the global error count. */ 253 254void ATTRIBUTE_GCC_DIAG(2,3) 255errorSupplemental (const Loc& loc, const char *format, ...) 256{ 257 va_list ap; 258 va_start (ap, format); 259 verrorSupplemental (loc, format, ap); 260 va_end (ap); 261} 262 263void ATTRIBUTE_GCC_DIAG(2,0) 264verrorSupplemental (const Loc& loc, const char *format, va_list ap) 265{ 266 if (global.gag && !global.params.showGaggedErrors) 267 return; 268 269 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); 270} 271 272/* Print a warning message with explicit location LOC, increasing the 273 global warning count. */ 274 275void ATTRIBUTE_GCC_DIAG(2,3) 276warning (const Loc& loc, const char *format, ...) 277{ 278 va_list ap; 279 va_start (ap, format); 280 vwarning (loc, format, ap); 281 va_end (ap); 282} 283 284void ATTRIBUTE_GCC_DIAG(2,0) 285vwarning (const Loc& loc, const char *format, va_list ap) 286{ 287 if (!global.gag && global.params.warnings != DIAGNOSTICoff) 288 { 289 /* Warnings don't count if not treated as errors. */ 290 if (global.params.warnings == DIAGNOSTICerror) 291 global.warnings++; 292 293 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false); 294 } 295} 296 297/* Print supplementary message about the last warning with explicit location 298 LOC. This doesn't increase the global warning count. */ 299 300void ATTRIBUTE_GCC_DIAG(2,3) 301warningSupplemental (const Loc& loc, const char *format, ...) 302{ 303 va_list ap; 304 va_start (ap, format); 305 vwarningSupplemental (loc, format, ap); 306 va_end (ap); 307} 308 309void ATTRIBUTE_GCC_DIAG(2,0) 310vwarningSupplemental (const Loc& loc, const char *format, va_list ap) 311{ 312 if (global.params.warnings == DIAGNOSTICoff || global.gag) 313 return; 314 315 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); 316} 317 318/* Print a deprecation message with explicit location LOC with an optional 319 message prefix PREFIX1 and PREFIX2, increasing the global warning or 320 error count depending on how deprecations are treated. */ 321 322void ATTRIBUTE_GCC_DIAG(2,3) 323deprecation (const Loc& loc, const char *format, ...) 324{ 325 va_list ap; 326 va_start (ap, format); 327 vdeprecation (loc, format, ap); 328 va_end (ap); 329} 330 331void ATTRIBUTE_GCC_DIAG(2,0) 332vdeprecation (const Loc& loc, const char *format, va_list ap, 333 const char *prefix1, const char *prefix2) 334{ 335 if (global.params.useDeprecated == DIAGNOSTICerror) 336 verror (loc, format, ap, prefix1, prefix2); 337 else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag) 338 { 339 char *xformat; 340 341 /* Build string and emit. */ 342 if (prefix2 != NULL) 343 xformat = xasprintf ("%s %s %s", escape_d_format (prefix1), 344 escape_d_format (prefix2), format); 345 else if (prefix1 != NULL) 346 xformat = xasprintf ("%s %s", escape_d_format (prefix1), format); 347 else 348 xformat = xasprintf ("%s", format); 349 350 d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap, 351 DK_WARNING, false); 352 free (xformat); 353 } 354} 355 356/* Print supplementary message about the last deprecation with explicit 357 location LOC. This does not increase the global error count. */ 358 359void ATTRIBUTE_GCC_DIAG(2,3) 360deprecationSupplemental (const Loc& loc, const char *format, ...) 361{ 362 va_list ap; 363 va_start (ap, format); 364 vdeprecationSupplemental (loc, format, ap); 365 va_end (ap); 366} 367 368void ATTRIBUTE_GCC_DIAG(2,0) 369vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap) 370{ 371 if (global.params.useDeprecated == DIAGNOSTICerror) 372 verrorSupplemental (loc, format, ap); 373 else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag) 374 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); 375} 376 377/* Print a verbose message with explicit location LOC. */ 378 379void ATTRIBUTE_GCC_DIAG(2, 3) 380message (const Loc& loc, const char *format, ...) 381{ 382 va_list ap; 383 va_start (ap, format); 384 vmessage (loc, format, ap); 385 va_end (ap); 386} 387 388void ATTRIBUTE_GCC_DIAG(2,0) 389vmessage (const Loc& loc, const char *format, va_list ap) 390{ 391 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true); 392} 393 394/* Same as above, but doesn't take a location argument. */ 395 396void ATTRIBUTE_GCC_DIAG(1, 2) 397message (const char *format, ...) 398{ 399 va_list ap; 400 va_start (ap, format); 401 vmessage (Loc (), format, ap); 402 va_end (ap); 403} 404 405/* Call this after printing out fatal error messages to clean up and 406 exit the compiler. */ 407 408void 409fatal (void) 410{ 411 exit (FATAL_EXIT_CODE); 412} 413