From 0c16762418c6c09fa78f968bc64f65c3cc7009f7 Mon Sep 17 00:00:00 2001 From: Steffen Nurpmeso Date: Tue, 27 Jul 2021 19:48:29 +0200 Subject: [PATCH] -W[no-]error=X: gcc compat: when disabling X again, do not unset the warning --- libtcc.c | 78 ++++++++++++++++++++++++++++++---------------------- tcc-doc.texi | 3 +- tcc.h | 26 ++++++++++++------ tccasm.c | 8 +++--- tccgen.c | 8 +++--- tccpp.c | 2 +- 6 files changed, 74 insertions(+), 51 deletions(-) diff --git a/libtcc.c b/libtcc.c index 2bb54290..65ceef05 100644 --- a/libtcc.c +++ b/libtcc.c @@ -786,7 +786,7 @@ LIBTCCAPI TCCState *tcc_new(void) s->nocommon = 1; s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/ s->cversion = 199901; /* default unless -std=c11 is supplied */ - s->warn_implicit_function_declaration = 1; + s->warn_mask |= WARN_IMPLICIT_FUNCTION_DECLARATION; s->ms_extensions = 1; #ifdef CHAR_IS_UNSIGNED @@ -1280,46 +1280,70 @@ ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name) return ret; } -ST_FUNC int set_W_flag(TCCState *s, const FlagDef *flags, const char *optarg) +ST_FUNC int set_W_flag(TCCState *s, const char *optarg) { - int value, ret; - const FlagDef *p; + static struct a_W_flag{ + uint32_t wbit; + uint32_t flags; + char const *name; + } const opts[] = { + {WARN_ALL, 0, "all"}, + {WARN_ERROR, 0, "error"}, + {WARN_UNSUPPORTED, WD_ERROR, "unsupported"}, + {WARN_GCC_COMPAT, WD_ERROR, "gcc-compat"}, + {WARN_WRITE_STRINGS, WD_ERROR | WD_ALL, "write-strings"}, + {WARN_IMPLICIT_FUNCTION_DECLARATION, WD_ERROR | WD_ALL, + "implicit-function-declaration"} + }, *p; + + int ret; + unsigned char mode; const char *r, *sub; - value = 1; + mode = 1; r = optarg; if (no_flag(&r)) - value = 0; + mode = 0; if ((sub = strchr(r, '=')) != NULL) { if (strncmp(r, "error", (uintptr_t)(sub - r))) return -1; r = ++sub; - if (value) - value = 1 | 2; + mode |= 2; } - /* .offset for "all" is 0 */ - for (ret = -1, p = flags; p->name; ++p) { + for (ret = -1, p = opts; p < &opts[countof(opts)]; ++p) { if (ret) { if (strcmp(r, p->name)) continue; - if (sub != NULL && !(p->flags & WD_ERROR)) + if ((mode & 2) && !(p->flags & WD_ERROR)) break; } else { if (0 == (p->flags & WD_ALL)) continue; } - if (p->offset) { - *((unsigned char *)s + p->offset) = value; - if (ret) { - ret = 0; - break; - } - } else { + + if (p->wbit == WARN_ALL) { + /* Start a loop over all the rest */ ret = 0; + continue; + } + + if (mode & 1) { + s->warn_mask |= p->wbit; + if (mode & 2) + s->warn_mask |= p->wbit << WARN_ERROR_SHIFT; + } else { + s->warn_mask &= ~(p->wbit << ((mode & 2) ? WARN_ERROR_SHIFT : 0)); + } + + /* Done if not in "all" mode */ + if (ret) { + ret = 0; + break; } } + return ret; } @@ -1513,7 +1537,7 @@ static int tcc_set_linker(TCCState *s, const char *option) tcc_error("unsupported linker option '%s'", option); } - if (ignoring && NEED_WARNING(s, unsupported)) + if (ignoring && NEED_WARNING(s, UNSUPPORTED)) tcc_warning("unsupported linker option '%s'", option); option = skip_linker_arg(&p); @@ -1658,18 +1682,6 @@ static const TCCOption tcc_options[] = { { NULL, 0, 0 }, }; -static const FlagDef options_W[] = { - { 0, 0, "all" }, - { offsetof(TCCState, warn_error), 0, "error" }, - { offsetof(TCCState, warn_unsupported), WD_ERROR, "unsupported" }, - { offsetof(TCCState, warn_gcc_compat), WD_ERROR, "gcc-compat" }, - { offsetof(TCCState, warn_write_strings), WD_ERROR | WD_ALL, - "write-strings" }, - { offsetof(TCCState, warn_implicit_function_declaration), - WD_ERROR | WD_ALL, "implicit-function-declaration" }, - { 0, 0, NULL } -}; - static const FlagDef options_f[] = { { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, @@ -1965,7 +1977,7 @@ reparse: break; case TCC_OPTION_W: s->warn_none = 0; - if (optarg[0] && set_W_flag(s, options_W, optarg) < 0) + if (optarg[0] && set_W_flag(s, optarg) < 0) goto unsupported_option; break; case TCC_OPTION_w: @@ -2052,7 +2064,7 @@ reparse: break; default: unsupported_option: - if (NEED_WARNING(s, unsupported)) + if (NEED_WARNING(s, UNSUPPORTED)) tcc_warning("unsupported option '%s'", r); break; } diff --git a/tcc-doc.texi b/tcc-doc.texi index 21adc4f9..34d09b80 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -270,7 +270,8 @@ Make string constants be of type @code{const char *} instead of @code{char Abort compilation if a warning is issued. Can be given an option to enable the specified warning and turn it into an error, for example @option{-Werror=unsupported}. -(Enabling general abortion and disabling specifics is not supported.) +Enabling general abortion and disabling specifics is not supported. +Disabling specific abortions again does not disable the according warning. @item -Wall Activate all warnings, except @option{-Werror}, @option{-Wunsupported} and diff --git a/tcc.h b/tcc.h index 7227a2da..6db8e2d1 100644 --- a/tcc.h +++ b/tcc.h @@ -737,6 +737,18 @@ struct sym_attr { #endif }; +/* 32-bit bit carrier, split in two halves: lower=warn, upper=error */ +enum warn_option { + WARN_NONE, + WARN_UNSUPPORTED = 1u<<0, + WARN_GCC_COMPAT = 1u<<1, + WARN_WRITE_STRINGS = 1u<<2, + WARN_IMPLICIT_FUNCTION_DECLARATION = 1u<<3, + WARN_ERROR = 1u<<4, + WARN_ALL = WARN_ERROR - 1 +}; +enum {WARN_ERROR_SHIFT = 16u}; + struct TCCState { unsigned char verbose; /* if true, display some information during compilation */ unsigned char nostdinc; /* if true, no standard headers are added */ @@ -767,17 +779,15 @@ struct TCCState { unsigned char dollars_in_identifiers; /* allows '$' char in identifiers */ unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ - /* warning switches; but for first two, W[no-]error=X is supported */ - /* XXX TCC_IS_WARN_OR_ERR(X,Y) used to drive W[[no-]error]=X */ unsigned char warn_none; unsigned char warn_error; - unsigned char warn_unsupported; - unsigned char warn_gcc_compat; - unsigned char warn_write_strings; - unsigned char warn_implicit_function_declaration; + /* NEED_WARNING(SELF,X) used to drive W[[no-]error]=X */ + uint32_t warn_mask; #define NEED_WARNING(SELF,SWITCH) \ - ((SELF)->warn_ ## SWITCH \ - ? (((SELF)->warn_ ## SWITCH & 2) ? (SELF)->warn_error = 1 : 1) : 0) + (((SELF)->warn_mask & \ + (WARN_ ## SWITCH | (WARN_ ## SWITCH << WARN_ERROR_SHIFT))) \ + ? (((SELF)->warn_mask & (WARN_ ## SWITCH << WARN_ERROR_SHIFT)) \ + ? (SELF)->warn_error = 1 : 1) : 0) /* compile with debug symbol (and use them if error during execution) */ unsigned char do_debug; diff --git a/tccasm.c b/tccasm.c index a9c4f1b9..c7d2db18 100644 --- a/tccasm.c +++ b/tccasm.c @@ -775,7 +775,7 @@ static void asm_parse_directive(TCCState *s1, int global) else pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); - if (NEED_WARNING(s1, unsupported)) + if (NEED_WARNING(s1, UNSUPPORTED)) tcc_warning("ignoring .file %s", filename); next(); @@ -793,7 +793,7 @@ static void asm_parse_directive(TCCState *s1, int global) else pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); - if (NEED_WARNING(s1, unsupported)) + if (NEED_WARNING(s1, UNSUPPORTED)) tcc_warning("ignoring .ident %s", ident); next(); @@ -810,7 +810,7 @@ static void asm_parse_directive(TCCState *s1, int global) } /* XXX .size name,label2-label1 */ - if (NEED_WARNING(s1, unsupported)) + if (NEED_WARNING(s1, UNSUPPORTED)) tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL)); next(); @@ -840,7 +840,7 @@ static void asm_parse_directive(TCCState *s1, int global) if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_FUNC; } - else if (NEED_WARNING(s1, unsupported)) + else if (NEED_WARNING(s1, UNSUPPORTED)) tcc_warning("change type of '%s' from 0x%x to '%s' ignored", get_tok_str(sym->v, NULL), sym->type.t, newtype); diff --git a/tccgen.c b/tccgen.c index 4bcfbcce..625a6f0c 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4506,7 +4506,7 @@ redo: ad->a.dllimport = 1; break; default: - if (NEED_WARNING(tcc_state, unsupported)) + if (NEED_WARNING(tcc_state, UNSUPPORTED)) tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL)); /* skip parameters */ if (tok == '(') { @@ -5915,7 +5915,7 @@ ST_FUNC void unary(void) len = strlen(funcname) + 1; /* generate char[len] type */ type.t = VT_BYTE; - if (NEED_WARNING(tcc_state, write_strings)) + if (NEED_WARNING(tcc_state, WRITE_STRINGS)) type.t |= VT_CONSTANT; mk_pointer(&type); type.t |= VT_ARRAY; @@ -5942,7 +5942,7 @@ ST_FUNC void unary(void) if (tcc_state->char_is_unsigned) t = VT_BYTE | VT_UNSIGNED; str_init: - if (NEED_WARNING(tcc_state, write_strings)) + if (NEED_WARNING(tcc_state, WRITE_STRINGS)) t |= VT_CONSTANT; type.t = t; mk_pointer(&type); @@ -6378,7 +6378,7 @@ special_math_val: tcc_error("'%s' undeclared", name); /* for simple function calls, we tolerate undeclared external reference to int() function */ - if (NEED_WARNING(tcc_state, implicit_function_declaration) + if (NEED_WARNING(tcc_state, IMPLICIT_FUNCTION_DECLARATION) #ifdef TCC_TARGET_PE /* must warn about using undeclared WINAPI functions (which usually start with uppercase letter) */ diff --git a/tccpp.c b/tccpp.c index afd8fb15..0da656dd 100644 --- a/tccpp.c +++ b/tccpp.c @@ -1770,7 +1770,7 @@ static void pragma_parse(TCCState *s1) tcc_free(p); } - } else if (NEED_WARNING(s1, unsupported)) + } else if (NEED_WARNING(s1, UNSUPPORTED)) tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc)); return;