From a7a13896b33006d6aef6c82a2bffe395a5a652e7 Mon Sep 17 00:00:00 2001 From: Steffen Nurpmeso Date: Tue, 27 Jul 2021 00:36:45 +0200 Subject: [PATCH] Add -W[no-]error=OPTION specific abortions --- libtcc.c | 65 ++++++++++++++++++++++++++++++++++++++++++++-------- tcc-doc.texi | 7 ++++-- tcc.h | 14 +++++++---- tccasm.c | 8 +++---- tccgen.c | 10 ++++---- tccpp.c | 3 +-- 6 files changed, 79 insertions(+), 28 deletions(-) diff --git a/libtcc.c b/libtcc.c index 855550d4..2bb54290 100644 --- a/libtcc.c +++ b/libtcc.c @@ -1230,8 +1230,9 @@ LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path) s->tcc_lib_path = tcc_strdup(path); } -#define WD_ALL 0x0001 /* warning is activated when using -Wall */ -#define FD_INVERT 0x0002 /* invert value before storing */ +#define WD_ALL (1u<<0) /* warning is activated when using -Wall */ +#define WD_ERROR (1u<<1) /* can be used with -W[no-]error=X */ +#define FD_INVERT (1u<<2) /* invert value before storing */ typedef struct FlagDef { uint16_t offset; @@ -1279,6 +1280,49 @@ 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) +{ + int value, ret; + const FlagDef *p; + const char *r, *sub; + + value = 1; + r = optarg; + if (no_flag(&r)) + value = 0; + + if ((sub = strchr(r, '=')) != NULL) { + if (strncmp(r, "error", (uintptr_t)(sub - r))) + return -1; + r = ++sub; + if (value) + value = 1 | 2; + } + + /* .offset for "all" is 0 */ + for (ret = -1, p = flags; p->name; ++p) { + if (ret) { + if (strcmp(r, p->name)) + continue; + if (sub != NULL && !(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 { + ret = 0; + } + } + return ret; +} + static int strstart(const char *val, const char **str) { const char *p, *q; @@ -1469,7 +1513,7 @@ static int tcc_set_linker(TCCState *s, const char *option) tcc_error("unsupported linker option '%s'", option); } - if (ignoring && s->warn_unsupported) + if (ignoring && NEED_WARNING(s, unsupported)) tcc_warning("unsupported linker option '%s'", option); option = skip_linker_arg(&p); @@ -1616,12 +1660,13 @@ static const TCCOption tcc_options[] = { static const FlagDef options_W[] = { { 0, 0, "all" }, - { offsetof(TCCState, warn_unsupported), 0, "unsupported" }, - { offsetof(TCCState, warn_write_strings), WD_ALL, "write-strings" }, { offsetof(TCCState, warn_error), 0, "error" }, - { offsetof(TCCState, warn_gcc_compat), 0, "gcc-compat" }, - { offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, - "implicit-function-declaration" }, + { 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 } }; @@ -1920,7 +1965,7 @@ reparse: break; case TCC_OPTION_W: s->warn_none = 0; - if (optarg[0] && set_flag(s, options_W, optarg) < 0) + if (optarg[0] && set_W_flag(s, options_W, optarg) < 0) goto unsupported_option; break; case TCC_OPTION_w: @@ -2007,7 +2052,7 @@ reparse: break; default: unsupported_option: - if (s->warn_unsupported) + if (NEED_WARNING(s, unsupported)) tcc_warning("unsupported option '%s'", r); break; } diff --git a/tcc-doc.texi b/tcc-doc.texi index cefb8674..21adc4f9 100644 --- a/tcc-doc.texi +++ b/tcc-doc.texi @@ -267,10 +267,13 @@ Make string constants be of type @code{const char *} instead of @code{char *}. @item -Werror -Abort compilation if warnings are issued. +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.) @item -Wall -Activate all warnings, except @option{-Werror}, @option{-Wunusupported} and +Activate all warnings, except @option{-Werror}, @option{-Wunsupported} and @option{-Wwrite-strings}. @end table diff --git a/tcc.h b/tcc.h index 890c8db6..7227a2da 100644 --- a/tcc.h +++ b/tcc.h @@ -767,13 +767,17 @@ 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 */ - unsigned char warn_write_strings; - unsigned char warn_unsupported; - unsigned char warn_error; + /* 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_implicit_function_declaration; + unsigned char warn_error; + unsigned char warn_unsupported; unsigned char warn_gcc_compat; + unsigned char warn_write_strings; + unsigned char warn_implicit_function_declaration; +#define NEED_WARNING(SELF,SWITCH) \ + ((SELF)->warn_ ## SWITCH \ + ? (((SELF)->warn_ ## SWITCH & 2) ? (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 097f41ca..a9c4f1b9 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 (s1->warn_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 (s1->warn_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 (s1->warn_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 (s1->warn_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 c36032ab..4bcfbcce 100644 --- a/tccgen.c +++ b/tccgen.c @@ -4506,7 +4506,7 @@ redo: ad->a.dllimport = 1; break; default: - if (tcc_state->warn_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 (tcc_state->warn_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 (tcc_state->warn_write_strings) + if (NEED_WARNING(tcc_state, write_strings)) t |= VT_CONSTANT; type.t = t; mk_pointer(&type); @@ -6378,9 +6378,9 @@ special_math_val: tcc_error("'%s' undeclared", name); /* for simple function calls, we tolerate undeclared external reference to int() function */ - if (tcc_state->warn_implicit_function_declaration + if (NEED_WARNING(tcc_state, implicit_function_declaration) #ifdef TCC_TARGET_PE - /* people must be warned about using undeclared WINAPI functions + /* must warn about using undeclared WINAPI functions (which usually start with uppercase letter) */ || (name[0] >= 'A' && name[0] <= 'Z') #endif diff --git a/tccpp.c b/tccpp.c index cb56781d..afd8fb15 100644 --- a/tccpp.c +++ b/tccpp.c @@ -1770,9 +1770,8 @@ static void pragma_parse(TCCState *s1) tcc_free(p); } - } else if (s1->warn_unsupported) { + } else if (NEED_WARNING(s1, unsupported)) tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc)); - } return; pragma_err: