1 /* d-diagnostics.cc -- D frontend interface to gcc diagnostics. 2 Copyright (C) 2017-2019 Free Software Foundation, Inc. 3 4 GCC is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3, or (at your option) 7 any later version. 8 9 GCC is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along 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 43 static char * 44 expand_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 != '`') 52 { 53 buf.writeByte (*p); 54 p++; 55 } 56 57 if (*p == '\0') 58 break; 59 60 if (*p == '`') 61 { 62 /* Text enclosed by `...` are translated as a quoted string. */ 63 if (inbacktick) 64 { 65 buf.writestring ("%>"); 66 inbacktick = false; 67 } 68 else 69 { 70 buf.writestring ("%<"); 71 inbacktick = true; 72 } 73 p++; 74 continue; 75 } 76 77 /* Check the conversion specification for unhandled flags. */ 78 buf.writeByte (*p); 79 p++; 80 81 Lagain: 82 switch (*p) 83 { 84 case '\0': 85 /* Malformed format string. */ 86 gcc_unreachable (); 87 88 case '-': 89 /* Remove whitespace formatting. */ 90 p++; 91 while (ISDIGIT (*p)) 92 p++; 93 goto Lagain; 94 95 case '0': 96 /* Remove zero padding from format string. */ 97 while (ISDIGIT (*p)) 98 p++; 99 goto Lagain; 100 101 case 'X': 102 /* Hex format only supports lower-case. */ 103 buf.writeByte ('x'); 104 p++; 105 break; 106 107 default: 108 break; 109 } 110 } 111 112 gcc_assert (!inbacktick); 113 return buf.extractString (); 114 } 115 116 /* Helper routine for all error routines. Reports a diagnostic specified by 117 KIND at the explicit location LOC. The message FORMAT comes from the dmd 118 front-end, which does not get translated by the gcc diagnostic routines. */ 119 120 static void ATTRIBUTE_GCC_DIAG(3,0) 121 d_diagnostic_report_diagnostic (const Loc& loc, int opt, const char *format, 122 va_list ap, diagnostic_t kind, bool verbatim) 123 { 124 va_list argp; 125 va_copy (argp, ap); 126 127 if (loc.filename || !verbatim) 128 { 129 rich_location rich_loc (line_table, make_location_t (loc)); 130 diagnostic_info diagnostic; 131 char *xformat = expand_d_format (format); 132 133 diagnostic_set_info_translated (&diagnostic, xformat, &argp, 134 &rich_loc, kind); 135 if (opt != 0) 136 diagnostic.option_index = opt; 137 138 diagnostic_report_diagnostic (global_dc, &diagnostic); 139 free (xformat); 140 } 141 else 142 { 143 /* Write verbatim messages with no location direct to stream. */ 144 text_info text; 145 text.err_no = errno; 146 text.args_ptr = &argp; 147 text.format_spec = expand_d_format (format); 148 text.x_data = NULL; 149 150 pp_format_verbatim (global_dc->printer, &text); 151 pp_newline_and_flush (global_dc->printer); 152 } 153 154 va_end (argp); 155 } 156 157 /* Print a hard error message with explicit location LOC with an optional 158 message prefix PREFIX1 and PREFIX2, increasing the global or gagged 159 error count. */ 160 161 void ATTRIBUTE_GCC_DIAG(2,3) 162 error (const Loc& loc, const char *format, ...) 163 { 164 va_list ap; 165 va_start (ap, format); 166 verror (loc, format, ap); 167 va_end (ap); 168 } 169 170 void ATTRIBUTE_GCC_DIAG(2,0) 171 verror (const Loc& loc, const char *format, va_list ap, 172 const char *prefix1, const char *prefix2, const char *) 173 { 174 if (!global.gag || global.params.showGaggedErrors) 175 { 176 char *xformat; 177 178 /* Build string and emit. */ 179 if (prefix2 != NULL) 180 xformat = xasprintf ("%s %s %s", prefix1, prefix2, format); 181 else if (prefix1 != NULL) 182 xformat = xasprintf ("%s %s", prefix1, format); 183 else 184 xformat = xasprintf ("%s", format); 185 186 d_diagnostic_report_diagnostic (loc, 0, xformat, ap, 187 global.gag ? DK_ANACHRONISM : DK_ERROR, 188 false); 189 free (xformat); 190 } 191 192 if (global.gag) 193 global.gaggedErrors++; 194 195 global.errors++; 196 } 197 198 /* Print supplementary message about the last error with explicit location LOC. 199 This doesn't increase the global error count. */ 200 201 void ATTRIBUTE_GCC_DIAG(2,3) 202 errorSupplemental (const Loc& loc, const char *format, ...) 203 { 204 va_list ap; 205 va_start (ap, format); 206 verrorSupplemental (loc, format, ap); 207 va_end (ap); 208 } 209 210 void ATTRIBUTE_GCC_DIAG(2,0) 211 verrorSupplemental (const Loc& loc, const char *format, va_list ap) 212 { 213 if (global.gag && !global.params.showGaggedErrors) 214 return; 215 216 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); 217 } 218 219 /* Print a warning message with explicit location LOC, increasing the 220 global warning count. */ 221 222 void ATTRIBUTE_GCC_DIAG(2,3) 223 warning (const Loc& loc, const char *format, ...) 224 { 225 va_list ap; 226 va_start (ap, format); 227 vwarning (loc, format, ap); 228 va_end (ap); 229 } 230 231 void ATTRIBUTE_GCC_DIAG(2,0) 232 vwarning (const Loc& loc, const char *format, va_list ap) 233 { 234 if (!global.gag && global.params.warnings != DIAGNOSTICoff) 235 { 236 /* Warnings don't count if not treated as errors. */ 237 if (global.params.warnings == DIAGNOSTICerror) 238 global.warnings++; 239 240 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_WARNING, false); 241 } 242 } 243 244 /* Print supplementary message about the last warning with explicit location 245 LOC. This doesn't increase the global warning count. */ 246 247 void ATTRIBUTE_GCC_DIAG(2,3) 248 warningSupplemental (const Loc& loc, const char *format, ...) 249 { 250 va_list ap; 251 va_start (ap, format); 252 vwarningSupplemental (loc, format, ap); 253 va_end (ap); 254 } 255 256 void ATTRIBUTE_GCC_DIAG(2,0) 257 vwarningSupplemental (const Loc& loc, const char *format, va_list ap) 258 { 259 if (global.params.warnings == DIAGNOSTICoff || global.gag) 260 return; 261 262 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); 263 } 264 265 /* Print a deprecation message with explicit location LOC with an optional 266 message prefix PREFIX1 and PREFIX2, increasing the global warning or 267 error count depending on how deprecations are treated. */ 268 269 void ATTRIBUTE_GCC_DIAG(2,3) 270 deprecation (const Loc& loc, const char *format, ...) 271 { 272 va_list ap; 273 va_start (ap, format); 274 vdeprecation (loc, format, ap); 275 va_end (ap); 276 } 277 278 void ATTRIBUTE_GCC_DIAG(2,0) 279 vdeprecation (const Loc& loc, const char *format, va_list ap, 280 const char *prefix1, const char *prefix2) 281 { 282 if (global.params.useDeprecated == DIAGNOSTICerror) 283 verror (loc, format, ap, prefix1, prefix2); 284 else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag) 285 { 286 char *xformat; 287 288 /* Build string and emit. */ 289 if (prefix2 != NULL) 290 xformat = xasprintf ("%s %s %s", prefix1, prefix2, format); 291 else if (prefix1 != NULL) 292 xformat = xasprintf ("%s %s", prefix1, format); 293 else 294 xformat = xasprintf ("%s", format); 295 296 d_diagnostic_report_diagnostic (loc, OPT_Wdeprecated, xformat, ap, 297 DK_WARNING, false); 298 free (xformat); 299 } 300 } 301 302 /* Print supplementary message about the last deprecation with explicit 303 location LOC. This does not increase the global error count. */ 304 305 void ATTRIBUTE_GCC_DIAG(2,3) 306 deprecationSupplemental (const Loc& loc, const char *format, ...) 307 { 308 va_list ap; 309 va_start (ap, format); 310 vdeprecationSupplemental (loc, format, ap); 311 va_end (ap); 312 } 313 314 void ATTRIBUTE_GCC_DIAG(2,0) 315 vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap) 316 { 317 if (global.params.useDeprecated == DIAGNOSTICerror) 318 verrorSupplemental (loc, format, ap); 319 else if (global.params.useDeprecated == DIAGNOSTICinform && !global.gag) 320 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, false); 321 } 322 323 /* Print a verbose message with explicit location LOC. */ 324 325 void ATTRIBUTE_GCC_DIAG(2, 3) 326 message (const Loc& loc, const char *format, ...) 327 { 328 va_list ap; 329 va_start (ap, format); 330 vmessage (loc, format, ap); 331 va_end (ap); 332 } 333 334 void ATTRIBUTE_GCC_DIAG(2,0) 335 vmessage (const Loc& loc, const char *format, va_list ap) 336 { 337 d_diagnostic_report_diagnostic (loc, 0, format, ap, DK_NOTE, true); 338 } 339 340 /* Same as above, but doesn't take a location argument. */ 341 342 void ATTRIBUTE_GCC_DIAG(1, 2) 343 message (const char *format, ...) 344 { 345 va_list ap; 346 va_start (ap, format); 347 vmessage (Loc (), format, ap); 348 va_end (ap); 349 } 350 351 /* Call this after printing out fatal error messages to clean up and 352 exit the compiler. */ 353 354 void 355 fatal (void) 356 { 357 exit (FATAL_EXIT_CODE); 358 } 359