-W[no-]error=X: gcc compat: when disabling X again, do not unset the warning

This commit is contained in:
Steffen Nurpmeso 2021-07-27 19:48:29 +02:00
parent b1d9de6794
commit 0c16762418
6 changed files with 74 additions and 51 deletions

View File

@ -786,7 +786,7 @@ LIBTCCAPI TCCState *tcc_new(void)
s->nocommon = 1; s->nocommon = 1;
s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/ s->dollars_in_identifiers = 1; /*on by default like in gcc/clang*/
s->cversion = 199901; /* default unless -std=c11 is supplied */ 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; s->ms_extensions = 1;
#ifdef CHAR_IS_UNSIGNED #ifdef CHAR_IS_UNSIGNED
@ -1280,46 +1280,70 @@ ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name)
return ret; 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; static struct a_W_flag{
const FlagDef *p; 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; const char *r, *sub;
value = 1; mode = 1;
r = optarg; r = optarg;
if (no_flag(&r)) if (no_flag(&r))
value = 0; mode = 0;
if ((sub = strchr(r, '=')) != NULL) { if ((sub = strchr(r, '=')) != NULL) {
if (strncmp(r, "error", (uintptr_t)(sub - r))) if (strncmp(r, "error", (uintptr_t)(sub - r)))
return -1; return -1;
r = ++sub; r = ++sub;
if (value) mode |= 2;
value = 1 | 2;
} }
/* .offset for "all" is 0 */ for (ret = -1, p = opts; p < &opts[countof(opts)]; ++p) {
for (ret = -1, p = flags; p->name; ++p) {
if (ret) { if (ret) {
if (strcmp(r, p->name)) if (strcmp(r, p->name))
continue; continue;
if (sub != NULL && !(p->flags & WD_ERROR)) if ((mode & 2) && !(p->flags & WD_ERROR))
break; break;
} else { } else {
if (0 == (p->flags & WD_ALL)) if (0 == (p->flags & WD_ALL))
continue; continue;
} }
if (p->offset) {
*((unsigned char *)s + p->offset) = value; if (p->wbit == WARN_ALL) {
if (ret) { /* Start a loop over all the rest */
ret = 0;
break;
}
} else {
ret = 0; 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; return ret;
} }
@ -1513,7 +1537,7 @@ static int tcc_set_linker(TCCState *s, const char *option)
tcc_error("unsupported linker option '%s'", 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); tcc_warning("unsupported linker option '%s'", option);
option = skip_linker_arg(&p); option = skip_linker_arg(&p);
@ -1658,18 +1682,6 @@ static const TCCOption tcc_options[] = {
{ NULL, 0, 0 }, { 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[] = { static const FlagDef options_f[] = {
{ offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" }, { offsetof(TCCState, char_is_unsigned), 0, "unsigned-char" },
{ offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" }, { offsetof(TCCState, char_is_unsigned), FD_INVERT, "signed-char" },
@ -1965,7 +1977,7 @@ reparse:
break; break;
case TCC_OPTION_W: case TCC_OPTION_W:
s->warn_none = 0; 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; goto unsupported_option;
break; break;
case TCC_OPTION_w: case TCC_OPTION_w:
@ -2052,7 +2064,7 @@ reparse:
break; break;
default: default:
unsupported_option: unsupported_option:
if (NEED_WARNING(s, unsupported)) if (NEED_WARNING(s, UNSUPPORTED))
tcc_warning("unsupported option '%s'", r); tcc_warning("unsupported option '%s'", r);
break; break;
} }

View File

@ -270,7 +270,8 @@ Make string constants be of type @code{const char *} instead of @code{char
Abort compilation if a warning is issued. Abort compilation if a warning is issued.
Can be given an option to enable the specified warning Can be given an option to enable the specified warning
and turn it into an error, for example @option{-Werror=unsupported}. 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 @item -Wall
Activate all warnings, except @option{-Werror}, @option{-Wunsupported} and Activate all warnings, except @option{-Werror}, @option{-Wunsupported} and

26
tcc.h
View File

@ -737,6 +737,18 @@ struct sym_attr {
#endif #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 { struct TCCState {
unsigned char verbose; /* if true, display some information during compilation */ unsigned char verbose; /* if true, display some information during compilation */
unsigned char nostdinc; /* if true, no standard headers are added */ 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 dollars_in_identifiers; /* allows '$' char in identifiers */
unsigned char ms_bitfields; /* if true, emulate MS algorithm for aligning bitfields */ 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_none;
unsigned char warn_error; unsigned char warn_error;
unsigned char warn_unsupported; /* NEED_WARNING(SELF,X) used to drive W[[no-]error]=X */
unsigned char warn_gcc_compat; uint32_t warn_mask;
unsigned char warn_write_strings;
unsigned char warn_implicit_function_declaration;
#define NEED_WARNING(SELF,SWITCH) \ #define NEED_WARNING(SELF,SWITCH) \
((SELF)->warn_ ## SWITCH \ (((SELF)->warn_mask & \
? (((SELF)->warn_ ## SWITCH & 2) ? (SELF)->warn_error = 1 : 1) : 0) (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) */ /* compile with debug symbol (and use them if error during execution) */
unsigned char do_debug; unsigned char do_debug;

View File

@ -775,7 +775,7 @@ static void asm_parse_directive(TCCState *s1, int global)
else else
pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); 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); tcc_warning("ignoring .file %s", filename);
next(); next();
@ -793,7 +793,7 @@ static void asm_parse_directive(TCCState *s1, int global)
else else
pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); 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); tcc_warning("ignoring .ident %s", ident);
next(); next();
@ -810,7 +810,7 @@ static void asm_parse_directive(TCCState *s1, int global)
} }
/* XXX .size name,label2-label1 */ /* 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)); tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL));
next(); next();
@ -840,7 +840,7 @@ static void asm_parse_directive(TCCState *s1, int global)
if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) { if (!strcmp(newtype, "function") || !strcmp(newtype, "STT_FUNC")) {
sym->type.t = (sym->type.t & ~VT_BTYPE) | VT_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", tcc_warning("change type of '%s' from 0x%x to '%s' ignored",
get_tok_str(sym->v, NULL), sym->type.t, newtype); get_tok_str(sym->v, NULL), sym->type.t, newtype);

View File

@ -4506,7 +4506,7 @@ redo:
ad->a.dllimport = 1; ad->a.dllimport = 1;
break; break;
default: default:
if (NEED_WARNING(tcc_state, unsupported)) if (NEED_WARNING(tcc_state, UNSUPPORTED))
tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL)); tcc_warning("'%s' attribute ignored", get_tok_str(t, NULL));
/* skip parameters */ /* skip parameters */
if (tok == '(') { if (tok == '(') {
@ -5915,7 +5915,7 @@ ST_FUNC void unary(void)
len = strlen(funcname) + 1; len = strlen(funcname) + 1;
/* generate char[len] type */ /* generate char[len] type */
type.t = VT_BYTE; type.t = VT_BYTE;
if (NEED_WARNING(tcc_state, write_strings)) if (NEED_WARNING(tcc_state, WRITE_STRINGS))
type.t |= VT_CONSTANT; type.t |= VT_CONSTANT;
mk_pointer(&type); mk_pointer(&type);
type.t |= VT_ARRAY; type.t |= VT_ARRAY;
@ -5942,7 +5942,7 @@ ST_FUNC void unary(void)
if (tcc_state->char_is_unsigned) if (tcc_state->char_is_unsigned)
t = VT_BYTE | VT_UNSIGNED; t = VT_BYTE | VT_UNSIGNED;
str_init: str_init:
if (NEED_WARNING(tcc_state, write_strings)) if (NEED_WARNING(tcc_state, WRITE_STRINGS))
t |= VT_CONSTANT; t |= VT_CONSTANT;
type.t = t; type.t = t;
mk_pointer(&type); mk_pointer(&type);
@ -6378,7 +6378,7 @@ special_math_val:
tcc_error("'%s' undeclared", name); tcc_error("'%s' undeclared", name);
/* for simple function calls, we tolerate undeclared /* for simple function calls, we tolerate undeclared
external reference to int() function */ 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 #ifdef TCC_TARGET_PE
/* must warn about using undeclared WINAPI functions /* must warn about using undeclared WINAPI functions
(which usually start with uppercase letter) */ (which usually start with uppercase letter) */

View File

@ -1770,7 +1770,7 @@ static void pragma_parse(TCCState *s1)
tcc_free(p); 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)); tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc));
return; return;