-W[no-]error...: features by shrinkage

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
This commit is contained in:
grischka 2021-07-31 20:44:51 +02:00
parent 931a146591
commit 4b2c6cf3a4
9 changed files with 167 additions and 226 deletions

218
libtcc.c
View file

@ -510,10 +510,6 @@ static void strcat_printf(char *buf, int buf_size, const char *fmt, ...)
va_end(ap); va_end(ap);
} }
#define ERROR_WARN 0
#define ERROR_NOABORT 1
#define ERROR_ERROR 2
PUB_FUNC void tcc_enter_state(TCCState *s1) PUB_FUNC void tcc_enter_state(TCCState *s1)
{ {
WAIT_SEM(); WAIT_SEM();
@ -526,6 +522,10 @@ PUB_FUNC void tcc_exit_state(void)
POST_SEM(); POST_SEM();
} }
#define ERROR_WARN 0
#define ERROR_NOABORT 1
#define ERROR_ERROR 2
static void error1(int mode, const char *fmt, va_list ap) static void error1(int mode, const char *fmt, va_list ap)
{ {
char buf[2048]; char buf[2048];
@ -537,15 +537,26 @@ static void error1(int mode, const char *fmt, va_list ap)
/* can happen only if called from tcc_malloc(): 'out of memory' */ /* can happen only if called from tcc_malloc(): 'out of memory' */
goto no_file; goto no_file;
if (s1 && !s1->error_set_jmp_enabled) if (!s1->error_set_jmp_enabled)
/* tcc_state just was set by tcc_enter_state() */ /* tcc_state just was set by tcc_enter_state() */
tcc_exit_state(); tcc_exit_state();
if (mode == ERROR_WARN) { if (mode == ERROR_WARN) {
if (s1->warn_mask & WARN_DISABLED) if (s1->warn_error)
return;
if (s1->warn_mask & WARN_ERROR_MASK) /* XXX individual ignorance */
mode = ERROR_ERROR; mode = ERROR_ERROR;
if (s1->warn_num) {
/* handle tcc_warning_c(warn_option)(fmt, ...) */
int wopt = *(&s1->warn_none + s1->warn_num);
s1->warn_num = 0;
if (0 == (wopt & WARN_ON))
return;
if (wopt & WARN_ERR)
mode = ERROR_ERROR;
if (wopt & WARN_NOE)
mode = ERROR_WARN;
}
if (s1->warn_none)
return;
} }
f = NULL; f = NULL;
@ -786,7 +797,8 @@ 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_mask |= WARN_IMPLICIT_FUNCTION_DECLARATION; s->warn_implicit_function_declaration = 1;
s->warn_discarded_qualifiers = 1;
s->ms_extensions = 1; s->ms_extensions = 1;
#ifdef CHAR_IS_UNSIGNED #ifdef CHAR_IS_UNSIGNED
@ -1230,122 +1242,8 @@ LIBTCCAPI void tcc_set_lib_path(TCCState *s, const char *path)
s->tcc_lib_path = tcc_strdup(path); s->tcc_lib_path = tcc_strdup(path);
} }
#define WD_ALL (1u<<0) /* warning is activated when using -Wall */ /********************************************************/
#define WD_ERROR (1u<<1) /* can be used with -W[no-]error=X */ /* options parser */
#define FD_INVERT (1u<<2) /* invert value before storing */
typedef struct FlagDef {
uint16_t offset;
uint16_t flags;
const char *name;
} FlagDef;
static int no_flag(const char **pp)
{
const char *p = *pp;
if (*p != 'n' || *++p != 'o' || *++p != '-')
return 0;
*pp = p + 1;
return 1;
}
ST_FUNC int set_flag(TCCState *s, const FlagDef *flags, const char *name)
{
int value, ret;
const FlagDef *p;
const char *r;
value = 1;
r = name;
if (no_flag(&r))
value = 0;
for (ret = -1, p = flags; p->name; ++p) {
if (ret) {
if (strcmp(r, p->name))
continue;
} else {
if (0 == (p->flags & WD_ALL))
continue;
}
if (p->offset) {
*((unsigned char *)s + p->offset) =
p->flags & FD_INVERT ? !value : value;
if (ret)
return 0;
} else {
ret = 0;
}
}
return ret;
}
ST_FUNC int set_W_flag(TCCState *s, const char *optarg)
{
static struct a_W_flag{
uint32_t wbit;
uint32_t flags;
char const *name;
} const opts[] = {
{WARN_ALL, 0, "all"},
{WARN_ERROR | (WARN_ERROR << WARN_ERROR_SHIFT), 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;
mode = 1;
r = optarg;
if (no_flag(&r))
mode = 0;
if ((sub = strchr(r, '=')) != NULL) {
if (strncmp(r, "error", (uintptr_t)(sub - r)))
return -1;
r = ++sub;
mode |= 2;
}
for (ret = -1, p = opts; p < &opts[countof(opts)]; ++p) {
if (ret) {
if (strcmp(r, p->name))
continue;
if ((mode & 2) && !(p->flags & WD_ERROR))
break;
} else {
if (0 == (p->flags & WD_ALL))
continue;
}
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;
}
static int strstart(const char *val, const char **str) static int strstart(const char *val, const char **str)
{ {
@ -1388,7 +1286,7 @@ static int link_option(const char *str, const char *val, const char **ptr)
ret = 1; ret = 1;
if (q[0] == '?') { if (q[0] == '?') {
++q; ++q;
if (no_flag(&p)) if (strstart("no-", &p))
ret = -1; ret = -1;
} }
@ -1536,10 +1434,8 @@ static int tcc_set_linker(TCCState *s, const char *option)
err: err:
tcc_error("unsupported linker option '%s'", option); tcc_error("unsupported linker option '%s'", option);
} }
if (ignoring)
if (ignoring && NEED_WARNING(s, UNSUPPORTED)) tcc_warning_c(warn_unsupported)("unsupported linker option '%s'", option);
tcc_warning("unsupported linker option '%s'", option);
option = skip_linker_arg(&p); option = skip_linker_arg(&p);
} }
return 1; return 1;
@ -1682,6 +1578,25 @@ static const TCCOption tcc_options[] = {
{ NULL, 0, 0 }, { NULL, 0, 0 },
}; };
typedef struct FlagDef {
uint16_t offset;
uint16_t flags;
const char *name;
} FlagDef;
#define WD_ALL 0x0001 /* warning is activated when using -Wall */
#define FD_INVERT 0x0002 /* invert value before storing */
static const FlagDef options_W[] = {
{ offsetof(TCCState, warn_all), WD_ALL, "all" },
{ offsetof(TCCState, warn_error), 0, "error" },
{ offsetof(TCCState, warn_write_strings), 0, "write-strings" },
{ offsetof(TCCState, warn_unsupported), 0, "unsupported" },
{ offsetof(TCCState, warn_implicit_function_declaration), WD_ALL, "implicit-function-declaration" },
{ offsetof(TCCState, warn_discarded_qualifiers), WD_ALL, "discarded-qualifiers" },
{ 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" },
@ -1701,6 +1616,40 @@ static const FlagDef options_m[] = {
{ 0, 0, NULL } { 0, 0, NULL }
}; };
static int set_flag(TCCState *s, const FlagDef *flags, const char *name)
{
int value, mask, ret;
const FlagDef *p;
const char *r;
unsigned char *f;
r = name, value = !strstart("no-", &r), mask = 0;
/* when called with options_W, look for -W[no-]error=<option> */
if ((flags->flags & WD_ALL) && strstart("error=", &r))
value = value ? WARN_ON|WARN_ERR : WARN_NOE, mask = WARN_ON;
for (ret = -1, p = flags; p->name; ++p) {
if (ret) {
if (strcmp(r, p->name))
continue;
} else {
if (0 == (p->flags & WD_ALL))
continue;
}
f = (unsigned char *)s + p->offset;
*f = (*f & mask) | (value ^ !!(p->flags & FD_INVERT));
if (ret) {
ret = 0;
if (strcmp(r, "all"))
break;
}
}
return ret;
}
static void args_parser_add_file(TCCState *s, const char* filename, int filetype) static void args_parser_add_file(TCCState *s, const char* filename, int filetype)
{ {
struct filespec *f = tcc_malloc(sizeof *f + strlen(filename)); struct filespec *f = tcc_malloc(sizeof *f + strlen(filename));
@ -1976,12 +1925,12 @@ reparse:
} }
break; break;
case TCC_OPTION_W: case TCC_OPTION_W:
s->warn_mask &= ~WARN_DISABLED; s->warn_none = 0;
if (optarg[0] && set_W_flag(s, optarg) < 0) if (optarg[0] && set_flag(s, options_W, optarg) < 0)
goto unsupported_option; goto unsupported_option;
break; break;
case TCC_OPTION_w: case TCC_OPTION_w:
s->warn_mask |= WARN_DISABLED; s->warn_none = 1;
break; break;
case TCC_OPTION_rdynamic: case TCC_OPTION_rdynamic:
s->rdynamic = 1; s->rdynamic = 1;
@ -2064,8 +2013,7 @@ reparse:
break; break;
default: default:
unsupported_option: unsupported_option:
if (NEED_WARNING(s, UNSUPPORTED)) tcc_warning_c(warn_unsupported)("unsupported option '%s'", r);
tcc_warning("unsupported option '%s'", r);
break; break;
} }
} }

View file

@ -267,15 +267,12 @@ Make string constants be of type @code{const char *} instead of @code{char
*}. *}.
@item -Werror @item -Werror
Abort compilation if a warning is issued. Abort compilation if a warning is issued. Can be given an option to enable
Can be given an option to enable the specified warning the specified warning and turn it into an error, for example
and turn it into an error, for example @option{-Werror=unsupported}. @option{-Werror=unsupported}.
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 some useful warnings.
@option{-Wwrite-strings}.
@end table @end table

13
tcc.c
View file

@ -36,7 +36,7 @@ static const char help[] =
" -std=c99 Conform to the ISO 1999 C standard (default).\n" " -std=c99 Conform to the ISO 1999 C standard (default).\n"
" -std=c11 Conform to the ISO 2011 C standard.\n" " -std=c11 Conform to the ISO 2011 C standard.\n"
" -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n" " -Wwarning set or reset (with 'no-' prefix) 'warning' (see tcc -hh)\n"
" -w disable all warnings and their consequences\n" " -w disable all warnings\n"
" --version -v show version\n" " --version -v show version\n"
" -vv show search paths or loaded files\n" " -vv show search paths or loaded files\n"
" -h -hh show this, show more help\n" " -h -hh show this, show more help\n"
@ -103,10 +103,11 @@ static const char help2[] =
" --param -pedantic -pipe -s -traditional\n" " --param -pedantic -pipe -s -traditional\n"
"-W[no-]... warnings:\n" "-W[no-]... warnings:\n"
" all turn on some (*) warnings\n" " all turn on some (*) warnings\n"
" error[=(X)] error out after first warning (for X)\n" " error[=warning] stop after warning (any or specified)\n"
" unsupported warn for ignored options, pragmas,.. (X)\n" " write-strings strings are const\n"
" write-strings strings are const (*,X)\n" " unsupported warn about ignored options, pragmas, etc.\n"
" implicit-function-declaration warn for missing prototype (*,X)\n" " implicit-function-declaration warn for missing prototype (*)\n"
" discarded-qualifiers warn when const is dropped (*)\n"
"-f[no-]... flags:\n" "-f[no-]... flags:\n"
" unsigned-char default char is unsigned\n" " unsigned-char default char is unsigned\n"
" signed-char default char is signed\n" " signed-char default char is signed\n"
@ -317,7 +318,7 @@ redo:
} }
if (s->nb_files == 0) if (s->nb_files == 0)
tcc_error("no input files\n"); tcc_error("no input files");
if (s->output_type == TCC_OUTPUT_PREPROCESS) { if (s->output_type == TCC_OUTPUT_PREPROCESS) {
if (s->outfile && 0!=strcmp("-",s->outfile)) { if (s->outfile && 0!=strcmp("-",s->outfile)) {

44
tcc.h
View file

@ -737,24 +737,6 @@ 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,
/* _ERROR is in lower as "max", there is no warning for it */
WARN_ERROR = 1u<<4,
WARN_ALL = WARN_ERROR - 1,
/* Is neither in lower nor upper: disables warnings and errors (-w) */
WARN_DISABLED = WARN_ERROR << 1
};
enum {
WARN_ERROR_SHIFT = 16u,
WARN_ERROR_MASK = (/*WARN_ALL |*/ WARN_ERROR) << WARN_ERROR_SHIFT
};
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 */
@ -785,13 +767,18 @@ 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 */
/* NEED_WARNING(SELF,X) used to drive W[[no-]error]=X */ /* warning switches */
uint32_t warn_mask; unsigned char warn_none;
#define NEED_WARNING(SELF,SWITCH) \ unsigned char warn_all;
(((SELF)->warn_mask & \ unsigned char warn_error;
(WARN_ ## SWITCH | (WARN_ ## SWITCH << WARN_ERROR_SHIFT))) \ unsigned char warn_write_strings;
? (((SELF)->warn_mask & (WARN_ ## SWITCH << WARN_ERROR_SHIFT)) \ unsigned char warn_unsupported;
? (SELF)->warn_mask |= (WARN_ERROR << WARN_ERROR_SHIFT), 1 : 1) : 0) unsigned char warn_implicit_function_declaration;
unsigned char warn_discarded_qualifiers;
#define WARN_ON 1 /* warning is on (-Woption) */
#define WARN_ERR 2 /* warning is an error (-Werror=option) */
#define WARN_NOE 4 /* warning is not an error (-Wno-error=option) */
unsigned char warn_num; /* temp var for tcc_warning_c() */
/* 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;
@ -1890,6 +1877,11 @@ ST_FUNC void gen_makedeps(TCCState *s, const char *target, const char *filename)
PUB_FUNC void tcc_enter_state(TCCState *s1); PUB_FUNC void tcc_enter_state(TCCState *s1);
PUB_FUNC void tcc_exit_state(void); PUB_FUNC void tcc_exit_state(void);
/* conditional warning depending on switch */
#define tcc_warning_c(sw) TCC_SET_STATE((\
tcc_state->warn_num = offsetof(TCCState, sw) \
- offsetof(TCCState, warn_none), _tcc_warning))
/********************************************************/ /********************************************************/
#endif /* _TCC_H */ #endif /* _TCC_H */
@ -1903,6 +1895,4 @@ PUB_FUNC void tcc_exit_state(void);
#else #else
# define TCC_STATE_VAR(sym) s1->sym # define TCC_STATE_VAR(sym) s1->sym
# define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn) # define TCC_SET_STATE(fn) (tcc_enter_state(s1),fn)
/* actually we could avoid the tcc_enter_state(s1) hack by using
__VA_ARGS__ except that some compiler doesn't support it. */
#endif #endif

View file

@ -769,15 +769,11 @@ static void asm_parse_directive(TCCState *s1, int global)
filename[0] = '\0'; filename[0] = '\0';
next(); next();
if (tok == TOK_STR) if (tok == TOK_STR)
pstrcat(filename, sizeof(filename), tokc.str.data); pstrcat(filename, sizeof(filename), tokc.str.data);
else else
pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL)); pstrcat(filename, sizeof(filename), get_tok_str(tok, NULL));
tcc_warning_c(warn_unsupported)("ignoring .file %s", filename);
if (NEED_WARNING(s1, UNSUPPORTED))
tcc_warning("ignoring .file %s", filename);
next(); next();
} }
break; break;
@ -787,15 +783,11 @@ static void asm_parse_directive(TCCState *s1, int global)
ident[0] = '\0'; ident[0] = '\0';
next(); next();
if (tok == TOK_STR) if (tok == TOK_STR)
pstrcat(ident, sizeof(ident), tokc.str.data); pstrcat(ident, sizeof(ident), tokc.str.data);
else else
pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL)); pstrcat(ident, sizeof(ident), get_tok_str(tok, NULL));
tcc_warning_c(warn_unsupported)("ignoring .ident %s", ident);
if (NEED_WARNING(s1, UNSUPPORTED))
tcc_warning("ignoring .ident %s", ident);
next(); next();
} }
break; break;
@ -808,11 +800,8 @@ static void asm_parse_directive(TCCState *s1, int global)
if (!sym) { if (!sym) {
tcc_error("label not found: %s", get_tok_str(tok, NULL)); tcc_error("label not found: %s", get_tok_str(tok, NULL));
} }
/* XXX .size name,label2-label1 */ /* XXX .size name,label2-label1 */
if (NEED_WARNING(s1, UNSUPPORTED)) tcc_warning_c(warn_unsupported)("ignoring .size %s,*", get_tok_str(tok, NULL));
tcc_warning("ignoring .size %s,*", get_tok_str(tok, NULL));
next(); next();
skip(','); skip(',');
while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) { while (tok != TOK_LINEFEED && tok != ';' && tok != CH_EOF) {
@ -839,9 +828,8 @@ 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
else if (NEED_WARNING(s1, UNSUPPORTED)) tcc_warning_c(warn_unsupported)("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);
next(); next();

View file

@ -4077,7 +4077,7 @@ static void verify_assign_cast(CType *dt)
} }
} }
if (qualwarn) if (qualwarn)
tcc_warning("assignment discards qualifiers from pointer target type"); tcc_warning_c(warn_discarded_qualifiers)("assignment discards qualifiers from pointer target type");
break; break;
case VT_BYTE: case VT_BYTE:
case VT_SHORT: case VT_SHORT:
@ -4355,8 +4355,8 @@ redo:
skip('('); skip('(');
s = sym_find(tok); s = sym_find(tok);
if (!s) { if (!s) {
tcc_warning("implicit declaration of function '%s'", tcc_warning_c(warn_implicit_function_declaration)(
get_tok_str(tok, &tokc)); "implicit declaration of function '%s'", get_tok_str(tok, &tokc));
s = external_global_sym(tok, &func_old_type); s = external_global_sym(tok, &func_old_type);
} else if ((s->type.t & VT_BTYPE) != VT_FUNC) } else if ((s->type.t & VT_BTYPE) != VT_FUNC)
tcc_error("'%s' is not declared as function", get_tok_str(tok, &tokc)); tcc_error("'%s' is not declared as function", get_tok_str(tok, &tokc));
@ -4506,8 +4506,7 @@ redo:
ad->a.dllimport = 1; ad->a.dllimport = 1;
break; break;
default: default:
if (NEED_WARNING(tcc_state, UNSUPPORTED)) tcc_warning_c(warn_unsupported)("'%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 == '(') {
int parenthesis = 0; int parenthesis = 0;
@ -5909,23 +5908,20 @@ ST_FUNC void unary(void)
case TOK___FUNC__: case TOK___FUNC__:
{ {
Section *sec; Section *sec;
void *ptr;
int len; int len;
/* special function name identifier */ /* special function name identifier */
len = strlen(funcname) + 1; len = strlen(funcname) + 1;
/* generate char[len] type */ /* generate char[len] type */
type.t = VT_BYTE; type.t = char_type.t;
if (NEED_WARNING(tcc_state, WRITE_STRINGS)) if (tcc_state->warn_write_strings & WARN_ON)
type.t |= VT_CONSTANT; type.t |= VT_CONSTANT;
mk_pointer(&type); mk_pointer(&type);
type.t |= VT_ARRAY; type.t |= VT_ARRAY;
type.ref->c = len; type.ref->c = len;
sec = rodata_section; sec = rodata_section;
vpush_ref(&type, sec, sec->data_offset, len); vpush_ref(&type, sec, sec->data_offset, len);
if (!NODATA_WANTED) { if (!NODATA_WANTED)
ptr = section_ptr_add(sec, len); memcpy(section_ptr_add(sec, len), funcname, len);
memcpy(ptr, funcname, len);
}
next(); next();
} }
break; break;
@ -5938,11 +5934,9 @@ ST_FUNC void unary(void)
goto str_init; goto str_init;
case TOK_STR: case TOK_STR:
/* string parsing */ /* string parsing */
t = VT_BYTE; t = char_type.t;
if (tcc_state->char_is_unsigned)
t = VT_BYTE | VT_UNSIGNED;
str_init: str_init:
if (NEED_WARNING(tcc_state, WRITE_STRINGS)) if (tcc_state->warn_write_strings & WARN_ON)
t |= VT_CONSTANT; t |= VT_CONSTANT;
type.t = t; type.t = t;
mk_pointer(&type); mk_pointer(&type);
@ -6378,14 +6372,8 @@ 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) tcc_warning_c(warn_implicit_function_declaration)(
#ifdef TCC_TARGET_PE "implicit declaration of function '%s'", name);
/* must warn about using undeclared WINAPI functions
(which usually start with uppercase letter) */
|| (name[0] >= 'A' && name[0] <= 'Z')
#endif
)
tcc_warning("implicit declaration of function '%s'", name);
s = external_global_sym(t, &func_old_type); s = external_global_sym(t, &func_old_type);
} }
@ -7650,12 +7638,10 @@ again:
block_after_label: block_after_label:
vla_restore(cur_scope->vla.loc); vla_restore(cur_scope->vla.loc);
/* we accept this, but it is a mistake */ if (tok != '}')
if (tok == '}') {
tcc_warning("deprecated use of label at end of compound statement");
} else {
goto again; goto again;
} /* we accept this, but it is a mistake */
tcc_warning_c(warn_all)("deprecated use of label at end of compound statement");
} else { } else {
/* expression case */ /* expression case */

View file

@ -1435,7 +1435,7 @@ ST_FUNC void label_pop(Sym **ptop, Sym *slast, int keep)
for(s = *ptop; s != slast; s = s1) { for(s = *ptop; s != slast; s = s1) {
s1 = s->prev; s1 = s->prev;
if (s->r == LABEL_DECLARED) { if (s->r == LABEL_DECLARED) {
tcc_warning("label '%s' declared but not used", get_tok_str(s->v, NULL)); tcc_warning_c(warn_all)("label '%s' declared but not used", get_tok_str(s->v, NULL));
} else if (s->r == LABEL_FORWARD) { } else if (s->r == LABEL_FORWARD) {
tcc_error("label '%s' used but not defined", tcc_error("label '%s' used but not defined",
get_tok_str(s->v, NULL)); get_tok_str(s->v, NULL));
@ -1770,8 +1770,8 @@ static void pragma_parse(TCCState *s1)
tcc_free(p); tcc_free(p);
} }
} else if (NEED_WARNING(s1, UNSUPPORTED)) } else
tcc_warning("#pragma %s is ignored", get_tok_str(tok, &tokc)); tcc_warning_c(warn_unsupported)("#pragma %s ignored", get_tok_str(tok, &tokc));
return; return;
pragma_err: pragma_err:
@ -2293,7 +2293,7 @@ static void parse_string(const char *s, int len)
if (n < 1) if (n < 1)
tcc_error("empty character constant"); tcc_error("empty character constant");
if (n > 1) if (n > 1)
tcc_warning("multi-character character constant"); tcc_warning_c(warn_all)("multi-character character constant");
for (c = i = 0; i < n; ++i) { for (c = i = 0; i < n; ++i) {
if (is_long) if (is_long)
c = ((nwchar_t *)tokcstr.data)[i]; c = ((nwchar_t *)tokcstr.data)[i];

View file

@ -399,4 +399,21 @@ int array[] = { 1, 2, 3 };
void v() {} void v() {}
int f() { return v(); } int f() { return v(); }
#elif defined test_switch_W1 || defined test_switch_W2 \
|| defined test_switch_W3 || defined test_switch_W4
#if defined test_switch_W1
#pragma comment(option, "-Wall")
#elif defined test_switch_W2
#pragma comment(option, "-Wunsupported -Wno-implicit-function-declaration -Wstuff")
#elif defined test_switch_W3
#pragma comment(option, "-Wwrite-strings -Werror=discarded-qualifiers")
#elif defined test_switch_W4
#pragma comment(option, "-Wunsupported -Wno-error=implicit-function-declaration -Werror")
#endif
void func()
{
char *ccp = "123";
fink();
}
__attribute__((stuff)) int fink() {return 0;}
#endif #endif

View file

@ -189,3 +189,17 @@ bar : 3 ; 3
[test_cast_from_void] [test_cast_from_void]
60_errors_and_warnings.c:400: error: cannot convert 'void' to 'int' 60_errors_and_warnings.c:400: error: cannot convert 'void' to 'int'
[test_switch_W1]
60_errors_and_warnings.c:416: warning: implicit declaration of function 'fink'
[test_switch_W2]
60_errors_and_warnings.c:407: warning: unsupported option '-Wstuff'
60_errors_and_warnings.c:418: warning: 'stuff' attribute ignored
[test_switch_W3]
60_errors_and_warnings.c:415: error: assignment discards qualifiers from pointer target type
[test_switch_W4]
60_errors_and_warnings.c:416: warning: implicit declaration of function 'fink'
60_errors_and_warnings.c:418: error: 'stuff' attribute ignored