136 insertions(+), 226 deletions(-), less 90 lines (except tests) only one set_flag() function required * can now turn off specific errors: -Werror -Wno-error=option * new interface: tcc_warning_c(warn_option)("format", args...); * new warning: -Wdiscarded-qualifiers (on by default) * new variable 'warn_all' for conditional warnings with -Wall see also the tests
Unified · Split
| @@ -510,10 +510,6 @@ static void strcat_printf(char *buf, int buf_size, const char *fmt, ...) · 509 unmodified lines | |||
| 510 | va_end(ap); | 510 | va_end(ap); |
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | #define ERROR_WARN 0 | ||
| 514 | #define ERROR_NOABORT 1 | ||
| 515 | #define ERROR_ERROR 2 | ||
| 516 | |||
| 517 | PUB_FUNC void tcc_enter_state(TCCState *s1) | 513 | PUB_FUNC void tcc_enter_state(TCCState *s1) |
| 518 | { | 514 | { |
| 519 | WAIT_SEM(); | 515 | WAIT_SEM(); |
| @@ -526,6 +522,10 @@ PUB_FUNC void tcc_exit_state(void) · 6 unmodified lines | |||
| 526 | POST_SEM(); | 522 | POST_SEM(); |
| 527 | } | 523 | } |
| 528 | 524 | ||
| 525 | #define ERROR_WARN 0 | ||
| 526 | #define ERROR_NOABORT 1 | ||
| 527 | #define ERROR_ERROR 2 | ||
| 528 | |||
| 529 | static void error1(int mode, const char *fmt, va_list ap) | 529 | static void error1(int mode, const char *fmt, va_list ap) |
| 530 | { | 530 | { |
| 531 | char buf[2048]; | 531 | char buf[2048]; |
| @@ -537,15 +537,26 @@ static void error1(int mode, const char *fmt, va_list ap) · 5 unmodified lines | |||
| 537 | /* can happen only if called from tcc_malloc(): 'out of memory' */ | 537 | /* can happen only if called from tcc_malloc(): 'out of memory' */ |
| 538 | goto no_file; | 538 | goto no_file; |
| 539 | 539 | ||
| 540 | if (s1 && !s1->error_set_jmp_enabled) | 540 | if (!s1->error_set_jmp_enabled) |
| 541 | /* tcc_state just was set by tcc_enter_state() */ | 541 | /* tcc_state just was set by tcc_enter_state() */ |
| 542 | tcc_exit_state(); | 542 | tcc_exit_state(); |
| 543 | 543 | ||
| 544 | if (mode == ERROR_WARN) { | 544 | if (mode == ERROR_WARN) { |
| 545 | if (s1->warn_mask & WARN_DISABLED) | 545 | if (s1->warn_error) |
| 546 | return; | ||
| 547 | if (s1->warn_mask & WARN_ERROR_MASK) /* XXX individual ignorance */ | ||
| 548 | mode = ERROR_ERROR; | 546 | mode = ERROR_ERROR; |
| 547 | if (s1->warn_num) { | ||
| 548 | /* handle tcc_warning_c(warn_option)(fmt, ...) */ | ||
| 549 | int wopt = *(&s1->warn_none + s1->warn_num); | ||
| 550 | s1->warn_num = 0; | ||
| 551 | if (0 == (wopt & WARN_ON)) | ||
| 552 | return; | ||
| 553 | if (wopt & WARN_ERR) | ||
| 554 | mode = ERROR_ERROR; | ||
| 555 | if (wopt & WARN_NOE) | ||
| 556 | mode = ERROR_WARN; | ||
| 557 | } | ||
| 558 | if (s1->warn_none) | ||
| 559 | return; | ||
| 549 | } | 560 | } |
| 550 | 561 | ||
| 551 | f = NULL; | 562 | f = NULL; |
| @@ -786,7 +797,8 @@ LIBTCCAPI TCCState *tcc_new(void) · 234 unmodified lines | |||
| 786 | s->nocommon = 1; | 797 | s->nocommon = 1; |
| 787 | s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/ | 798 | s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/ |
| 788 | s->cversion = 199901; /* default unless -std=c11 is supplied */ | 799 | s->cversion = 199901; /* default unless -std=c11 is supplied */ |
| 789 | s->warn_mask |= WARN_IMPLICIT_FUNCTION_DECLARATION; | 800 | s->warn_implicit_function_declaration = 1; |
| 801 | s->warn_discarded_qualifiers = 1; | ||
| 790 | s->ms_extensions = 1; | 802 | s->ms_extensions = 1; |
| 791 | 803 | ||
| 792 | #ifdef CHAR_IS_UNSIGNED | 804 | #ifdef CHAR_IS_UNSIGNED |
| @@ -1230,122 +1242,8 @@ LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) · 437 unmodified lines | |||
| 1230 | s->tcc_lib_path = tcc_strdup(path); | 1242 | s->tcc_lib_path = tcc_strdup(path); |
| 1231 | } | 1243 | } |
| 1232 | 1244 | ||
| 1233 | #define WD_ALL (1u<<0) /* warning is activated when using -Wall */ | 1245 | /********************************************************/ |
| 1234 | #define WD_ERROR (1u<<1) /* can be used with -W[no-]error=X */ | 1246 | /* options parser */ |
| 1235 | #define FD_INVERT (1u<<2) /* invert value before storing */ | ||
| 1236 | |||
| 1237 | typedef struct FlagDef { | ||
| 1238 | uint16_t offset; | ||
| 1239 | uint16_t flags; | ||
| 1240 | const char *name; | ||
| 1241 | } FlagDef; | ||
| 1242 | |||
| 1243 | static int no_flag(const char **pp) | ||
| 1244 | { | ||
| 1245 | const char *p = *pp; | ||
| 1246 | if (*p != 'n' || *++p != 'o' || *++p != '-') | ||
| 1247 | return 0; | ||
| 1248 | *pp = p + 1; | ||
| 1249 | return 1; | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name) | ||
| 1253 | { | ||
| 1254 | int value, ret; | ||
| 1255 | const FlagDef *p; | ||
| 1256 | const char *r; | ||
| 1257 | |||
| 1258 | value = 1; | ||
| 1259 | r = name; | ||
| 1260 | if (no_flag(&r)) | ||
| 1261 | value = 0; | ||
| 1262 | |||
| 1263 | for (ret = -1, p = flags; p->name; ++p) { | ||
| 1264 | if (ret) { | ||
| 1265 | if (strcmp(r, p->name)) | ||
| 1266 | continue; | ||
| 1267 | } else { | ||
| 1268 | if (0 == (p->flags & WD_ALL)) | ||
| 1269 | continue; | ||
| 1270 | } | ||
| 1271 | if (p->offset) { | ||
| 1272 | *((unsigned char *)s + p->offset) = | ||
| 1273 | p->flags & FD_INVERT ? !value : value; | ||
| 1274 | if (ret) | ||
| 1275 | return 0; | ||
| 1276 | } else { | ||
| 1277 | ret = 0; | ||
| 1278 | } | ||
| 1279 | } | ||
| 1280 | return ret; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | ST_FUNC int set_W_flag(TCCState *s, const char *optarg) | ||
| 1284 | { | ||
| 1285 | static struct a_W_flag{ | ||
| 1286 | uint32_t wbit; | ||
| 1287 | uint32_t flags; | ||
| 1288 | char const *name; | ||
| 1289 | } const opts[] = { | ||
| 1290 | {WARN_ALL, 0, "all"}, | ||
| 1291 | {WARN_ERROR | (WARN_ERROR << WARN_ERROR_SHIFT), 0, "error"}, | ||
| 1292 | {WARN_UNSUPPORTED, WD_ERROR, "unsupported"}, | ||
| 1293 | {WARN_GCC_COMPAT, WD_ERROR, "gcc-compat"}, | ||
| 1294 | {WARN_WRITE_STRINGS, WD_ERROR | WD_ALL, "write-strings"}, | ||
| 1295 | {WARN_IMPLICIT_FUNCTION_DECLARATION, WD_ERROR | WD_ALL, | ||
| 1296 | "implicit-function-declaration"} | ||
| 1297 | }, *p; | ||
| 1298 | |||
| 1299 | int ret; | ||
| 1300 | unsigned char mode; | ||
| 1301 | const char *r, *sub; | ||
| 1302 | |||
| 1303 | mode = 1; | ||
| 1304 | r = optarg; | ||
| 1305 | if (no_flag(&r)) | ||
| 1306 | mode = 0; | ||
| 1307 | |||
| 1308 | if ((sub = strchr(r, '=')) != NULL) { | ||
| 1309 | if (strncmp(r, "error", (uintptr_t)(sub - r))) | ||
| 1310 | return -1; | ||
| 1311 | r = ++sub; | ||
| 1312 | mode |= 2; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | for (ret = -1, p = opts; p < &opts[countof(opts)]; ++p) { | ||
| 1316 | if (ret) { | ||
| 1317 | if (strcmp(r, p->name)) | ||
| 1318 | continue; | ||
| 1319 | if ((mode & 2) && !(p->flags & WD_ERROR)) | ||
| 1320 | break; | ||
| 1321 | } else { | ||
| 1322 | if (0 == (p->flags & WD_ALL)) | ||
| 1323 | continue; | ||
| 1324 | } | ||
| 1325 | |||
| 1326 | if (p->wbit == WARN_ALL) { | ||
| 1327 | /* Start a loop over all the rest */ | ||
| 1328 | ret = 0; | ||
| 1329 | continue; | ||
| 1330 | } | ||
| 1331 | |||
| 1332 | if (mode & 1) { | ||
| 1333 | s->warn_mask |= p->wbit; | ||
| 1334 | if (mode & 2) | ||
| 1335 | s->warn_mask |= p->wbit << WARN_ERROR_SHIFT; | ||
| 1336 | } else { | ||
| 1337 | s->warn_mask &= ~(p->wbit << ((mode & 2) ? WARN_ERROR_SHIFT : 0)); | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | /* Done if not in "all" mode */ | ||
| 1341 | if (ret) { | ||
| 1342 | ret = 0; | ||
| 1343 | break; | ||
| 1344 | } | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | return ret; | ||
| 1348 | } | ||
| 1349 | 1247 | ||
| 1350 | static int strstart(const char *val, const char **str) | 1248 | static int strstart(const char *val, const char **str) |
| 1351 | { | 1249 | { |
| @@ -1388,7 +1286,7 @@ static int link_option(const char *str, const char *val, const char **ptr) · 36 unmodified lines | |||
| 1388 | ret = 1; | 1286 | ret = 1; |
| 1389 | if (q[0] == '?') { | 1287 | if (q[0] == '?') { |
| 1390 | ++q; | 1288 | ++q; |
| 1391 | if (no_flag(&p)) | 1289 | if (strstart("no-", &p)) |
| 1392 | ret = -1; | 1290 | ret = -1; |
| 1393 | } | 1291 | } |
| 1394 | 1292 | ||
| @@ -1536,10 +1434,8 @@ static int tcc_set_linker(TCCState *s, const char *option) · 141 unmodified lines | |||
| 1536 | err: | 1434 | err: |
| 1537 | tcc_error("unsupported linker option '%s'", option); | 1435 | tcc_error("unsupported linker option '%s'", option); |
| 1538 | } | 1436 | } |
| 1539 | 1437 | if (ignoring) | |
| 1540 | if (ignoring && NEED_WARNING(s, UNSUPPORTED)) | 1438 | tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", option); |
| 1541 | tcc_warning("unsupported linker option '%s'", option); | ||
| 1542 | |||
| 1543 | option = skip_linker_arg(&p); | 1439 | option = skip_linker_arg(&p); |
| 1544 | } | 1440 | } |
| 1545 | return 1; | 1441 | return 1; |
| @@ -1682,6 +1578,25 @@ static const TCCOption tcc_options[] = { · 136 unmodified lines | |||
| 1682 | { NULL, 0, 0 }, | 1578 | { NULL, 0, 0 }, |
| 1683 | }; | 1579 | }; |
| 1684 | 1580 | ||
| 1581 | typedef struct FlagDef { | ||
| 1582 | uint16_t offset; | ||
| 1583 | uint16_t flags; | ||
| 1584 | const char *name; | ||
| 1585 | } FlagDef; | ||
| 1586 | |||
| 1587 | #define WD_ALL 0x0001 /* warning is activated when using -Wall */ | ||
| 1588 | #define FD_INVERT 0x0002 /* invert value before storing */ | ||
| 1589 | |||
| 1590 | static const FlagDef options_W[] = { | ||
| 1591 | { offsetof(TCCState, warn_all), WD_ALL, "all" }, | ||
| 1592 | { offsetof(TCCState, warn_error), 0, "error" }, | ||
| 1593 | { offsetof(TCCState, warn_write_strings), 0, "write-strings" }, | ||
| 1594 | { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, | ||
| 1595 | { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, "implicit-function-declaration" }, | ||
| 1596 | { offsetof(TCCState, warn_discarded_qualifiers), WD_ALL, "discarded-qualifiers" }, | ||
| 1597 | { 0, 0, NULL } | ||
| 1598 | }; | ||
| 1599 | |||
| 1685 | static const FlagDef options_f[] = { | 1600 | static const FlagDef options_f[] = { |
| 1686 | { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, | 1601 | { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, |
| 1687 | { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, | 1602 | { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, |
| @@ -1701,6 +1616,40 @@ static const FlagDef options_m[] = { · 13 unmodified lines | |||
| 1701 | { 0, 0, NULL } | 1616 | { 0, 0, NULL } |
| 1702 | }; | 1617 | }; |
| 1703 | 1618 | ||
| 1619 | static int set_flag(TCCState *s, const FlagDef *flags, const char *name) | ||
| 1620 | { | ||
| 1621 | int value, mask, ret; | ||
| 1622 | const FlagDef *p; | ||
| 1623 | const char *r; | ||
| 1624 | unsigned char *f; | ||
| 1625 | |||
| 1626 | r = name, value = !strstart("no-", &r), mask = 0; | ||
| 1627 | |||
| 1628 | /* when called with options_W, look for -W[no-]error=<option> */ | ||
| 1629 | if ((flags->flags & WD_ALL) && strstart("error=", &r)) | ||
| 1630 | value = value ? WARN_ON|WARN_ERR : WARN_NOE, mask = WARN_ON; | ||
| 1631 | |||
| 1632 | for (ret = -1, p = flags; p->name; ++p) { | ||
| 1633 | if (ret) { | ||
| 1634 | if (strcmp(r, p->name)) | ||
| 1635 | continue; | ||
| 1636 | } else { | ||
| 1637 | if (0 == (p->flags & WD_ALL)) | ||
| 1638 | continue; | ||
| 1639 | } | ||
| 1640 | |||
| 1641 | f = (unsigned char *)s + p->offset; | ||
| 1642 | *f = (*f & mask) | (value ^ !!(p->flags & FD_INVERT)); | ||
| 1643 | |||
| 1644 | if (ret) { | ||
| 1645 | ret = 0; | ||
| 1646 | if (strcmp(r, "all")) | ||
| 1647 | break; | ||
| 1648 | } | ||
| 1649 | } | ||
| 1650 | return ret; | ||
| 1651 | } | ||
| 1652 | |||
| 1704 | static void args_parser_add_file(TCCState *s, const char* filename, int filetype) | 1653 | static void args_parser_add_file(TCCState *s, const char* filename, int filetype) |
| 1705 | { | 1654 | { |
| 1706 | struct filespec *f = tcc_malloc(sizeof *f + strlen(filename)); | 1655 | struct filespec *f = tcc_malloc(sizeof *f + strlen(filename)); |
| @@ -1976,12 +1925,12 @@ reparse: · 269 unmodified lines | |||
| 1976 | } | 1925 | } |
| 1977 | break; | 1926 | break; |
| 1978 | case TCC_OPTION_W: | 1927 | case TCC_OPTION_W: |
| 1979 | s->warn_mask &= ~WARN_DISABLED; | 1928 | s->warn_none = 0; |
| 1980 | if (optarg[0] && set_W_flag(s, optarg) < 0) | 1929 | if (optarg[0] && set_flag(s, options_W, optarg) < 0) |
| 1981 | goto unsupported_option; | 1930 | goto unsupported_option; |
| 1982 | break; | 1931 | break; |
| 1983 | case TCC_OPTION_w: | 1932 | case TCC_OPTION_w: |
| 1984 | s->warn_mask |= WARN_DISABLED; | 1933 | s->warn_none = 1; |
| 1985 | break; | 1934 | break; |
| 1986 | case TCC_OPTION_rdynamic: | 1935 | case TCC_OPTION_rdynamic: |
| 1987 | s->rdynamic = 1; | 1936 | s->rdynamic = 1; |
| @@ -2064,8 +2013,7 @@ reparse: · 76 unmodified lines | |||
| 2064 | break; | 2013 | break; |
| 2065 | default: | 2014 | default: |
| 2066 | unsupported_option: | 2015 | unsupported_option: |
| 2067 | if (NEED_WARNING(s, UNSUPPORTED)) | 2016 | tcc_warning_c(warn_unsupported)("unsupported option '%s'", r); |
| 2068 | tcc_warning("unsupported option '%s'", r); | ||
| 2069 | break; | 2017 | break; |
| 2070 | } | 2018 | } |
| 2071 | } | 2019 | } |
| @@ -267,15 +267,12 @@ Make string constants be of type @code{const char *} instead of @code{char · 266 unmodified lines | |||
| 267 | *}. | 267 | *}. |
| 268 | 268 | ||
| 269 | @item -Werror | 269 | @item -Werror |
| 270 | Abort compilation if a warning is issued. | 270 | Abort compilation if a warning is issued. Can be given an option to enable |
| 271 | Can be given an option to enable the specified warning | 271 | the specified warning and turn it into an error, for example |
| 272 | and turn it into an error, for example @option{-Werror=unsupported}. | 272 | @option{-Werror=unsupported}. |
| 273 | Enabling general abortion and disabling specifics is not supported. | ||
| 274 | Disabling specific abortions again does not disable the according warning. | ||
| 275 | 273 | ||
| 276 | @item -Wall | 274 | @item -Wall |
| 277 | Activate all warnings, except @option{-Werror}, @option{-Wunsupported} and | 275 | Activate some useful warnings. |
| 278 | @option{-Wwrite-strings}. | ||
| 279 | 276 | ||
| 280 | @end table | 277 | @end table |
| 281 | 278 | ||
| @@ -36,7 +36,7 @@ static const char help[] = · 35 unmodified lines | |||
| 36 | " -std=c99 Conform to the ISO 1999 C standard (default).\n" | 36 | " -std=c99 Conform to the ISO 1999 C standard (default).\n" |
| 37 | " -std=c11 Conform to the ISO 2011 C standard.\n" | 37 | " -std=c11 Conform to the ISO 2011 C standard.\n" |
| 38 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" | 38 | " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" |
| 39 | " -w disable all warnings and their consequences\n" | 39 | " -w disable all warnings\n" |
| 40 | " --version -v show version\n" | 40 | " --version -v show version\n" |
| 41 | " -vv show search paths or loaded files\n" | 41 | " -vv show search paths or loaded files\n" |
| 42 | " -h -hh show this, show more help\n" | 42 | " -h -hh show this, show more help\n" |
| @@ -103,10 +103,11 @@ static const char help2[] = · 60 unmodified lines | |||
| 103 | " --param -pedantic -pipe -s -traditional\n" | 103 | " --param -pedantic -pipe -s -traditional\n" |
| 104 | "-W[no-]... warnings:\n" | 104 | "-W[no-]... warnings:\n" |
| 105 | " all turn on some (*) warnings\n" | 105 | " all turn on some (*) warnings\n" |
| 106 | " error[=(X)] error out after first warning (for X)\n" | 106 | " error[=warning] stop after warning (any or specified)\n" |
| 107 | " unsupported warn for ignored options, pragmas,.. (X)\n" | 107 | " write-strings strings are const\n" |
| 108 | " write-strings strings are const (*,X)\n" | 108 | " unsupported warn about ignored options, pragmas, etc.\n" |
| 109 | " implicit-function-declaration warn for missing prototype (*,X)\n" | 109 | " implicit-function-declaration warn for missing prototype (*)\n" |
| 110 | " discarded-qualifiers warn when const is dropped (*)\n" | ||
| 110 | "-f[no-]... flags:\n" | 111 | "-f[no-]... flags:\n" |
| 111 | " unsigned-char default char is unsigned\n" | 112 | " unsigned-char default char is unsigned\n" |
| 112 | " signed-char default char is signed\n" | 113 | " signed-char default char is signed\n" |
| @@ -317,7 +318,7 @@ redo: · 204 unmodified lines | |||
| 317 | } | 318 | } |
| 318 | 319 | ||
| 319 | if (s->nb_files == 0) | 320 | if (s->nb_files == 0) |
| 320 | tcc_error("no input files\n"); | 321 | tcc_error("no input files"); |
| 321 | 322 | ||
| 322 | if (s->output_type == TCC_OUTPUT_PREPROCESS) { | 323 | if (s->output_type == TCC_OUTPUT_PREPROCESS) { |
| 323 | if (s->outfile && 0!=strcmp("-",s->outfile)) { | 324 | if (s->outfile && 0!=strcmp("-",s->outfile)) { |
| @@ -737,24 +737,6 @@ struct sym_attr { · 736 unmodified lines | |||
| 737 | #endif | 737 | #endif |
| 738 | }; | 738 | }; |
| 739 | 739 | ||
| 740 | /* 32-bit bit carrier, split in two halves: lower=warn, upper=error */ | ||
| 741 | enum warn_option { | ||
| 742 | WARN_NONE, | ||
| 743 | WARN_UNSUPPORTED = 1u<<0, | ||
| 744 | WARN_GCC_COMPAT = 1u<<1, | ||
| 745 | WARN_WRITE_STRINGS = 1u<<2, | ||
| 746 | WARN_IMPLICIT_FUNCTION_DECLARATION = 1u<<3, | ||
| 747 | /* _ERROR is in lower as "max", there is no warning for it */ | ||
| 748 | WARN_ERROR = 1u<<4, | ||
| 749 | WARN_ALL = WARN_ERROR - 1, | ||
| 750 | /* Is neither in lower nor upper: disables warnings and errors (-w) */ | ||
| 751 | WARN_DISABLED = WARN_ERROR << 1 | ||
| 752 | }; | ||
| 753 | enum { | ||
| 754 | WARN_ERROR_SHIFT = 16u, | ||
| 755 | WARN_ERROR_MASK = (/*WARN_ALL |*/ WARN_ERROR) << WARN_ERROR_SHIFT | ||
| 756 | }; | ||
| 757 | |||
| 758 | struct TCCState { | 740 | struct TCCState { |
| 759 | unsigned char verbose; /* if true, display some information during compilation */ | 741 | unsigned char verbose; /* if true, display some information during compilation */ |
| 760 | unsigned char nostdinc; /* if true, no standard headers are added */ | 742 | unsigned char nostdinc; /* if true, no standard headers are added */ |
| @@ -785,13 +767,18 @@ struct TCCState { · 24 unmodified lines | |||
| 785 | unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */ | 767 | unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */ |
| 786 | unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ | 768 | unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ |
| 787 | 769 | ||
| 788 | /* NEED_WARNING(SELF,X) used to drive W[[no-]error]=X */ | 770 | /* warning switches */ |
| 789 | uint32_t warn_mask; | 771 | unsigned char warn_none; |
| 790 | #define NEED_WARNING(SELF,SWITCH) \ | 772 | unsigned char warn_all; |
| 791 | (((SELF)->warn_mask & \ | 773 | unsigned char warn_error; |
| 792 | (WARN_ ## SWITCH | (WARN_ ## SWITCH << WARN_ERROR_SHIFT))) \ | 774 | unsigned char warn_write_strings; |
| 793 | ? (((SELF)->warn_mask & (WARN_ ## SWITCH << WARN_ERROR_SHIFT)) \ | 775 | unsigned char warn_unsupported; |
| 794 | ? (SELF)->warn_mask |= (WARN_ERROR << WARN_ERROR_SHIFT), 1 : 1) : 0) | 776 | unsigned char warn_implicit_function_declaration; |
| 777 | unsigned char warn_discarded_qualifiers; | ||
| 778 | #define WARN_ON 1 /* warning is on (-Woption) */ | ||
| 779 | #define WARN_ERR 2 /* warning is an error (-Werror=option) */ | ||
| 780 | #define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */ | ||
| 781 | unsigned char warn_num; /* temp var for tcc_warning_c() */ | ||
| 795 | 782 | ||
| 796 | /* compile with debug symbol (and use them if error during execution) */ | 783 | /* compile with debug symbol (and use them if error during execution) */ |
| 797 | unsigned char do_debug; | 784 | unsigned char do_debug; |
| @@ -1890,6 +1877,11 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename) · 1092 unmodified lines | |||
| 1890 | PUB_FUNC void tcc_enter_state(TCCState *s1); | 1877 | PUB_FUNC void tcc_enter_state(TCCState *s1); |
| 1891 | PUB_FUNC void tcc_exit_state(void); | 1878 | PUB_FUNC void tcc_exit_state(void); |
| 1892 | 1879 | ||
| 1880 | /* conditional warning depending on switch */ | ||
| 1881 | #define tcc_warning_c(sw) TCC_SET_STATE((\ | ||
| 1882 | tcc_state->warn_num = offsetof(TCCState, sw) \ | ||
| 1883 | - offsetof(TCCState, warn_none), _tcc_warning)) | ||
| 1884 | |||
| 1893 | /********************************************************/ | 1885 | /********************************************************/ |
| 1894 | #endif /* _TCC_H */ | 1886 | #endif /* _TCC_H */ |
| 1895 | 1887 | ||
| @@ -1903,6 +1895,4 @@ PUB_FUNC void tcc_exit_state(void); · 7 unmodified lines | |||
| 1903 | #else | 1895 | #else |
| 1904 | # define TCC_STATE_VAR(sym) s1->sym | 1896 | # define TCC_STATE_VAR(sym) s1->sym |
| 1905 | # define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn) | 1897 | # define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn) |
| 1906 | /* actually we could avoid the tcc_enter_state(s1) hack by using | ||
| 1907 | __VA_ARGS__ except that some compiler doesn't support it. */ | ||
| 1908 | #endif | 1898 | #endif |
| @@ -769,15 +769,11 @@ static void asm_parse_directive(TCCState *s1, int global) · 768 unmodified lines | |||
| 769 | 769 | ||
| 770 | filename[0] = '\0'; | 770 | filename[0] = '\0'; |
| 771 | next(); | 771 | next(); |
| 772 | |||
| 773 | if (tok == TOK_STR) | 772 | if (tok == TOK_STR) |
| 774 | pstrcat(filename, sizeof(filename), tokc.str.data); | 773 | pstrcat(filename, sizeof(filename), tokc.str.data); |
| 775 | else | 774 | else |
| 776 | pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); | 775 | pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); |
| 777 | 776 | tcc_warning_c(warn_unsupported)("ignoring .file %s", filename); | |
| 778 | if (NEED_WARNING(s1, UNSUPPORTED)) | ||
| 779 | tcc_warning("ignoring .file %s", filename); | ||
| 780 | |||
| 781 | next(); | 777 | next(); |
| 782 | } | 778 | } |
| 783 | break; | 779 | break; |
| @@ -787,15 +783,11 @@ static void asm_parse_directive(TCCState *s1, int global) · 3 unmodified lines | |||
| 787 | 783 | ||
| 788 | ident[0] = '\0'; | 784 | ident[0] = '\0'; |
| 789 | next(); | 785 | next(); |
| 790 | |||
| 791 | if (tok == TOK_STR) | 786 | if (tok == TOK_STR) |
| 792 | pstrcat(ident, sizeof(ident), tokc.str.data); | 787 | pstrcat(ident, sizeof(ident), tokc.str.data); |
| 793 | else | 788 | else |
| 794 | pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); | 789 | pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); |
| 795 | 790 | tcc_warning_c(warn_unsupported)("ignoring .ident %s", ident); | |
| 796 | if (NEED_WARNING(s1, UNSUPPORTED)) | ||
| 797 | tcc_warning("ignoring .ident %s", ident); | ||
| 798 | |||
| 799 | next(); | 791 | next(); |
| 800 | } | 792 | } |
| 801 | break; | 793 | break; |
| @@ -808,11 +800,8 @@ static void asm_parse_directive(TCCState *s1, int global) · 6 unmodified lines | |||
| 808 | if (!sym) { | 800 | if (!sym) { |
| 809 | tcc_error("label not found: %s", get_tok_str(tok, NULL)); | 801 | tcc_error("label not found: %s", get_tok_str(tok, NULL)); |
| 810 | } | 802 | } |
| 811 | |||
| 812 | /* XXX .size name,label2-label1 */ | 803 | /* XXX .size name,label2-label1 */ |
| 813 | if (NEED_WARNING(s1, UNSUPPORTED)) | 804 | tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL)); |
| 814 | tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL)); | ||
| 815 | |||
| 816 | next(); | 805 | next(); |
| 817 | skip(','); | 806 | skip(','); |
| 818 | while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) { | 807 | while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) { |
| @@ -839,9 +828,8 @@ static void asm_parse_directive(TCCState *s1, int global) · 20 unmodified lines | |||
| 839 | 828 | ||
| 840 | if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { | 829 | if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { |
| 841 | sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; | 830 | sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; |
| 842 | } | 831 | } else |
| 843 | else if (NEED_WARNING(s1, UNSUPPORTED)) | 832 | tcc_warning_c(warn_unsupported)("change type of '%s' from 0x%x to '%s' ignored", |
| 844 | tcc_warning("change type of '%s' from 0x%x to '%s' ignored", | ||
| 845 | get_tok_str(sym->v, NULL), sym->type.t, newtype); | 833 | get_tok_str(sym->v, NULL), sym->type.t, newtype); |
| 846 | 834 | ||
| 847 | next(); | 835 | next(); |
| @@ -4077,7 +4077,7 @@ static void verify_assign_cast(CType *dt) · 4076 unmodified lines | |||
| 4077 | } | 4077 | } |
| 4078 | } | 4078 | } |
| 4079 | if (qualwarn) | 4079 | if (qualwarn) |
| 4080 | tcc_warning("assignment discards qualifiers from pointer target type"); | 4080 | tcc_warning_c(warn_discarded_qualifiers)("assignment discards qualifiers from pointer target type"); |
| 4081 | break; | 4081 | break; |
| 4082 | case VT_BYTE: | 4082 | case VT_BYTE: |
| 4083 | case VT_SHORT: | 4083 | case VT_SHORT: |
| @@ -4355,9 +4355,9 @@ redo: · 271 unmodified lines | |||
| 4355 | skip('('); | 4355 | skip('('); |
| 4356 | s = sym_find(tok); | 4356 | s = sym_find(tok); |
| 4357 | if (!s) { | 4357 | if (!s) { |
| 4358 | tcc_warning("implicit declaration of function '%s'", | 4358 | tcc_warning_c(warn_implicit_function_declaration)( |
| 4359 | get_tok_str(tok, &tokc)); | 4359 | "implicit declaration of function '%s'", get_tok_str(tok, &tokc)); |
| 4360 | s = external_global_sym(tok, &func_old_type); | 4360 | s = external_global_sym(tok, &func_old_type); |
| 4361 | } else if ((s->type.t & VT_BTYPE) != VT_FUNC) | 4361 | } else if ((s->type.t & VT_BTYPE) != VT_FUNC) |
| 4362 | tcc_error("'%s' is not declared as function", get_tok_str(tok, &tokc)); | 4362 | tcc_error("'%s' is not declared as function", get_tok_str(tok, &tokc)); |
| 4363 | ad->cleanup_func = s; | 4363 | ad->cleanup_func = s; |
| @@ -4506,8 +4506,7 @@ redo: · 142 unmodified lines | |||
| 4506 | ad->a.dllimport = 1; | 4506 | ad->a.dllimport = 1; |
| 4507 | break; | 4507 | break; |
| 4508 | default: | 4508 | default: |
| 4509 | if (NEED_WARNING(tcc_state, UNSUPPORTED)) | 4509 | tcc_warning_c(warn_unsupported)("'%s' attribute ignored", get_tok_str(t, NULL)); |
| 4510 | tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL)); | ||
| 4511 | /* skip parameters */ | 4510 | /* skip parameters */ |
| 4512 | if (tok == '(') { | 4511 | if (tok == '(') { |
| 4513 | int parenthesis = 0; | 4512 | int parenthesis = 0; |
| @@ -5909,23 +5908,20 @@ ST_FUNC void unary(void) · 1395 unmodified lines | |||
| 5909 | case TOK___FUNC__: | 5908 | case TOK___FUNC__: |
| 5910 | { | 5909 | { |
| 5911 | Section *sec; | 5910 | Section *sec; |
| 5912 | void *ptr; | ||
| 5913 | int len; | 5911 | int len; |
| 5914 | /* special function name identifier */ | 5912 | /* special function name identifier */ |
| 5915 | len = strlen(funcname) + 1; | 5913 | len = strlen(funcname) + 1; |
| 5916 | /* generate char[len] type */ | 5914 | /* generate char[len] type */ |
| 5917 | type.t = VT_BYTE; | 5915 | type.t = char_type.t; |
| 5918 | if (NEED_WARNING(tcc_state, WRITE_STRINGS)) | 5916 | if (tcc_state->warn_write_strings & WARN_ON) |
| 5919 | type.t |= VT_CONSTANT; | 5917 | type.t |= VT_CONSTANT; |
| 5920 | mk_pointer(&type); | 5918 | mk_pointer(&type); |
| 5921 | type.t |= VT_ARRAY; | 5919 | type.t |= VT_ARRAY; |
| 5922 | type.ref->c = len; | 5920 | type.ref->c = len; |
| 5923 | sec = rodata_section; | 5921 | sec = rodata_section; |
| 5924 | vpush_ref(&type, sec, sec->data_offset, len); | 5922 | vpush_ref(&type, sec, sec->data_offset, len); |
| 5925 | if (!NODATA_WANTED) { | 5923 | if (!NODATA_WANTED) |
| 5926 | ptr = section_ptr_add(sec, len); | 5924 | memcpy(section_ptr_add(sec, len), funcname, len); |
| 5927 | memcpy(ptr, funcname, len); | ||
| 5928 | } | ||
| 5929 | next(); | 5925 | next(); |
| 5930 | } | 5926 | } |
| 5931 | break; | 5927 | break; |
| @@ -5938,11 +5934,9 @@ ST_FUNC void unary(void) · 6 unmodified lines | |||
| 5938 | goto str_init; | 5934 | goto str_init; |
| 5939 | case TOK_STR: | 5935 | case TOK_STR: |
| 5940 | /* string parsing */ | 5936 | /* string parsing */ |
| 5941 | t = VT_BYTE; | 5937 | t = char_type.t; |
| 5942 | if (tcc_state->char_is_unsigned) | ||
| 5943 | t = VT_BYTE | VT_UNSIGNED; | ||
| 5944 | str_init: | 5938 | str_init: |
| 5945 | if (NEED_WARNING(tcc_state, WRITE_STRINGS)) | 5939 | if (tcc_state->warn_write_strings & WARN_ON) |
| 5946 | t |= VT_CONSTANT; | 5940 | t |= VT_CONSTANT; |
| 5947 | type.t = t; | 5941 | type.t = t; |
| 5948 | mk_pointer(&type); | 5942 | mk_pointer(&type); |
| @@ -6378,14 +6372,8 @@ special_math_val: · 429 unmodified lines | |||
| 6378 | tcc_error("'%s' undeclared", name); | 6372 | tcc_error("'%s' undeclared", name); |
| 6379 | /* for simple function calls, we tolerate undeclared | 6373 | /* for simple function calls, we tolerate undeclared |
| 6380 | external reference to int() function */ | 6374 | external reference to int() function */ |
| 6381 | if (NEED_WARNING(tcc_state, IMPLICIT_FUNCTION_DECLARATION) | 6375 | tcc_warning_c(warn_implicit_function_declaration)( |
| 6382 | #ifdef TCC_TARGET_PE | 6376 | "implicit declaration of function '%s'", name); |
| 6383 | /* must warn about using undeclared WINAPI functions | ||
| 6384 | (which usually start with uppercase letter) */ | ||
| 6385 | || (name[0] >= 'A' && name[0] <= 'Z') | ||
| 6386 | #endif | ||
| 6387 | ) | ||
| 6388 | tcc_warning("implicit declaration of function '%s'", name); | ||
| 6389 | s = external_global_sym(t, &func_old_type); | 6377 | s = external_global_sym(t, &func_old_type); |
| 6390 | } | 6378 | } |
| 6391 | 6379 | ||
| @@ -7650,12 +7638,10 @@ again: · 1258 unmodified lines | |||
| 7650 | 7638 | ||
| 7651 | block_after_label: | 7639 | block_after_label: |
| 7652 | vla_restore(cur_scope->vla.loc); | 7640 | vla_restore(cur_scope->vla.loc); |
| 7653 | /* we accept this, but it is a mistake */ | 7641 | if (tok != '}') |
| 7654 | if (tok == '}') { | ||
| 7655 | tcc_warning("deprecated use of label at end of compound statement"); | ||
| 7656 | } else { | ||
| 7657 | goto again; | 7642 | goto again; |
| 7658 | } | 7643 | /* we accept this, but it is a mistake */ |
| 7644 | tcc_warning_c(warn_all)("deprecated use of label at end of compound statement"); | ||
| 7659 | 7645 | ||
| 7660 | } else { | 7646 | } else { |
| 7661 | /* expression case */ | 7647 | /* expression case */ |
| @@ -1435,7 +1435,7 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep) · 1434 unmodified lines | |||
| 1435 | for(s = *ptop; s != slast; s = s1) { | 1435 | for(s = *ptop; s != slast; s = s1) { |
| 1436 | s1 = s->prev; | 1436 | s1 = s->prev; |
| 1437 | if (s->r == LABEL_DECLARED) { | 1437 | if (s->r == LABEL_DECLARED) { |
| 1438 | tcc_warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); | 1438 | tcc_warning_c(warn_all)("label '%s' declared but not used", get_tok_str(s->v, NULL)); |
| 1439 | } else if (s->r == LABEL_FORWARD) { | 1439 | } else if (s->r == LABEL_FORWARD) { |
| 1440 | tcc_error("label '%s' used but not defined", | 1440 | tcc_error("label '%s' used but not defined", |
| 1441 | get_tok_str(s->v, NULL)); | 1441 | get_tok_str(s->v, NULL)); |
| @@ -1770,8 +1770,8 @@ static void pragma_parse(TCCState *s1) · 328 unmodified lines | |||
| 1770 | tcc_free(p); | 1770 | tcc_free(p); |
| 1771 | } | 1771 | } |
| 1772 | 1772 | ||
| 1773 | } else if (NEED_WARNING(s1, UNSUPPORTED)) | 1773 | } else |
| 1774 | tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc)); | 1774 | tcc_warning_c(warn_unsupported)("#pragma %s ignored", get_tok_str(tok, &tokc)); |
| 1775 | return; | 1775 | return; |
| 1776 | 1776 | ||
| 1777 | pragma_err: | 1777 | pragma_err: |
| @@ -2293,7 +2293,7 @@ static void parse_string(const char *s, int len) · 515 unmodified lines | |||
| 2293 | if (n < 1) | 2293 | if (n < 1) |
| 2294 | tcc_error("empty character constant"); | 2294 | tcc_error("empty character constant"); |
| 2295 | if (n > 1) | 2295 | if (n > 1) |
| 2296 | tcc_warning("multi-character character constant"); | 2296 | tcc_warning_c(warn_all)("multi-character character constant"); |
| 2297 | for (c = i = 0; i < n; ++i) { | 2297 | for (c = i = 0; i < n; ++i) { |
| 2298 | if (is_long) | 2298 | if (is_long) |
| 2299 | c = ((nwchar_t *)tokcstr.data)[i]; | 2299 | c = ((nwchar_t *)tokcstr.data)[i]; |
| @@ -399,4 +399,21 @@ int array[] = { 1, 2, 3 }; · 398 unmodified lines | |||
| 399 | void v() {} | 399 | void v() {} |
| 400 | int f() { return v(); } | 400 | int f() { return v(); } |
| 401 | 401 | ||
| 402 | #elif defined test_switch_W1 || defined test_switch_W2 \ | ||
| 403 | || defined test_switch_W3 || defined test_switch_W4 | ||
| 404 | #if defined test_switch_W1 | ||
| 405 | #pragma comment(option, "-Wall") | ||
| 406 | #elif defined test_switch_W2 | ||
| 407 | #pragma comment(option, "-Wunsupported -Wno-implicit-function-declaration -Wstuff") | ||
| 408 | #elif defined test_switch_W3 | ||
| 409 | #pragma comment(option, "-Wwrite-strings -Werror=discarded-qualifiers") | ||
| 410 | #elif defined test_switch_W4 | ||
| 411 | #pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror") | ||
| 412 | #endif | ||
| 413 | void func() | ||
| 414 | { | ||
| 415 | char *ccp = "123"; | ||
| 416 | fink(); | ||
| 417 | } | ||
| 418 | __attribute__((stuff)) int fink() {return 0;} | ||
| 402 | #endif | 419 | #endif |
| @@ -189,3 +189,17 @@ bar : 3 ; 3 · 188 unmodified lines | |||
| 189 | 189 | ||
| 190 | [test_cast_from_void] | 190 | [test_cast_from_void] |
| 191 | 60_errors_and_warnings.c:400: error: cannot convert 'void' to 'int' | 191 | 60_errors_and_warnings.c:400: error: cannot convert 'void' to 'int' |
| 192 | |||
| 193 | [test_switch_W1] | ||
| 194 | 60_errors_and_warnings.c:416: warning: implicit declaration of function 'fink' | ||
| 195 | |||
| 196 | [test_switch_W2] | ||
| 197 | 60_errors_and_warnings.c:407: warning: unsupported option '-Wstuff' | ||
| 198 | 60_errors_and_warnings.c:418: warning: 'stuff' attribute ignored | ||
| 199 | |||
| 200 | [test_switch_W3] | ||
| 201 | 60_errors_and_warnings.c:415: error: assignment discards qualifiers from pointer target type | ||
| 202 | |||
| 203 | [test_switch_W4] | ||
| 204 | 60_errors_and_warnings.c:416: warning: implicit declaration of function 'fink' | ||
| 205 | 60_errors_and_warnings.c:418: error: 'stuff' attribute ignored | ||