From bb8544d38aaa4c716603a5d565c3ff3840454ffc Mon Sep 17 00:00:00 2001 From: Christoph Mallon Date: Tue, 21 Jun 2011 15:43:56 +0200 Subject: [PATCH] Improve diagnostic handling: Add [-Wfoo] and -Werror-foo. - Print the name of the warning switch at the end of each warning message, e.g. [-Wfoo] - Every warning can now be turned into an error with -Werror-foo. --- adt/util.h | 2 + ast2firm.c | 44 ++-- attribute.c | 55 ++--- cparser.1 | 10 +- diagnostic.c | 50 ++-- diagnostic.h | 3 +- format_check.c | 69 +++--- lexer.c | 15 +- main.c | 2 +- parser.c | 626 ++++++++++++++++++++----------------------------- preprocessor.c | 13 +- type.c | 11 +- warning.c | 334 ++++++++++---------------- warning.h | 150 ++++++------ 14 files changed, 593 insertions(+), 791 deletions(-) diff --git a/adt/util.h b/adt/util.h index 61c3c7d..54dfc83 100644 --- a/adt/util.h +++ b/adt/util.h @@ -52,4 +52,6 @@ #define lengthof(x) (sizeof(x) / sizeof(*(x))) +#define endof(x) ((x) + lengthof(x)) + #endif diff --git a/ast2firm.c b/ast2firm.c index 4e9efa5..559b1c2 100644 --- a/ast2firm.c +++ b/ast2firm.c @@ -126,9 +126,9 @@ static ir_node *uninitialized_local_var(ir_graph *irg, ir_mode *mode, int pos) { const entity_t *entity = get_irg_loc_description(irg, pos); - if (entity != NULL && warning.uninitialized) { + if (entity != NULL) { source_position_t const *const pos = &entity->base.source_position; - warningf(pos, "'%N' might be used uninitialized", entity); + warningf(WARN_UNINITIALIZED, pos, "'%N' might be used uninitialized", entity); } return new_r_Unknown(irg, mode); } @@ -1544,11 +1544,9 @@ static ir_node *reference_expression_to_firm(const reference_expression_t *ref) /* for gcc compatibility we have to produce (dummy) addresses for some * builtins which don't have entities */ if (irentity == NULL) { - if (warning.other) { - warningf(&ref->base.source_position, - "taking address of builtin '%Y'", - ref->entity->base.symbol); - } + source_position_t const *const pos = &ref->base.source_position; + symbol_t const *const sym = ref->entity->base.symbol; + warningf(WARN_OTHER, pos, "taking address of builtin '%Y'", sym); /* simply create a NULL pointer */ ir_mode *mode = get_ir_mode_arithmetic(type_void_ptr); @@ -5292,20 +5290,19 @@ static void asm_statement_to_firm(const asm_statement_t *statement) asm_constraint_flags_t asm_flags = be_parse_asm_constraints(constraints); - if (asm_flags & ASM_CONSTRAINT_FLAG_NO_SUPPORT) { - warningf(&statement->base.source_position, - "some constraints in '%s' are not supported", constraints); - } - if (asm_flags & ASM_CONSTRAINT_FLAG_INVALID) { - errorf(&statement->base.source_position, - "some constraints in '%s' are invalid", constraints); - continue; - } - if (! (asm_flags & ASM_CONSTRAINT_FLAG_MODIFIER_WRITE)) { - errorf(&statement->base.source_position, - "no write flag specified for output constraints '%s'", - constraints); - continue; + { + source_position_t const *const pos = &statement->base.source_position; + if (asm_flags & ASM_CONSTRAINT_FLAG_NO_SUPPORT) { + warningf(WARN_OTHER, pos, "some constraints in '%s' are not supported", constraints); + } + if (asm_flags & ASM_CONSTRAINT_FLAG_INVALID) { + errorf(pos, "some constraints in '%s' are invalid", constraints); + continue; + } + if (! (asm_flags & ASM_CONSTRAINT_FLAG_MODIFIER_WRITE)) { + errorf(pos, "no write flag specified for output constraints '%s'", constraints); + continue; + } } unsigned pos = next_pos++; @@ -5478,7 +5475,8 @@ static void asm_statement_to_firm(const asm_statement_t *statement) static void ms_try_statement_to_firm(ms_try_statement_t *statement) { statement_to_firm(statement->try_statement); - warningf(&statement->base.source_position, "structured exception handling ignored"); + source_position_t const *const pos = &statement->base.source_position; + warningf(WARN_OTHER, pos, "structured exception handling ignored"); } static void leave_statement_to_firm(leave_statement_t *statement) @@ -5864,7 +5862,7 @@ static void create_function(entity_t *entity) /* if we have computed goto's in the function, we cannot inline it */ if (get_irg_inline_property(irg) >= irg_inline_recomended) { source_position_t const *const pos = &entity->base.source_position; - warningf(pos, "'%N' can never be inlined because it contains a computed goto", entity); + warningf(WARN_OTHER, pos, "'%N' can never be inlined because it contains a computed goto", entity); } set_irg_inline_property(irg, irg_inline_forbidden); } diff --git a/attribute.c b/attribute.c index 3e2101b..07f152b 100644 --- a/attribute.c +++ b/attribute.c @@ -166,9 +166,8 @@ type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type) } else if (strcmp_underscore("DI", symbol_str) == 0) { akind = sign ? ATOMIC_TYPE_LONGLONG : ATOMIC_TYPE_ULONGLONG; } else { - if (warning.other) - warningf(&attribute->source_position, "ignoring unknown mode '%s'", - symbol_str); + source_position_t const *const pos = &attribute->source_position; + warningf(WARN_OTHER, pos, "ignoring unknown mode '%s'", symbol_str); return orig_type; } @@ -181,8 +180,8 @@ type_t *handle_attribute_mode(const attribute_t *attribute, type_t *orig_type) copy->enumt.akind = akind; return identify_new_type(copy); } else if (is_type_pointer(type)) { - warningf(&attribute->source_position, - "__attribute__((mode)) on pointers not implemented yet (ignored)"); + source_position_t const *const pos = &attribute->source_position; + warningf(WARN_OTHER, pos, "__attribute__((mode)) on pointers not implemented yet (ignored)"); return type; } @@ -231,15 +230,14 @@ static void handle_attribute_aligned(const attribute_t *attribute, entity->compound.alignment = alignment; } break; - default: - if (warning.other) { - const char *what = get_entity_kind_name(entity->kind); - warningf(&attribute->source_position, - "alignment attribute specification on %s '%S' ignored", - what, entity->base.symbol); - } + default: { + source_position_t const *const pos = &attribute->source_position; + char const *const what = get_entity_kind_name(entity->kind); + symbol_t const *const sym = entity->base.symbol; + warningf(WARN_OTHER, pos, "alignment attribute specification on %s '%S' ignored", what, sym); break; } + } } static const char *get_argument_string(const attribute_argument_t *argument) @@ -285,15 +283,14 @@ static void handle_attribute_visibility(const attribute_t *attribute, case ENTITY_FUNCTION: entity->function.elf_visibility = visibility; break; - default: - if (warning.other) { - const char *what = get_entity_kind_name(entity->kind); - warningf(&attribute->source_position, - "visibility attribute specification on %s '%S' ignored", - what, entity->base.symbol); - } + default: { + source_position_t const *const pos = &attribute->source_position; + char const *const what = get_entity_kind_name(entity->kind); + symbol_t const *const sym = entity->base.symbol; + warningf(WARN_OTHER, pos, "visibility attribute specification on %s '%S' ignored", what, sym); break; } + } } static void warn_arguments(const attribute_t *attribute) @@ -301,11 +298,9 @@ static void warn_arguments(const attribute_t *attribute) if (attribute->a.arguments == NULL) return; - if (warning.other) { - warningf(&attribute->source_position, - "attribute '%s' needs no arguments", - get_attribute_name(attribute->kind)); - } + source_position_t const *const pos = &attribute->source_position; + char const *const what = get_attribute_name(attribute->kind); + warningf(WARN_OTHER, pos, "attribute '%s' needs no arguments", what); } static void handle_attribute_packed_e(const attribute_t *attribute, @@ -313,10 +308,10 @@ static void handle_attribute_packed_e(const attribute_t *attribute, { #if 0 if (entity->kind != ENTITY_STRUCT) { - warningf(&attribute->source_position, - "packed attribute on %s '%s' ignored", - get_entity_kind_name(entity->kind), - entity->base.symbol->string); + source_position_t const *const pos = &attribute->source_position; + char const *const what = get_entity_kind_name(entity->kind); + symbol_t const *const sym = entity->base.symbol; + warningf(WARN_OTHER, pos, "packed attribute on %s '%S' ignored", what, sym); return; } #endif @@ -328,8 +323,8 @@ static void handle_attribute_packed_e(const attribute_t *attribute, static void handle_attribute_packed(const attribute_t *attribute, type_t *type) { if (type->kind != TYPE_COMPOUND_STRUCT) { - warningf(&attribute->source_position, - "packed attribute on type '%T' ignored", type); + source_position_t const *const pos = &attribute->source_position; + warningf(WARN_OTHER, pos, "packed attribute on type '%T' ignored", type); return; } diff --git a/cparser.1 b/cparser.1 index 3700bd9..1b7a266 100644 --- a/cparser.1 +++ b/cparser.1 @@ -14,7 +14,7 @@ .Op Fl - Ns Oo Cm no- Oc Ns Cm ms .Op Fl g .Op Fl O Ns Ar level -.Op Fl W Ns Oo Cm no- Oc Ns Ar warn +.Op Fl W Ns Oo Cm no- Ns | Ns Cm error- Oc Ns Ar warn .Op Fl w .Op Fl I Ar dir .Op Fl L Ar dir @@ -91,12 +91,14 @@ format. .\" TODO expand Select the optimization level. Sensible values are between 0 and 4, inclusive. -.It Fl W Ns Oo Cm no- Oc Ns Ar warn +.It Fl W Ns Oo Cm no- Ns | Ns Cm error- Oc Ns Ar warn .\" TODO expand Disable/enable a specific warning. Every warning option has a corresponding .Cm no- -switch to deactivate it. +switch to deactivate it and an +.Cm error- +switch to turn it into an error. .It Fl Waddress Warn about suspicious use of addresses, like using the address of a function or variable as boolean condition or comparing with the address of a string literal. .It Fl Waggregate-return @@ -144,8 +146,6 @@ Warn about empty statements, i.e. statements which only consist of a single Use {} as replacement to avoid this warning. .It Fl Werror Treat warnings as errors, i.e. do not continue after parsing when a warning is encountered. -.It Fl Werror-implicit-function-declaration -Generate an error, when calling a function without a prior declaration. .It Fl Wextra (Alias .Fl W Ns ) diff --git a/diagnostic.c b/diagnostic.c index 5fb6677..6376abb 100644 --- a/diagnostic.c +++ b/diagnostic.c @@ -30,12 +30,12 @@ #include "warning.h" /** Number of occurred diagnostics. */ -unsigned diagnostic_count = 0; +unsigned diagnostic_count = 0; /** Number of occurred errors. */ -unsigned error_count = 0; +unsigned error_count = 0; /** Number of occurred warnings. */ -unsigned warning_count = 0; -bool show_column = true; +unsigned warning_count = 0; +bool show_column = true; static const source_position_t *curr_pos = NULL; @@ -219,15 +219,16 @@ static void diagnosticposvf(source_position_t const *const pos, char const *cons fprintf(out, " %s: ", kind); curr_pos = pos; diagnosticvf(fmt, ap); - fputc('\n', out); } static void errorvf(const source_position_t *pos, const char *const fmt, va_list ap) { + curr_pos = pos; ++error_count; diagnosticposvf(pos, "error", fmt, ap); - if (warning.fatal_errors) + fputc('\n', stderr); + if (is_warn_on(WARN_FATAL_ERRORS)) exit(EXIT_FAILURE); } @@ -235,27 +236,35 @@ void errorf(const source_position_t *pos, const char *const fmt, ...) { va_list ap; va_start(ap, fmt); - curr_pos = pos; errorvf(pos, fmt, ap); va_end(ap); } -static void warningvf(const source_position_t *pos, - const char *const fmt, va_list ap) -{ - ++warning_count; - diagnosticposvf(pos, "warning", fmt, ap); -} - -void warningf(const source_position_t *pos, const char *const fmt, ...) +void warningf(warning_t const warn, source_position_t const* pos, char const *const fmt, ...) { va_list ap; va_start(ap, fmt); - curr_pos = pos; - if (warning.s_are_errors) { - errorvf(pos, fmt, ap); - } else { - warningvf(pos, fmt, ap); + warning_switch_t const *const s = get_warn_switch(warn); + switch (s->level) { + case WARN_LEVEL_OFF: + break; + + char const* kind; + case WARN_LEVEL_ON: + if (is_warn_on(WARN_ERROR)) { + case WARN_LEVEL_ERROR: + ++error_count; + kind = "error"; + } else { + ++warning_count; + kind = "warning"; + } + diagnosticposvf(pos, kind, fmt, ap); + fprintf(stderr, " [-W%s]\n", s->name); + break; + + default: + panic("invalid warning level"); } va_end(ap); } @@ -264,6 +273,7 @@ static void internal_errorvf(const source_position_t *pos, const char *const fmt, va_list ap) { diagnosticposvf(pos, "internal error", fmt, ap); + fputc('\n', stderr); } void internal_errorf(const source_position_t *pos, const char *const fmt, ...) diff --git a/diagnostic.h b/diagnostic.h index 7f00a43..313a2a9 100644 --- a/diagnostic.h +++ b/diagnostic.h @@ -22,6 +22,7 @@ #include #include "token_t.h" +#include "warning.h" /* define a NORETURN attribute */ #ifndef NORETURN @@ -59,7 +60,7 @@ */ void diagnosticf(const char *fmt, ...); void errorf(const source_position_t *pos, const char *fmt, ...); -void warningf(const source_position_t *pos, const char *fmt, ...); +void warningf(warning_t, const source_position_t *pos, const char *fmt, ...); NORETURN internal_errorf(const source_position_t *pos, const char *fmt, ...); extern unsigned diagnostic_count; diff --git a/format_check.c b/format_check.c index 38423d9..16eafd1 100644 --- a/format_check.c +++ b/format_check.c @@ -96,10 +96,8 @@ static void warn_invalid_length_modifier(const source_position_t *pos, const format_length_modifier_t mod, const utf32 conversion) { - warningf(pos, - "invalid length modifier '%s' for conversion specifier '%%%c'", - get_length_modifier_name(mod), conversion - ); + char const *const lmod = get_length_modifier_name(mod); + warningf(WARN_FORMAT, pos, "invalid length modifier '%s' for conversion specifier '%%%c'", lmod, conversion); } /** @@ -145,7 +143,7 @@ static int internal_check_printf_format(const expression_t *fmt_expr, fmt = *(++c); if (fmt == '\0') { - warningf(pos, "dangling %% in format string"); + warningf(WARN_FORMAT, pos, "dangling %% in format string"); break; } if (fmt == '%') @@ -186,14 +184,14 @@ static int internal_check_printf_format(const expression_t *fmt_expr, case ' ': if (fmt_flags & FMT_FLAG_PLUS) { - warningf(pos, "' ' is overridden by prior '+' in conversion specification %u", num_fmt); + warningf(WARN_FORMAT, pos, "' ' is overridden by prior '+' in conversion specification %u", num_fmt); } flag = FMT_FLAG_SPACE; break; case '+': if (fmt_flags & FMT_FLAG_SPACE) { - warningf(pos, "'+' overrides prior ' ' in conversion specification %u", num_fmt); + warningf(WARN_FORMAT, pos, "'+' overrides prior ' ' in conversion specification %u", num_fmt); } flag = FMT_FLAG_PLUS; break; @@ -201,7 +199,7 @@ static int internal_check_printf_format(const expression_t *fmt_expr, default: goto break_fmt_flags; } if (fmt_flags & flag) { - warningf(pos, "repeated flag '%c' in conversion specification %u", (char)fmt, num_fmt); + warningf(WARN_FORMAT, pos, "repeated flag '%c' in conversion specification %u", (char)fmt, num_fmt); } fmt_flags |= flag; fmt = *(++c); @@ -213,12 +211,12 @@ break_fmt_flags: ++num_args; fmt = *(++c); if (arg == NULL) { - warningf(pos, "missing argument for '*' field width in conversion specification %u", num_fmt); + warningf(WARN_FORMAT, pos, "missing argument for '*' field width in conversion specification %u", num_fmt); return -1; } const type_t *const arg_type = arg->expression->base.type; if (arg_type != type_int) { - warningf(pos, "argument for '*' field width in conversion specification %u is not an 'int', but an '%T'", num_fmt, arg_type); + warningf(WARN_FORMAT, pos, "argument for '*' field width in conversion specification %u is not an 'int', but an '%T'", num_fmt, arg_type); } arg = arg->next; } else { @@ -235,12 +233,12 @@ break_fmt_flags: if (fmt == '*') { fmt = *(++c); if (arg == NULL) { - warningf(pos, "missing argument for '*' precision in conversion specification %u", num_fmt); + warningf(WARN_FORMAT, pos, "missing argument for '*' precision in conversion specification %u", num_fmt); return -1; } const type_t *const arg_type = arg->expression->base.type; if (arg_type != type_int) { - warningf(pos, "argument for '*' precision in conversion specification %u is not an 'int', but an '%T'", num_fmt, arg_type); + warningf(WARN_FORMAT, pos, "argument for '*' precision in conversion specification %u is not an 'int', but an '%T'", num_fmt, arg_type); } arg = arg->next; } else { @@ -468,9 +466,9 @@ eval_fmt_mod_unsigned: break; default: - warningf(pos, "encountered unknown conversion specifier '%%%c' at position %u", fmt, num_fmt); + warningf(WARN_FORMAT, pos, "encountered unknown conversion specifier '%%%c' at position %u", fmt, num_fmt); if (arg == NULL) { - warningf(pos, "too few arguments for format string"); + warningf(WARN_FORMAT, pos, "too few arguments for format string"); return -1; } goto next_arg; @@ -488,11 +486,11 @@ eval_fmt_mod_unsigned: if (wrong_flags & FMT_FLAG_TICK) *p++ = '\''; *p = '\0'; - warningf(pos, "invalid format flags \"%s\" in conversion specification %%%c at position %u", wrong, fmt, num_fmt); + warningf(WARN_FORMAT, pos, "invalid format flags \"%s\" in conversion specification %%%c at position %u", wrong, fmt, num_fmt); } if (arg == NULL) { - warningf(pos, "too few arguments for format string"); + warningf(WARN_FORMAT, pos, "too few arguments for format string"); return -1; } @@ -520,9 +518,9 @@ eval_fmt_mod_unsigned: goto next_arg; } if (is_type_valid(arg_skip)) { - warningf(&arg->expression->base.source_position, - "argument type '%T' does not match conversion specifier '%%%s%c' at position %u", - arg_type, get_length_modifier_name(fmt_mod), (char)fmt, num_fmt); + source_position_t const *const apos = &arg->expression->base.source_position; + char const *const mod = get_length_modifier_name(fmt_mod); + warningf(WARN_FORMAT, apos, "argument type '%T' does not match conversion specifier '%%%s%c' at position %u", arg_type, mod, (char)fmt, num_fmt); } } next_arg: @@ -530,7 +528,7 @@ next_arg: } assert(fmt == '\0'); if (c+1 < string + size) { - warningf(pos, "format string contains '\\0'"); + warningf(WARN_FORMAT, pos, "format string contains '\\0'"); } return num_args; } @@ -563,10 +561,8 @@ static void check_printf_format(call_argument_t const *arg, for (; arg != NULL; arg = arg->next) ++num_args; if (num_args > (size_t)num_fmt) { - warningf(&fmt_expr->base.source_position, - "%u argument%s but only %u format specifier%s", - num_args, num_args != 1 ? "s" : "", - num_fmt, num_fmt != 1 ? "s" : ""); + source_position_t const *const pos = &fmt_expr->base.source_position; + warningf(WARN_FORMAT, pos, "%u argument%s but only %u format specifier%s", num_args, num_args != 1 ? "s" : "", num_fmt, num_fmt != 1 ? "s" : ""); } } @@ -609,7 +605,7 @@ static void check_scanf_format(const call_argument_t *arg, continue; fmt = *(++c); if (fmt == '\0') { - warningf(pos, "dangling '%%' in format string"); + warningf(WARN_FORMAT, pos, "dangling '%%' in format string"); break; } if (fmt == '%') @@ -679,7 +675,7 @@ static void check_scanf_format(const call_argument_t *arg, } if (fmt == '\0') { - warningf(pos, "dangling % with conversion specififer in format string"); + warningf(WARN_FORMAT, pos, "dangling %% with conversion specififer in format string"); break; } @@ -816,17 +812,16 @@ static void check_scanf_format(const call_argument_t *arg, break; default: - warningf(pos, "encountered unknown conversion specifier '%%%c' at format %u", - fmt, num_fmt); + warningf(WARN_FORMAT, pos, "encountered unknown conversion specifier '%%%c' at format %u", fmt, num_fmt); if (arg == NULL) { - warningf(pos, "too few arguments for format string"); + warningf(WARN_FORMAT, pos, "too few arguments for format string"); return; } goto next_arg; } if (arg == NULL) { - warningf(pos, "too few arguments for format string"); + warningf(WARN_FORMAT, pos, "too few arguments for format string"); return; } @@ -858,9 +853,9 @@ static void check_scanf_format(const call_argument_t *arg, } error_arg_type: if (is_type_valid(arg_skip)) { - warningf(&arg->expression->base.source_position, - "argument type '%T' does not match conversion specifier '%%%s%c' at position %u", - arg_type, get_length_modifier_name(fmt_mod), (char)fmt, num_fmt); + source_position_t const *const apos = &arg->expression->base.source_position; + char const *const mod = get_length_modifier_name(fmt_mod); + warningf(WARN_FORMAT, apos, "argument type '%T' does not match conversion specifier '%%%s%c' at position %u", arg_type, mod, (char)fmt, num_fmt); } } next_arg: @@ -868,7 +863,7 @@ next_arg: } assert(fmt == '\0'); if (c+1 < string + size) { - warningf(pos, "format string contains '\\0'"); + warningf(WARN_FORMAT, pos, "format string contains '\\0'"); } if (arg != NULL) { unsigned num_args = num_fmt; @@ -876,9 +871,7 @@ next_arg: ++num_args; arg = arg->next; } - warningf(pos, "%u argument%s but only %u format specifier%s", - num_args, num_args != 1 ? "s" : "", - num_fmt, num_fmt != 1 ? "s" : ""); + warningf(WARN_FORMAT, pos, "%u argument%s but only %u format specifier%s", num_args, num_args != 1 ? "s" : "", num_fmt, num_fmt != 1 ? "s" : ""); } } @@ -933,7 +926,7 @@ static const format_spec_t builtin_table[] = { void check_format(const call_expression_t *const call) { - if (!warning.format) + if (!is_warn_on(WARN_FORMAT)) return; const expression_t *const func_expr = call->function; diff --git a/lexer.c b/lexer.c index c7cc960..80e4916 100644 --- a/lexer.c +++ b/lexer.c @@ -963,7 +963,7 @@ static void parse_string_literal(void) case '\\': { utf32 const tc = parse_escape_sequence(); if (tc >= 0x100) { - warningf(&lexer_pos, "escape sequence out of range"); + warningf(WARN_OTHER, &lexer_pos, "escape sequence out of range"); } obstack_1grow(&symbol_obstack, tc); break; @@ -1071,7 +1071,7 @@ static void parse_character_constant(void) case '\\': { utf32 const tc = parse_escape_sequence(); if (tc >= 0x100) { - warningf(&lexer_pos, "escape sequence out of range"); + warningf(WARN_OTHER, &lexer_pos, "escape sequence out of range"); } obstack_1grow(&symbol_obstack, tc); break; @@ -1124,9 +1124,7 @@ static void skip_multiline_comment(void) next_char(); if (c == '*') { /* nested comment, warn here */ - if (warning.comment) { - warningf(&lexer_pos, "'/*' within comment"); - } + warningf(WARN_COMMENT, &lexer_pos, "'/*' within comment"); } break; case '*': @@ -1168,8 +1166,7 @@ static void skip_line_comment(void) case '\\': next_char(); if (c == '\n' || c == '\r') { - if (warning.comment) - warningf(&lexer_pos, "multi-line comment"); + warningf(WARN_COMMENT, &lexer_pos, "multi-line comment"); return; } break; @@ -1328,8 +1325,8 @@ static void parse_pragma(void) unknown_pragma = true; } eat_until_newline(); - if (unknown_pragma && warning.unknown_pragmas) { - warningf(&pp_token.source_position, "encountered unknown #pragma"); + if (unknown_pragma) { + warningf(WARN_UNKNOWN_PRAGMAS, &pp_token.source_position, "encountered unknown #pragma"); } } diff --git a/main.c b/main.c index 6a0852b..9930066 100644 --- a/main.c +++ b/main.c @@ -980,7 +980,7 @@ int main(int argc, char **argv) } else if (SINGLE_OPTION('v')) { verbose = 1; } else if (SINGLE_OPTION('w')) { - memset(&warning, 0, sizeof(warning)); + disable_all_warnings(); } else if (option[0] == 'x') { const char *opt; GET_ARG_AFTER(opt, "-x"); diff --git a/parser.c b/parser.c index d9397d9..90e8ca4 100644 --- a/parser.c +++ b/parser.c @@ -950,10 +950,7 @@ typedef enum assign_error_t { ASSIGN_WARNING_INT_FROM_POINTER } assign_error_t; -static void report_assign_error(assign_error_t error, type_t *orig_type_left, - const expression_t *const right, - const char *context, - const source_position_t *source_position) +static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, source_position_t const *const pos) { type_t *const orig_type_right = right->base.type; type_t *const type_left = skip_typeref(orig_type_left); @@ -963,48 +960,29 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left, case ASSIGN_SUCCESS: return; case ASSIGN_ERROR_INCOMPATIBLE: - errorf(source_position, - "destination type '%T' in %s is incompatible with type '%T'", - orig_type_left, context, orig_type_right); + errorf(pos, "destination type '%T' in %s is incompatible with type '%T'", orig_type_left, context, orig_type_right); return; case ASSIGN_ERROR_POINTER_QUALIFIER_MISSING: { - if (warning.other) { - type_t *points_to_left = skip_typeref(type_left->pointer.points_to); - type_t *points_to_right = skip_typeref(type_right->pointer.points_to); + type_t *points_to_left = skip_typeref(type_left->pointer.points_to); + type_t *points_to_right = skip_typeref(type_right->pointer.points_to); - /* the left type has all qualifiers from the right type */ - unsigned missing_qualifiers - = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers; - warningf(source_position, - "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type", - orig_type_left, context, orig_type_right, missing_qualifiers); - } + /* the left type has all qualifiers from the right type */ + unsigned missing_qualifiers = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers; + warningf(WARN_OTHER, pos, "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type", orig_type_left, context, orig_type_right, missing_qualifiers); return; } case ASSIGN_WARNING_POINTER_INCOMPATIBLE: - if (warning.other) { - warningf(source_position, - "destination type '%T' in %s is incompatible with '%E' of type '%T'", - orig_type_left, context, right, orig_type_right); - } + warningf(WARN_OTHER, pos, "destination type '%T' in %s is incompatible with '%E' of type '%T'", orig_type_left, context, right, orig_type_right); return; case ASSIGN_WARNING_POINTER_FROM_INT: - if (warning.other) { - warningf(source_position, - "%s makes pointer '%T' from integer '%T' without a cast", - context, orig_type_left, orig_type_right); - } + warningf(WARN_OTHER, pos, "%s makes pointer '%T' from integer '%T' without a cast", context, orig_type_left, orig_type_right); return; case ASSIGN_WARNING_INT_FROM_POINTER: - if (warning.other) { - warningf(source_position, - "%s makes integer '%T' from pointer '%T' without a cast", - context, orig_type_left, orig_type_right); - } + warningf(WARN_OTHER, pos, "%s makes integer '%T' from pointer '%T' without a cast", context, orig_type_left, orig_type_right); return; default: @@ -1095,9 +1073,7 @@ static expression_t *parse_assignment_expression(void) static void warn_string_concat(const source_position_t *pos) { - if (warning.traditional) { - warningf(pos, "traditional C rejects string constant concatenation"); - } + warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation"); } static string_t parse_string_literals(void) @@ -1269,9 +1245,7 @@ static attribute_t *parse_attribute_gnu_single(void) char const *const name = symbol->string; for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) { if (kind > ATTRIBUTE_GNU_LAST) { - if (warning.attribute) { - warningf(HERE, "unknown attribute '%s' ignored", name); - } + warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name); /* TODO: we should still save the attribute in the list... */ kind = ATTRIBUTE_UNKNOWN; break; @@ -1360,8 +1334,7 @@ static attribute_t *parse_attributes(attribute_t *first) case T___thiscall: /* TODO record modifier */ - if (warning.other) - warningf(HERE, "Ignoring declaration modifier %K", &token); + warningf(WARN_OTHER, HERE, "Ignoring declaration modifier %K", &token); eat(T___thiscall); attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL); break; @@ -1751,8 +1724,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, /* there might be extra {} hierarchies */ int braces = 0; if (token.type == '{') { - if (warning.other) - warningf(HERE, "extra curly braces around scalar initializer"); + warningf(WARN_OTHER, HERE, "extra curly braces around scalar initializer"); do { eat('{'); ++braces; @@ -1781,8 +1753,8 @@ static initializer_t *parse_scalar_initializer(type_t *type, while (braces > 0) { next_if(','); if (token.type != '}') { - if (!additional_warning_displayed && warning.other) { - warningf(HERE, "additional elements in scalar initializer"); + if (!additional_warning_displayed) { + warningf(WARN_OTHER, HERE, "additional elements in scalar initializer"); additional_warning_displayed = true; } } @@ -2201,13 +2173,11 @@ finish_designator: goto error_parse_next; } - if (warning.other) { - source_position_t const* const pos = &expression->base.source_position; - if (env->entity != NULL) { - warningf(pos, "excess elements in initializer for '%Y'", env->entity->base.symbol); - } else { - warningf(pos, "excess elements in initializer"); - } + source_position_t const* const pos = &expression->base.source_position; + if (env->entity != NULL) { + warningf(WARN_OTHER, pos, "excess elements in initializer for '%Y'", env->entity->base.symbol); + } else { + warningf(WARN_OTHER, pos, "excess elements in initializer"); } goto error_parse_next; } @@ -2219,9 +2189,8 @@ finish_designator: sub = initializer_from_expression(outer_type, expression); if (sub != NULL) { next_if(','); - if (token.type != '}' && warning.other) { - warningf(HERE, "excessive elements in initializer for type '%T'", - orig_type); + if (token.type != '}') { + warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type); } /* TODO: eat , ... */ return sub; @@ -2737,8 +2706,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) } } - if (kind == ATTRIBUTE_UNKNOWN && warning.attribute) { - warningf(HERE, "unknown __declspec '%s' ignored", name); + if (kind == ATTRIBUTE_UNKNOWN) { + warningf(WARN_ATTRIBUTE, HERE, "unknown __declspec '%s' ignored", name); } eat(T_IDENTIFIER); } else { @@ -3111,10 +3080,7 @@ finish_specifiers: | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_ULONGLONG; warn_about_long_long: - if (warning.long_long) { - warningf(&specifiers->source_position, - "ISO C90 does not support 'long long'"); - } + warningf(WARN_LONG_LONG, &specifiers->source_position, "ISO C90 does not support 'long long'"); break; case SPECIFIER_UNSIGNED | SPECIFIER_INT8: @@ -3193,9 +3159,7 @@ warn_about_long_long: if (!saw_error) { /* ISO/IEC 14882:1998(E) §C.1.5:4 */ if (!(c_mode & _CXX) && !strict_mode) { - if (warning.implicit_int) { - warningf(pos, "no type specifiers in declaration, using 'int'"); - } + warningf(WARN_IMPLICIT_INT, pos, "no type specifiers in declaration, using 'int'"); atomic_type = ATOMIC_TYPE_INT; break; } else { @@ -3718,8 +3682,8 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, } else if (is_type_array(skipped_return_type)) { errorf(pos, "function returning array is not allowed"); } else { - if (skipped_return_type->base.qualifiers != 0 && warning.other) { - warningf(pos, "type qualifiers in return type of function type are meaningless"); + if (skipped_return_type->base.qualifiers != 0) { + warningf(WARN_OTHER, pos, "type qualifiers in return type of function type are meaningless"); } } @@ -4008,30 +3972,28 @@ static void check_main(const entity_t *entity) { const source_position_t *pos = &entity->base.source_position; if (entity->kind != ENTITY_FUNCTION) { - warningf(pos, "'main' is not a function"); + warningf(WARN_MAIN, pos, "'main' is not a function"); return; } if (entity->declaration.storage_class == STORAGE_CLASS_STATIC) { - warningf(pos, "'main' is normally a non-static function"); + warningf(WARN_MAIN, pos, "'main' is normally a non-static function"); } type_t *type = skip_typeref(entity->declaration.type); assert(is_type_function(type)); - function_type_t *func_type = &type->function; - if (!types_compatible(skip_typeref(func_type->return_type), type_int)) { - warningf(pos, "return type of 'main' should be 'int', but is '%T'", - func_type->return_type); + function_type_t const *const func_type = &type->function; + type_t *const ret_type = func_type->return_type; + if (!types_compatible(skip_typeref(ret_type), type_int)) { + warningf(WARN_MAIN, pos, "return type of 'main' should be 'int', but is '%T'", ret_type); } const function_parameter_t *parm = func_type->parameters; if (parm != NULL) { type_t *const first_type = skip_typeref(parm->type); type_t *const first_type_unqual = get_unqualified_type(first_type); if (!types_compatible(first_type_unqual, type_int)) { - warningf(pos, - "first argument of 'main' should be 'int', but is '%T'", - parm->type); + warningf(WARN_MAIN, pos, "first argument of 'main' should be 'int', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) { @@ -4039,8 +4001,7 @@ static void check_main(const entity_t *entity) type_t *const second_type_unqual = get_unqualified_type(second_type); if (!types_compatible(second_type_unqual, type_char_ptr_ptr)) { - warningf(pos, "second argument of 'main' should be 'char**', but is '%T'", - parm->type); + warningf(WARN_MAIN, pos, "second argument of 'main' should be 'char**', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) { @@ -4048,8 +4009,7 @@ static void check_main(const entity_t *entity) type_t *const third_type_unqual = get_unqualified_type(third_type); if (!types_compatible(third_type_unqual, type_char_ptr_ptr)) { - warningf(pos, "third argument of 'main' should be 'char**', but is '%T'", - parm->type); + warningf(WARN_MAIN, pos, "third argument of 'main' should be 'char**', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) @@ -4057,7 +4017,7 @@ static void check_main(const entity_t *entity) } } else { warn_arg_count: - warningf(pos, "'main' takes only zero, two or three arguments"); + warningf(WARN_MAIN, pos, "'main' takes only zero, two or three arguments"); } } } @@ -4153,24 +4113,21 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) assert(is_type_function(type)); if (type->function.unspecified_parameters && - warning.strict_prototypes && previous_entity == NULL && !entity->declaration.implicit) { - warningf(pos, "function declaration '%#N' is not a prototype", entity); + warningf(WARN_STRICT_PROTOTYPES, pos, "function declaration '%#N' is not a prototype", entity); } - if (warning.main && current_scope == file_scope - && is_sym_main(symbol)) { + if (current_scope == file_scope && is_sym_main(symbol)) { check_main(entity); } } if (is_declaration(entity) && - warning.nested_externs && entity->declaration.storage_class == STORAGE_CLASS_EXTERN && current_scope != file_scope && !entity->declaration.implicit) { - warningf(pos, "nested extern declaration of '%#N'", entity); + warningf(WARN_NESTED_EXTERNS, pos, "nested extern declaration of '%#N'", entity); } if (previous_entity != NULL) { @@ -4226,12 +4183,11 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) } else { unsigned old_storage_class = prev_decl->storage_class; - if (warning.redundant_decls && - is_definition && + if (is_definition && !prev_decl->used && !(prev_decl->modifiers & DM_USED) && prev_decl->storage_class == STORAGE_CLASS_STATIC) { - warningf(ppos, "unnecessary static forward declaration for '%#N'", previous_entity); + warningf(WARN_REDUNDANT_DECLS, ppos, "unnecessary static forward declaration for '%#N'", previous_entity); } storage_class_t new_storage_class = decl->storage_class; @@ -4252,10 +4208,8 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) case STORAGE_CLASS_EXTERN: if (is_definition) { - if (warning.missing_prototypes && - prev_type->function.unspecified_parameters && - !is_sym_main(symbol)) { - warningf(pos, "no previous prototype for '%#N'", entity); + if (prev_type->function.unspecified_parameters && !is_sym_main(symbol)) { + warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity); } } else if (new_storage_class == STORAGE_CLASS_NONE) { new_storage_class = STORAGE_CLASS_EXTERN; @@ -4279,10 +4233,9 @@ warn_redundant_declaration: ; if (has_new_attrs) { merge_in_attributes(decl, prev_decl->attributes); } else if (!is_definition && - warning.redundant_decls && is_type_valid(prev_type) && strcmp(ppos->input_name, "") != 0) { - warningf(pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos); + warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos); } } else if (current_function == NULL) { if (old_storage_class != STORAGE_CLASS_STATIC && @@ -4314,27 +4267,30 @@ error_redeclaration: return previous_entity; } - if (warning.shadow || - (warning.shadow_local && previous_entity->base.parent_scope != file_scope)) { + warning_t why; + if (is_warn_on(why = WARN_SHADOW) || + (is_warn_on(why = WARN_SHADOW_LOCAL) && previous_entity->base.parent_scope != file_scope)) { char const *const what = get_entity_kind_name(previous_entity->kind); - warningf(pos, "'%N' shadows %s (declared %P)", entity, what, ppos); + warningf(why, pos, "'%N' shadows %s (declared %P)", entity, what, ppos); } } if (entity->kind == ENTITY_FUNCTION) { if (is_definition && - entity->declaration.storage_class != STORAGE_CLASS_STATIC) { - if (warning.missing_prototypes && !is_sym_main(symbol)) { - warningf(pos, "no previous prototype for '%#N'", entity); - } else if (warning.missing_declarations && !is_sym_main(symbol)) { - warningf(pos, "no previous declaration for '%#N'", entity); + entity->declaration.storage_class != STORAGE_CLASS_STATIC && + !is_sym_main(symbol)) { + if (is_warn_on(WARN_MISSING_PROTOTYPES)) { + warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity); + } else { + goto warn_missing_declaration; } } } else if (entity->kind == ENTITY_VARIABLE) { - if (warning.missing_declarations && - current_scope == file_scope && - entity->declaration.storage_class == STORAGE_CLASS_NONE) { - warningf(pos, "no previous declaration for '%#N'", entity); + if (current_scope == file_scope && + entity->declaration.storage_class == STORAGE_CLASS_NONE && + !entity->declaration.implicit) { +warn_missing_declaration: + warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity); } } @@ -4426,31 +4382,28 @@ static void parse_anonymous_declaration_rest( eat(';'); anonymous_entity = NULL; - if (warning.other) { - if (specifiers->storage_class != STORAGE_CLASS_NONE || - specifiers->thread_local) { - warningf(&specifiers->source_position, - "useless storage class in empty declaration"); - } + source_position_t const *const pos = &specifiers->source_position; + if (specifiers->storage_class != STORAGE_CLASS_NONE || + specifiers->thread_local) { + warningf(WARN_OTHER, pos, "useless storage class in empty declaration"); + } - type_t *type = specifiers->type; - switch (type->kind) { - case TYPE_COMPOUND_STRUCT: - case TYPE_COMPOUND_UNION: { - if (type->compound.compound->base.symbol == NULL) { - warningf(&specifiers->source_position, - "unnamed struct/union that defines no instances"); - } - break; + type_t *type = specifiers->type; + switch (type->kind) { + case TYPE_COMPOUND_STRUCT: + case TYPE_COMPOUND_UNION: { + if (type->compound.compound->base.symbol == NULL) { + warningf(WARN_OTHER, pos, "unnamed struct/union that defines no instances"); } + break; + } - case TYPE_ENUM: - break; + case TYPE_ENUM: + break; - default: - warningf(&specifiers->source_position, "empty declaration"); - break; - } + default: + warningf(WARN_OTHER, pos, "empty declaration"); + break; } } @@ -4661,9 +4614,7 @@ decl_list_end: errorf(pos, "no type specified for function '%N'", parameter); parameter_type = type_error_type; } else { - if (warning.implicit_int) { - warningf(pos, "no type specified for function '%N', using 'int'", parameter); - } + warningf(WARN_IMPLICIT_INT, pos, "no type specified for function parameter '%N', using 'int'", parameter); parameter_type = type_int; } parameter->declaration.type = parameter_type; @@ -4698,11 +4649,11 @@ decl_list_end: new_type->function.parameters = parameters; new_type = identify_new_type(new_type); - if (warning.other && need_incompatible_warning) { + if (need_incompatible_warning) { + symbol_t const *const sym = entity->base.symbol; source_position_t const *const pos = &entity->base.source_position; source_position_t const *const ppos = &proto_type->base.source_position; - symbol_t const *const sym = entity->base.symbol; - warningf(pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos); + warningf(WARN_OTHER, pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos); } entity->declaration.type = new_type; @@ -4745,7 +4696,7 @@ static void check_labels(void) } } - if (warning.unused_label) { + if (is_warn_on(WARN_UNUSED_LABEL)) { for (const label_statement_t *label_statement = label_first; label_statement != NULL; label_statement = label_statement->next) { @@ -4754,13 +4705,13 @@ static void check_labels(void) if (! label->used) { print_in_function(); source_position_t const *const pos = &label_statement->base.source_position; - warningf(pos, "'%N' defined but not used", (entity_t const*)label); + warningf(WARN_UNUSED_LABEL, pos, "'%N' defined but not used", (entity_t const*)label); } } } } -static void warn_unused_entity(entity_t *entity, entity_t *last) +static void warn_unused_entity(warning_t const why, entity_t *entity, entity_t *const last) { entity_t const *const end = last != NULL ? last->base.next : NULL; for (; entity != end; entity = entity->base.next) { @@ -4773,10 +4724,10 @@ static void warn_unused_entity(entity_t *entity, entity_t *last) if (!declaration->used) { print_in_function(); - warningf(&entity->base.source_position, "'%N' is unused", entity); + warningf(why, &entity->base.source_position, "'%N' is unused", entity); } else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) { print_in_function(); - warningf(&entity->base.source_position, "'%N' is never read", entity); + warningf(why, &entity->base.source_position, "'%N' is never read", entity); } } } @@ -4788,13 +4739,12 @@ static void check_unused_variables(statement_t *const stmt, void *const env) switch (stmt->kind) { case STATEMENT_DECLARATION: { declaration_statement_t const *const decls = &stmt->declaration; - warn_unused_entity(decls->declarations_begin, - decls->declarations_end); + warn_unused_entity(WARN_UNUSED_VARIABLE, decls->declarations_begin, decls->declarations_end); return; } case STATEMENT_FOR: - warn_unused_entity(stmt->fors.scope.entities, NULL); + warn_unused_entity(WARN_UNUSED_VARIABLE, stmt->fors.scope.entities, NULL); return; default: @@ -4807,15 +4757,15 @@ static void check_unused_variables(statement_t *const stmt, void *const env) */ static void check_declarations(void) { - if (warning.unused_parameter) { + if (is_warn_on(WARN_UNUSED_PARAMETER)) { const scope_t *scope = ¤t_function->parameters; /* do not issue unused warnings for main */ if (!is_sym_main(current_function->base.base.symbol)) { - warn_unused_entity(scope->entities, NULL); + warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL); } } - if (warning.unused_variable) { + if (is_warn_on(WARN_UNUSED_VARIABLE)) { walk_statements(current_function->statement, check_unused_variables, NULL); } @@ -5228,12 +5178,11 @@ found_break_parent: type_t *const type = skip_typeref(current_function->base.type); assert(is_type_function(type)); type_t *const ret = skip_typeref(type->function.return_type); - if (warning.return_type && - !is_type_atomic(ret, ATOMIC_TYPE_VOID) && + if (!is_type_atomic(ret, ATOMIC_TYPE_VOID) && is_type_valid(ret) && !is_sym_main(current_function->base.base.symbol)) { - warningf(&stmt->base.source_position, - "control reaches end of non-void function"); + source_position_t const *const pos = &stmt->base.source_position; + warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function"); } return; } @@ -5366,8 +5315,8 @@ static void check_unreachable(statement_t* const stmt, void *const env) if (!stmt->base.reachable) { expression_t const *const cond = stmt->do_while.condition; if (determine_truth(cond) >= 0) { - warningf(&cond->base.source_position, - "condition of do-while-loop is unreachable"); + source_position_t const *const pos = &cond->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "condition of do-while-loop is unreachable"); } } return; @@ -5377,21 +5326,21 @@ static void check_unreachable(statement_t* const stmt, void *const env) // if init and step are unreachable, cond is unreachable, too if (!stmt->base.reachable && !fors->step_reachable) { - warningf(&stmt->base.source_position, "statement is unreachable"); + goto warn_unreachable; } else { if (!stmt->base.reachable && fors->initialisation != NULL) { - warningf(&fors->initialisation->base.source_position, - "initialisation of for-statement is unreachable"); + source_position_t const *const pos = &fors->initialisation->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "initialisation of for-statement is unreachable"); } if (!fors->condition_reachable && fors->condition != NULL) { - warningf(&fors->condition->base.source_position, - "condition of for-statement is unreachable"); + source_position_t const *const pos = &fors->condition->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "condition of for-statement is unreachable"); } if (!fors->step_reachable && fors->step != NULL) { - warningf(&fors->step->base.source_position, - "step of for-statement is unreachable"); + source_position_t const *const pos = &fors->step->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "step of for-statement is unreachable"); } } return; @@ -5422,8 +5371,10 @@ static void check_unreachable(statement_t* const stmt, void *const env) default: warn_unreachable: - if (!stmt->base.reachable) - warningf(&stmt->base.source_position, "statement is unreachable"); + if (!stmt->base.reachable) { + source_position_t const *const pos = &stmt->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "statement is unreachable"); + } return; } } @@ -5493,15 +5444,13 @@ static void parse_external_declaration(void) errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration); } - if (warning.aggregate_return && - is_type_compound(skip_typeref(type->function.return_type))) { - warningf(pos, "'%N' returns an aggregate", ndeclaration); + if (is_type_compound(skip_typeref(type->function.return_type))) { + warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration); } - if (warning.traditional && !type->function.unspecified_parameters) { - warningf(pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration); - } - if (warning.old_style_definition && type->function.unspecified_parameters) { - warningf(pos, "old-style definition of '%N'", ndeclaration); + if (type->function.unspecified_parameters) { + warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration); + } else { + warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration); } /* §6.7.5.3:14 a function definition with () means no @@ -5567,19 +5516,17 @@ static void parse_external_declaration(void) first_err = true; check_labels(); check_declarations(); - if (warning.return_type || - warning.unreachable_code || - (warning.missing_noreturn - && !(function->base.modifiers & DM_NORETURN))) { + if (is_warn_on(WARN_RETURN_TYPE) || + is_warn_on(WARN_UNREACHABLE_CODE) || + (is_warn_on(WARN_MISSING_NORETURN) && !(function->base.modifiers & DM_NORETURN))) { noreturn_candidate = true; check_reachable(body); - if (warning.unreachable_code) + if (is_warn_on(WARN_UNREACHABLE_CODE)) walk_statements(body, check_unreachable, NULL); - if (warning.missing_noreturn && - noreturn_candidate && + if (noreturn_candidate && !(function->base.modifiers & DM_NORETURN)) { source_position_t const *const pos = &body->base.source_position; - warningf(pos, "function '%#N' is candidate for attribute 'noreturn'", entity); + warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity); } } @@ -5662,19 +5609,17 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol) static void check_deprecated(const source_position_t *source_position, const entity_t *entity) { - if (!warning.deprecated_declarations) - return; if (!is_declaration(entity)) return; if ((entity->declaration.modifiers & DM_DEPRECATED) == 0) return; - source_position_t const *const pos = &entity->base.source_position; - char const* const msg = get_deprecated_string(entity->declaration.attributes); + source_position_t const *const epos = &entity->base.source_position; + char const *const msg = get_deprecated_string(entity->declaration.attributes); if (msg != NULL) { - warningf(source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, pos, msg); + warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg); } else { - warningf(source_position, "'%N' is deprecated (declared %P)", entity, pos); + warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P)", entity, epos); } } @@ -5905,12 +5850,12 @@ static expression_t *expected_expression_error(void) static type_t *get_string_type(void) { - return warning.write_strings ? type_const_char_ptr : type_char_ptr; + return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr; } static type_t *get_wide_string_type(void) { - return warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr; + return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr; } /** @@ -5962,10 +5907,7 @@ static expression_t *parse_boolean_literal(bool value) static void warn_traditional_suffix(void) { - if (!warning.traditional) - return; - warningf(&token.source_position, "traditional C rejects the '%Y' suffix", - token.symbol); + warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%Y' suffix", token.symbol); } static void check_integer_suffix(void) @@ -6097,9 +6039,9 @@ static expression_t *parse_character_constant(void) if (len > 1) { if (!GNU_MODE && !(c_mode & _C99)) { errorf(HERE, "more than 1 character in character constant"); - } else if (warning.multichar) { + } else { literal->base.type = type_int; - warningf(HERE, "multi-character character constant"); + warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); } } @@ -6119,7 +6061,7 @@ static expression_t *parse_wide_character_constant(void) size_t len = wstrlen(&literal->literal.value); if (len > 1) { - warningf(HERE, "multi-character character constant"); + warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); } next_token(); @@ -6304,12 +6246,7 @@ static entity_t *parse_qualified_identifier(void) if (entity == NULL) { if (!strict_mode && token.type == '(') { /* an implicitly declared function */ - if (warning.error_implicit_function_declaration) { - errorf(&pos, "implicit declaration of function '%Y'", symbol); - } else if (warning.implicit_function_declaration) { - warningf(&pos, "implicit declaration of function '%Y'", symbol); - } - + warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of function '%Y'", symbol); entity = create_implicit_function(symbol, &pos); } else { errorf(&pos, "unknown identifier '%Y' found.", symbol); @@ -6367,10 +6304,9 @@ static expression_t *parse_reference(void) check_deprecated(&pos, entity); - if (warning.init_self && entity == current_init_decl && !in_type_prop - && entity->kind == ENTITY_VARIABLE) { + if (entity == current_init_decl && !in_type_prop && entity->kind == ENTITY_VARIABLE) { current_init_decl = NULL; - warningf(&pos, "variable '%#N' is initialized by itself", entity); + warningf(WARN_INIT_SELF, &pos, "variable '%#N' is initialized by itself", entity); } return expression; @@ -6408,17 +6344,13 @@ static bool semantic_cast(expression_t *cast) return false; } - if (warning.cast_qual && - is_type_pointer(src_type) && - is_type_pointer(dst_type)) { + if (is_type_pointer(src_type) && is_type_pointer(dst_type)) { type_t *src = skip_typeref(src_type->pointer.points_to); type_t *dst = skip_typeref(dst_type->pointer.points_to); unsigned missing_qualifiers = src->base.qualifiers & ~dst->base.qualifiers; if (missing_qualifiers != 0) { - warningf(pos, - "cast discards qualifiers '%Q' in pointer target type of '%T'", - missing_qualifiers, orig_type_right); + warningf(WARN_CAST_QUAL, pos, "cast discards qualifiers '%Q' in pointer target type of '%T'", missing_qualifiers, orig_type_right); } } return true; @@ -6501,8 +6433,9 @@ static expression_t *parse_statement_expression(void) if (stmt->kind == STATEMENT_EXPRESSION) { type = stmt->expression.expression->base.type; } - } else if (warning.other) { - warningf(&expression->base.source_position, "empty statement expression ({})"); + } else { + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_OTHER, pos, "empty statement expression ({})"); } expression->base.type = type; @@ -7095,8 +7028,9 @@ check_idx: res_type = automatic_type_conversion(res_type); if (!is_type_integer(idx_type)) { errorf(&idx->base.source_position, "array subscript must have integer type"); - } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR) && warning.char_subscripts) { - warningf(&idx->base.source_position, "array subscript has char type"); + } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) { + source_position_t const *const pos = &idx->base.source_position; + warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type"); } } else { if (is_type_valid(type_left) && is_type_valid(type_inside)) { @@ -7162,11 +7096,9 @@ typeprop_expression: } else if (type->kind == TYPE_FUNCTION) { if (GNU_MODE) { /* function types are allowed (and return 1) */ - if (warning.other) { - char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; - warningf(&tp_expression->base.source_position, - "%s expression with function argument returns invalid result", what); - } + source_position_t const *const pos = &tp_expression->base.source_position; + char const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; + warningf(WARN_OTHER, pos, "%s expression with function argument returns invalid result", what); } else { wrong_type = "function"; } @@ -7307,15 +7239,14 @@ static void check_call_argument(type_t *expected_type, snprintf(buf, sizeof(buf), "call argument %u", pos); report_assign_error(error, expected_type, arg_expr, buf, &arg_expr->base.source_position); - } else if (warning.traditional || warning.conversion) { + } else { type_t *const promoted_type = get_default_promoted_type(arg_type); if (!types_compatible(expected_type_skip, promoted_type) && !types_compatible(expected_type_skip, type_void_ptr) && !types_compatible(type_void_ptr, promoted_type)) { /* Deliberately show the skipped types in this warning */ - warningf(&arg_expr->base.source_position, - "passing call argument %u as '%T' rather than '%T' due to prototype", - pos, expected_type_skip, promoted_type); + source_position_t const *const apos = &arg_expr->base.source_position; + warningf(WARN_TRADITIONAL, apos, "passing call argument %u as '%T' rather than '%T' due to prototype", pos, expected_type_skip, promoted_type); } } } @@ -7461,10 +7392,9 @@ static expression_t *parse_call_expression(expression_t *expression) check_format(call); - if (warning.aggregate_return && - is_type_compound(skip_typeref(function_type->return_type))) { - warningf(&expression->base.source_position, - "function call has aggregate value"); + if (is_type_compound(skip_typeref(function_type->return_type))) { + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_AGGREGATE_RETURN, pos, "function call has aggregate value"); } if (expression->kind == EXPR_REFERENCE) { @@ -7519,27 +7449,22 @@ static expression_t const *get_reference_address(expression_t const *expr) static void warn_reference_address_as_bool(expression_t const* expr) { - if (!warning.address) - return; - expr = get_reference_address(expr); if (expr != NULL) { source_position_t const *const pos = &expr->base.source_position; entity_t const *const ent = expr->reference.entity; - warningf(pos, "the address of '%N' will always evaluate as 'true'", ent); + warningf(WARN_ADDRESS, pos, "the address of '%N' will always evaluate as 'true'", ent); } } static void warn_assignment_in_condition(const expression_t *const expr) { - if (!warning.parentheses) - return; if (expr->base.kind != EXPR_BINARY_ASSIGN) return; if (expr->base.parenthesized) return; - warningf(&expr->base.source_position, - "suggest parentheses around assignment used as truth value"); + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest parentheses around assignment used as truth value"); } static void semantic_condition(expression_t const *const expr, @@ -7592,7 +7517,8 @@ end_error:; type_t *const false_type = skip_typeref(orig_false_type); /* 6.5.15.3 */ - type_t *result_type; + source_position_t const *const pos = &conditional->base.source_position; + type_t *result_type; if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) || is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { /* ISO/IEC 14882:1998(E) §5.16:2 */ @@ -7601,12 +7527,9 @@ end_error:; } else if (false_expression->kind == EXPR_UNARY_THROW) { result_type = true_type; } else { - if (warning.other && ( - !is_type_atomic(true_type, ATOMIC_TYPE_VOID) || - !is_type_atomic(false_type, ATOMIC_TYPE_VOID) - )) { - warningf(&conditional->base.source_position, - "ISO C forbids conditional expression with only one void side"); + if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) || + !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { + warningf(WARN_OTHER, pos, "ISO C forbids conditional expression with only one void side"); } result_type = type_void; } @@ -7645,11 +7568,7 @@ end_error:; get_unqualified_type(to2))) { to = to1; } else { - if (warning.other) { - warningf(&conditional->base.source_position, - "pointer types '%T' and '%T' in conditional expression are incompatible", - true_type, false_type); - } + warningf(WARN_OTHER, pos, "pointer types '%T' and '%T' in conditional expression are incompatible", true_type, false_type); to = type_void; } @@ -7657,10 +7576,7 @@ end_error:; get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers); result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE); } else if (is_type_integer(other_type)) { - if (warning.other) { - warningf(&conditional->base.source_position, - "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); - } + warningf(WARN_OTHER, pos, "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); result_type = pointer_type; } else { goto types_incompatible; @@ -7668,9 +7584,7 @@ end_error:; } else { types_incompatible: if (is_type_valid(true_type) && is_type_valid(false_type)) { - type_error_incompatible("while parsing conditional", - &conditional->base.source_position, true_type, - false_type); + type_error_incompatible("while parsing conditional", pos, true_type, false_type); } result_type = type_error_type; } @@ -7745,10 +7659,9 @@ end_error:; errorf(&value->base.source_position, "operand of delete must have pointer type"); } - } else if (warning.other && - is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) { - warningf(&value->base.source_position, - "deleting 'void*' is undefined"); + } else if (is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) { + source_position_t const *const pos = &value->base.source_position; + warningf(WARN_OTHER, pos, "deleting 'void*' is undefined"); } return result; @@ -7806,10 +7719,8 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, "arithmetic with pointer to incomplete type '%T' not allowed", orig_pointer_type); return false; - } else if (warning.pointer_arith) { - warningf(source_position, - "pointer of type '%T' used in arithmetic", - orig_pointer_type); + } else { + warningf(WARN_POINTER_ARITH, source_position, "pointer of type '%T' used in arithmetic", orig_pointer_type); } } else if (is_type_function(points_to)) { if (!GNU_MODE) { @@ -7817,10 +7728,8 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, "arithmetic with pointer to function type '%T' not allowed", orig_pointer_type); return false; - } else if (warning.pointer_arith) { - warningf(source_position, - "pointer to a function '%T' used in arithmetic", - orig_pointer_type); + } else { + warningf(WARN_POINTER_ARITH, source_position, "pointer to a function '%T' used in arithmetic", orig_pointer_type); } } return true; @@ -7891,9 +7800,8 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) static void semantic_unexpr_plus(unary_expression_t *expression) { semantic_unexpr_arithmetic(expression); - if (warning.traditional) - warningf(&expression->base.source_position, - "traditional C rejects the unary plus operator"); + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_TRADITIONAL, pos, "traditional C rejects the unary plus operator"); } static void semantic_not(unary_expression_t *expression) @@ -8161,8 +8069,7 @@ static void semantic_binexpr_integer(binary_expression_t *const expression) static void warn_div_by_zero(binary_expression_t const *const expression) { - if (!warning.div_by_zero || - !is_type_integer(expression->base.type)) + if (!is_type_integer(expression->base.type)) return; expression_t const *const right = expression->right; @@ -8170,7 +8077,8 @@ static void warn_div_by_zero(binary_expression_t const *const expression) if (is_type_integer(right->base.type) && is_constant_expression(right) == EXPR_CLASS_CONSTANT && !fold_constant_to_bool(right)) { - warningf(&expression->base.source_position, "division by zero"); + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_DIV_BY_ZERO, pos, "division by zero"); } } @@ -8195,8 +8103,8 @@ static void warn_addsub_in_shift(const expression_t *const expr) default: return; } - warningf(&expr->base.source_position, - "suggest parentheses around '%c' inside shift", op); + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest parentheses around '%c' inside shift", op); } static bool semantic_shift(binary_expression_t *expression) @@ -8220,14 +8128,13 @@ static bool semantic_shift(binary_expression_t *expression) type_left = promote_integer(type_left); if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) { - long count = fold_constant_to_int(right); + source_position_t const *const pos = &right->base.source_position; + long const count = fold_constant_to_int(right); if (count < 0) { - warningf(&right->base.source_position, - "shift count must be non-negative"); + warningf(WARN_OTHER, pos, "shift count must be non-negative"); } else if ((unsigned long)count >= get_atomic_type_size(type_left->atomic.akind) * 8) { - warningf(&right->base.source_position, - "shift count must be less than type width"); + warningf(WARN_OTHER, pos, "shift count must be less than type width"); } } @@ -8245,10 +8152,8 @@ static void semantic_shift_op(binary_expression_t *expression) if (!semantic_shift(expression)) return; - if (warning.parentheses) { - warn_addsub_in_shift(left); - warn_addsub_in_shift(right); - } + warn_addsub_in_shift(left); + warn_addsub_in_shift(right); type_t *const orig_type_left = left->base.type; type_t * type_left = skip_typeref(orig_type_left); @@ -8319,8 +8224,8 @@ static void semantic_sub(binary_expression_t *expression) if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) { errorf(pos, "subtracting pointers to non-object types '%T'", orig_type_left); - } else if (warning.other) { - warningf(pos, "subtracting pointers to void"); + } else { + warningf(WARN_OTHER, pos, "subtracting pointers to void"); } } expression->base.type = type_ptrdiff_t; @@ -8341,8 +8246,8 @@ static void warn_string_literal_address(expression_t const* expr) if (expr->kind == EXPR_STRING_LITERAL || expr->kind == EXPR_WIDE_STRING_LITERAL) { - warningf(&expr->base.source_position, - "comparison with string literal results in unspecified behaviour"); + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour"); } } @@ -8357,17 +8262,15 @@ static bool maybe_negative(expression_t const *const expr) static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other) { - if (warning.address) { - warn_string_literal_address(expr); + warn_string_literal_address(expr); - expression_t const* const ref = get_reference_address(expr); - if (ref != NULL && is_null_pointer_constant(other)) { - entity_t const *const ent = ref->reference.entity; - warningf(pos, "the address of '%N' will never be NULL", ent); - } + expression_t const* const ref = get_reference_address(expr); + if (ref != NULL && is_null_pointer_constant(other)) { + entity_t const *const ent = ref->reference.entity; + warningf(WARN_ADDRESS, pos, "the address of '%N' will never be NULL", ent); } - if (warning.parentheses && !expr->base.parenthesized) { + if (!expr->base.parenthesized) { switch (expr->base.kind) { case EXPR_BINARY_LESS: case EXPR_BINARY_GREATER: @@ -8375,7 +8278,7 @@ static void warn_comparison(source_position_t const *const pos, expression_t con case EXPR_BINARY_GREATEREQUAL: case EXPR_BINARY_NOTEQUAL: case EXPR_BINARY_EQUAL: - warningf(pos, "comparisons like 'x <= y < z' do not have their mathematical meaning"); + warningf(WARN_PARENTHESES, pos, "comparisons like 'x <= y < z' do not have their mathematical meaning"); break; default: break; @@ -8407,7 +8310,7 @@ static void semantic_comparison(binary_expression_t *expression) type_t *arithmetic_type = semantic_arithmetic(type_left, type_right); /* test for signed vs unsigned compares */ - if (warning.sign_compare && is_type_integer(arithmetic_type)) { + if (is_type_integer(arithmetic_type)) { bool const signed_left = is_type_signed(type_left); bool const signed_right = is_type_signed(type_right); if (signed_left != signed_right) { @@ -8415,7 +8318,7 @@ static void semantic_comparison(binary_expression_t *expression) /* TODO check whether constant value can be represented by other type */ if ((signed_left && maybe_negative(left)) || (signed_right && maybe_negative(right))) { - warningf(pos, "comparison between signed and unsigned"); + warningf(WARN_SIGN_COMPARE, pos, "comparison between signed and unsigned"); } } } @@ -8423,11 +8326,10 @@ static void semantic_comparison(binary_expression_t *expression) expression->left = create_implicit_cast(left, arithmetic_type); expression->right = create_implicit_cast(right, arithmetic_type); expression->base.type = arithmetic_type; - if (warning.float_equal && - (expression->base.kind == EXPR_BINARY_EQUAL || + if ((expression->base.kind == EXPR_BINARY_EQUAL || expression->base.kind == EXPR_BINARY_NOTEQUAL) && is_type_float(arithmetic_type)) { - warningf(pos, "comparing floating point with == or != is unsafe"); + warningf(WARN_FLOAT_EQUAL, pos, "comparing floating point with == or != is unsafe"); } } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) { /* TODO check compatibility */ @@ -8619,8 +8521,8 @@ static void warn_logical_and_within_or(const expression_t *const expr) return; if (expr->base.parenthesized) return; - warningf(&expr->base.source_position, - "suggest parentheses around && within ||"); + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest parentheses around && within ||"); } /** @@ -8632,8 +8534,7 @@ static void semantic_logical_op(binary_expression_t *expression) * §6.5.14:2 Each of the operands shall have scalar type. */ semantic_condition(expression->left, "left operand of logical operator"); semantic_condition(expression->right, "right operand of logical operator"); - if (expression->base.kind == EXPR_BINARY_LOGICAL_OR && - warning.parentheses) { + if (expression->base.kind == EXPR_BINARY_LOGICAL_OR) { warn_logical_and_within_or(expression->left); warn_logical_and_within_or(expression->right); } @@ -8804,12 +8705,10 @@ static bool expression_has_effect(const expression_t *const expr) static void semantic_comma(binary_expression_t *expression) { - if (warning.unused_value) { - const expression_t *const left = expression->left; - if (!expression_has_effect(left)) { - warningf(&left->base.source_position, - "left-hand operand of comma expression has no effect"); - } + const expression_t *const left = expression->left; + if (!expression_has_effect(left)) { + source_position_t const *const pos = &left->base.source_position; + warningf(WARN_UNUSED_VALUE, pos, "left-hand operand of comma expression has no effect"); } expression->base.type = expression->right->base.type; } @@ -9263,9 +9162,9 @@ static statement_t *parse_case_statement(void) long const val = fold_constant_to_int(end_range); statement->case_label.last_case = val; - if (warning.other && val < statement->case_label.first_case) { + if (val < statement->case_label.first_case) { statement->case_label.is_empty_range = true; - warningf(pos, "empty range specified"); + warningf(WARN_OTHER, pos, "empty range specified"); } } } @@ -9417,11 +9316,10 @@ end_error: if (next_if(T_else)) { statement->ifs.false_statement = parse_statement(); - } else if (warning.parentheses && - true_stmt->kind == STATEMENT_IF && + } else if (true_stmt->kind == STATEMENT_IF && true_stmt->ifs.false_statement != NULL) { - warningf(&true_stmt->base.source_position, - "suggest explicit braces to avoid ambiguous 'else'"); + source_position_t const *const pos = &true_stmt->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'"); } POP_PARENT; @@ -9435,6 +9333,8 @@ end_error: */ static void check_enum_cases(const switch_statement_t *statement) { + if (!is_warn_on(WARN_SWITCH_ENUM)) + return; const type_t *type = skip_typeref(statement->expression->base.type); if (! is_type_enum(type)) return; @@ -9462,7 +9362,8 @@ static void check_enum_cases(const switch_statement_t *statement) } } if (!found) { - warningf(&statement->base.source_position, "'%N' not handled in switch", entry); + source_position_t const *const pos = &statement->base.source_position; + warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry); } last_value = value; } @@ -9486,12 +9387,8 @@ static statement_t *parse_switch(void) type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { type = promote_integer(type); - if (warning.traditional) { - if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) { - warningf(&expr->base.source_position, - "'%T' switch expression not converted to '%T' in ISO C", - type, type_int); - } + if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) { + warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int); } } else if (is_type_valid(type)) { errorf(&expr->base.source_position, @@ -9507,12 +9404,10 @@ static statement_t *parse_switch(void) statement->switchs.body = parse_statement(); current_switch = rem; - if (warning.switch_default && - statement->switchs.default_label == NULL) { - warningf(&statement->base.source_position, "switch has no default case"); + if (statement->switchs.default_label == NULL) { + warningf(WARN_SWITCH_DEFAULT, &statement->base.source_position, "switch has no default case"); } - if (warning.switch_enum) - check_enum_cases(&statement->switchs); + check_enum_cases(&statement->switchs); POP_PARENT; return statement; @@ -9628,9 +9523,8 @@ static statement_t *parse_for(void) expression_t *const init = parse_expression(); statement->fors.initialisation = init; mark_vars_read(init, ENT_ANY); - if (warning.unused_value && !expression_has_effect(init)) { - warningf(&init->base.source_position, - "initialisation of 'for'-statement has no effect"); + if (!expression_has_effect(init)) { + warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect"); } rem_anchor_token(';'); expect(';', end_error2); @@ -9652,9 +9546,8 @@ static statement_t *parse_for(void) expression_t *const step = parse_expression(); statement->fors.step = step; mark_vars_read(step, ENT_ANY); - if (warning.unused_value && !expression_has_effect(step)) { - warningf(&step->base.source_position, - "step of 'for'-statement has no effect"); + if (!expression_has_effect(step)) { + warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect"); } } expect(')', end_error2); @@ -9700,9 +9593,8 @@ static statement_t *parse_goto(void) if (!is_type_pointer(type) && !is_type_integer(type)) { errorf(&expression->base.source_position, "cannot convert to a pointer type"); - } else if (warning.other && type != type_void_ptr) { - warningf(&expression->base.source_position, - "type of computed goto expression should be 'void*' not '%T'", type); + } else if (type != type_void_ptr) { + warningf(WARN_OTHER, &expression->base.source_position, "type of computed goto expression should be 'void*' not '%T'", type); } expression = create_implicit_cast(expression, type_void_ptr); } @@ -9866,18 +9758,16 @@ static statement_t *parse_return(void) if (c_mode & _CXX || strict_mode) { errorf(pos, "'return' with a value, in function returning 'void'"); - } else if (warning.other) { - warningf(pos, - "'return' with a value, in function returning 'void'"); + } else { + warningf(WARN_OTHER, pos, "'return' with a value, in function returning 'void'"); } } else if (!(c_mode & _CXX)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */ /* Only warn in C mode, because GCC does the same */ if (strict_mode) { errorf(pos, "'return' with expression in function returning 'void'"); - } else if (warning.other) { - warningf(pos, - "'return' with expression in function returning 'void'"); + } else { + warningf(WARN_OTHER, pos, "'return' with expression in function returning 'void'"); } } } else { @@ -9887,21 +9777,19 @@ static statement_t *parse_return(void) } return_value = create_implicit_cast(return_value, return_type); /* check for returning address of a local var */ - if (warning.other && return_value != NULL - && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) { + if (return_value != NULL && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) { const expression_t *expression = return_value->unary.value; if (expression_is_local_variable(expression)) { - warningf(pos, "function returns address of local variable"); + warningf(WARN_OTHER, pos, "function returns address of local variable"); } } - } else if (warning.other && !is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { + } else if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */ if (c_mode & _CXX || strict_mode) { errorf(pos, "'return' without value, in function returning non-void"); } else { - warningf(pos, - "'return' without value, in function returning non-void"); + warningf(WARN_OTHER, pos, "'return' without value, in function returning non-void"); } } statement->returns.value = return_value; @@ -10000,9 +9888,7 @@ end_error: static statement_t *parse_empty_statement(void) { - if (warning.empty_statement) { - warningf(HERE, "statement is empty"); - } + warningf(WARN_EMPTY_STATEMENT, HERE, "statement is empty"); statement_t *const statement = create_empty_statement(); eat(';'); return statement; @@ -10207,11 +10093,10 @@ static statement_t *parse_statement(void) { statement_t *statement = intern_parse_statement(); - if (statement->kind == STATEMENT_EXPRESSION && warning.unused_value) { + if (statement->kind == STATEMENT_EXPRESSION) { expression_t *expression = statement->expression.expression; if (!expression_has_effect(expression)) { - warningf(&expression->base.source_position, - "statement has no effect"); + warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect"); } } @@ -10337,13 +10222,11 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) continue; } - if (warning.declaration_after_statement) { - if (sub_statement->kind != STATEMENT_DECLARATION) { - only_decls_so_far = false; - } else if (!only_decls_so_far) { - warningf(&sub_statement->base.source_position, - "ISO C90 forbids mixed declarations and code"); - } + if (sub_statement->kind != STATEMENT_DECLARATION) { + only_decls_so_far = false; + } else if (!only_decls_so_far) { + source_position_t const *const pos = &sub_statement->base.source_position; + warningf(WARN_DECLARATION_AFTER_STATEMENT, pos, "ISO C90 forbids mixed declarations and code"); } *anchor = sub_statement; @@ -10356,7 +10239,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) next_token(); /* look over all statements again to produce no effect warnings */ - if (warning.unused_value) { + if (is_warn_on(WARN_UNUSED_VALUE)) { statement_t *sub_statement = statement->compound.statements; for (; sub_statement != NULL; sub_statement = sub_statement->base.next) { if (sub_statement->kind != STATEMENT_EXPRESSION) @@ -10368,8 +10251,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) expression_t *expression = sub_statement->expression.expression; if (!expression_has_effect(expression)) { - warningf(&expression->base.source_position, - "statement has no effect"); + warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect"); } } } @@ -10475,7 +10357,7 @@ end_error: */ static void check_unused_globals(void) { - if (!warning.unused_function && !warning.unused_variable) + if (!is_warn_on(WARN_UNUSED_FUNCTION) && !is_warn_on(WARN_UNUSED_VARIABLE)) return; for (const entity_t *entity = file_scope->entities; entity != NULL; @@ -10490,18 +10372,21 @@ static void check_unused_globals(void) declaration->storage_class != STORAGE_CLASS_STATIC) continue; - const char *s; + warning_t why; + char const *s; if (entity->kind == ENTITY_FUNCTION) { /* inhibit warning for static inline functions */ if (entity->function.is_inline) continue; - s = entity->function.statement != NULL ? "defined" : "declared"; + why = WARN_UNUSED_FUNCTION; + s = entity->function.statement != NULL ? "defined" : "declared"; } else { - s = "defined"; + why = WARN_UNUSED_VARIABLE; + s = "defined"; } - warningf(&declaration->base.source_position, "'%#N' %s but not used", entity); + warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity); } } @@ -10585,8 +10470,7 @@ static void parse_external(void) case ';': if (!strict_mode) { - if (warning.other) - warningf(HERE, "stray ';' outside of function"); + warningf(WARN_OTHER, HERE, "stray ';' outside of function"); next_token(); return; } @@ -10717,10 +10601,8 @@ static void complete_incomplete_arrays(void) if (!is_type_incomplete(type)) continue; - if (warning.other) { - source_position_t const *const pos = &decl->base.source_position; - warningf(pos, "array '%#N' assumed to have one element", (entity_t const*)decl); - } + source_position_t const *const pos = &decl->base.source_position; + warningf(WARN_OTHER, pos, "array '%#N' assumed to have one element", (entity_t const*)decl); type_t *const new_type = duplicate_type(type); new_type->array.size_constant = true; diff --git a/preprocessor.c b/preprocessor.c index 95743dc..2b077bb 100644 --- a/preprocessor.c +++ b/preprocessor.c @@ -1392,8 +1392,7 @@ static void parse_define_directive(void) pp_definition_t *old_definition = symbol->pp_definition; if (old_definition != NULL) { if (!pp_definitions_equal(old_definition, new_definition)) { - warningf(&input.position, "multiple definition of macro '%Y' (first defined %P)", - symbol, &old_definition->source_position); + warningf(WARN_OTHER, &input.position, "multiple definition of macro '%Y' (first defined %P)", symbol, &old_definition->source_position); } else { /* reuse the old definition */ obstack_free(&pp_obstack, new_definition); @@ -1428,7 +1427,7 @@ static void parse_undef_directive(void) next_preprocessing_token(); if(pp_token.type != '\n') { - warningf(&input.position, "extra tokens at end of #undef directive"); + warningf(WARN_OTHER, &input.position, "extra tokens at end of #undef directive"); } /* eat until '\n' */ eat_pp_directive(); @@ -1524,8 +1523,7 @@ static bool parse_include_directive(void) } if (pp_token.type != '\n' && pp_token.type != TP_EOF) { - warningf(&pp_token.source_position, - "extra tokens at end of #include directive"); + warningf(WARN_OTHER, &pp_token.source_position, "extra tokens at end of #include directive"); eat_pp_directive(); } @@ -1641,7 +1639,7 @@ static void parse_else_directive(void) if (pp_token.type != '\n') { if (!skip_mode) { - warningf(&pp_token.source_position, "extra tokens at end of #else"); + warningf(WARN_OTHER, &pp_token.source_position, "extra tokens at end of #else"); } eat_pp_directive(); } @@ -1673,8 +1671,7 @@ static void parse_endif_directive(void) if (pp_token.type != '\n') { if (!skip_mode) { - warningf(&pp_token.source_position, - "extra tokens at end of #endif"); + warningf(WARN_OTHER, &pp_token.source_position, "extra tokens at end of #endif"); } eat_pp_directive(); } diff --git a/type.c b/type.c index c877093..eccc07e 100644 --- a/type.c +++ b/type.c @@ -1793,14 +1793,11 @@ void layout_struct_type(compound_type_t *type) } } + source_position_t const *const pos = &compound->base.source_position; if (need_pad) { - if (warning.padded) { - warningf(&compound->base.source_position, "'%T' needs padding", - type); - } - } else if (compound->packed && warning.packed) { - warningf(&compound->base.source_position, - "superfluous packed attribute on '%T'", type); + warningf(WARN_PADDED, pos, "'%T' needs padding", type); + } else if (compound->packed) { + warningf(WARN_PACKED, pos, "superfluous packed attribute on '%T'", type); } compound->size = offset; diff --git a/warning.c b/warning.c index 6804537..65e39dd 100644 --- a/warning.c +++ b/warning.c @@ -17,257 +17,171 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ +#include #include #include + +#include "adt/util.h" #include "warning.h" #include "help.h" -warning_t warning = { - .other = true, - - .address = true, - .aggregate_return = false, - .attribute = true, - .cast_qual = false, - .char_subscripts = true, - .comment = false, - .conversion = false, - .declaration_after_statement = false, - .deprecated_declarations = true, - .div_by_zero = true, - .empty_statement = false, - .error_implicit_function_declaration = false, - .fatal_errors = false, - .float_equal = false, - .format = true, - .implicit_function_declaration = true, - .implicit_int = true, - .init_self = true, - .long_long = false, - .main = true, - .missing_declarations = false, - .missing_noreturn = false, - .missing_prototypes = false, - .multichar = true, - .nested_externs = false, - .nonnull = true, - .old_style_definition = false, - .packed = false, - .padded = false, - .parentheses = false, - .pointer_arith = true, - .redundant_decls = true, - .return_type = true, - .s_are_errors = false, - .shadow = false, - .shadow_local = false, - .sign_compare = false, - .strict_prototypes = true, - .switch_default = false, - .switch_enum = false, - .traditional = false, - .uninitialized = true, - .unknown_pragmas = true, - .unreachable_code = false, - .unused_function = false, - .unused_label = false, - .unused_parameter = false, - .unused_value = true, - .unused_variable = false, - .write_strings = false +static warning_switch_t warning[] = { + [WARN_ADDRESS] = { WARN_LEVEL_ON, "address" }, + [WARN_AGGREGATE_RETURN] = { WARN_LEVEL_OFF, "aggregate-return" }, + [WARN_ATTRIBUTE] = { WARN_LEVEL_ON, "attribute" }, + [WARN_CAST_QUAL] = { WARN_LEVEL_OFF, "cast-qual", }, + [WARN_CHAR_SUBSCRIPTS] = { WARN_LEVEL_ON, "char-subscripts", }, + [WARN_COMMENT] = { WARN_LEVEL_OFF, "comment", }, + [WARN_CONVERSION] = { WARN_LEVEL_OFF, "conversion", }, + [WARN_DECLARATION_AFTER_STATEMENT] = { WARN_LEVEL_OFF, "declaration-after-statement", }, + [WARN_DEPRECATED_DECLARATIONS] = { WARN_LEVEL_ON, "deprecated-declarations", }, + [WARN_DIV_BY_ZERO] = { WARN_LEVEL_ON, "div-by-zero", }, + [WARN_EMPTY_STATEMENT] = { WARN_LEVEL_OFF, "empty-statement", }, + [WARN_ERROR] = { WARN_LEVEL_OFF, "error" }, + [WARN_FATAL_ERRORS] = { WARN_LEVEL_OFF, "fatal-errors" }, + [WARN_FLOAT_EQUAL] = { WARN_LEVEL_OFF, "float-equal", }, + [WARN_FORMAT] = { WARN_LEVEL_ON, "format" }, + [WARN_IMPLICIT_FUNCTION_DECLARATION] = { WARN_LEVEL_ON, "implicit-function-declaration" }, + [WARN_IMPLICIT_INT] = { WARN_LEVEL_ON, "implicit-int" }, + [WARN_INIT_SELF] = { WARN_LEVEL_ON, "init-self", }, + [WARN_LONG_LONG] = { WARN_LEVEL_OFF, "long-long" }, + [WARN_MAIN] = { WARN_LEVEL_ON, "main", }, + [WARN_MISSING_DECLARATIONS] = { WARN_LEVEL_OFF, "missing-declarations", }, + [WARN_MISSING_NORETURN] = { WARN_LEVEL_OFF, "missing-noreturn", }, + [WARN_MISSING_PROTOTYPES] = { WARN_LEVEL_OFF, "missing-prototypes", }, + [WARN_MULTICHAR] = { WARN_LEVEL_ON, "multichar", }, + [WARN_NESTED_EXTERNS] = { WARN_LEVEL_OFF, "nested-externs" }, + [WARN_NONNULL] = { WARN_LEVEL_ON, "nonnull", }, + [WARN_OLD_STYLE_DEFINITION] = { WARN_LEVEL_OFF, "old-style-definition", }, + [WARN_OTHER] = { WARN_LEVEL_ON, "other" }, + [WARN_PACKED] = { WARN_LEVEL_OFF, "packed", }, + [WARN_PADDED] = { WARN_LEVEL_OFF, "padded", }, + [WARN_PARENTHESES] = { WARN_LEVEL_OFF, "parentheses", }, + [WARN_POINTER_ARITH] = { WARN_LEVEL_ON, "pointer-arith", }, + [WARN_REDUNDANT_DECLS] = { WARN_LEVEL_ON, "redundant-decls", }, + [WARN_RETURN_TYPE] = { WARN_LEVEL_ON, "return-type", }, + [WARN_SHADOW] = { WARN_LEVEL_OFF, "shadow", }, + [WARN_SHADOW_LOCAL] = { WARN_LEVEL_OFF, "shadow-local", }, + [WARN_SIGN_COMPARE] = { WARN_LEVEL_OFF, "sign-compare", }, + [WARN_STRICT_PROTOTYPES] = { WARN_LEVEL_ON, "strict-prototypes" }, + [WARN_SWITCH_DEFAULT] = { WARN_LEVEL_OFF, "switch-default", }, + [WARN_SWITCH_ENUM] = { WARN_LEVEL_OFF, "switch-enum", }, + [WARN_TRADITIONAL] = { WARN_LEVEL_OFF, "traditional" }, + [WARN_UNINITIALIZED] = { WARN_LEVEL_ON, "uninitialized", }, + [WARN_UNKNOWN_PRAGMAS] = { WARN_LEVEL_ON, "unknown-pragmas", }, + [WARN_UNREACHABLE_CODE] = { WARN_LEVEL_OFF, "unreachable-code" }, + [WARN_UNUSED_FUNCTION] = { WARN_LEVEL_OFF, "unused-function", }, + [WARN_UNUSED_LABEL] = { WARN_LEVEL_OFF, "unused-label", }, + [WARN_UNUSED_PARAMETER] = { WARN_LEVEL_OFF, "unused-parameter", }, + [WARN_UNUSED_VALUE] = { WARN_LEVEL_ON, "unused-value", }, + [WARN_UNUSED_VARIABLE] = { WARN_LEVEL_OFF, "unused-variable", }, + [WARN_WRITE_STRINGS] = { WARN_LEVEL_OFF, "write-strings", }, }; +warning_switch_t const *get_warn_switch(warning_t const w) +{ + assert((size_t)w < lengthof(warning)); + assert(warning[w].name); + return &warning[w]; +} + void print_warning_opt_help(void) { /* TODO: write explanations */ - put_help("-Waddress", ""); - put_help("-Wall", ""); - put_help("-Waggregate-return", ""); - put_help("-Wattribute", ""); - put_help("-Wcast-qual", ""); - put_help("-Wchar-subscripts", ""); - put_help("-Wcomment", ""); - put_help("-Wconversion", ""); - put_help("-Wdeclaration-after-statement", ""); - put_help("-Wdeprecated-declarations", ""); - put_help("-Wdiv-by-zero", ""); - put_help("-Wempty-statement", ""); - put_help("-Werror", "warnings are errors"); - put_help("-Werror-implicit-function-declaration", ""); - put_help("-Wextra", ""); - put_help("-Wfatal-errors", ""); - put_help("-Wfloat-equal", ""); - put_help("-Wformat", ""); - put_help("-Wimplicit", ""); - put_help("-Wimplicit-function-declaration", ""); - put_help("-Wimplicit-int", ""); - put_help("-Winit-self", ""); - put_help("-Wlong-long", ""); - put_help("-Wmain", ""); - put_help("-Wmissing-declarations", ""); - put_help("-Wmissing-noreturn", ""); - put_help("-Wmissing-prototypes", ""); - put_help("-Wmultichar", ""); - put_help("-Wnested-externs", ""); - put_help("-Wnonnull", ""); - put_help("-Wold-style-definition", ""); - put_help("-Wparentheses", ""); - put_help("-Wpacked", ""); - put_help("-Wpadded", ""); - put_help("-Wparentheses", ""); - put_help("-Wpointer-arith", ""); - put_help("-Wredundant-decls", ""); - put_help("-Wreturn-type", ""); - put_help("-Wshadow", ""); - put_help("-Wshadow-local", ""); - put_help("-Wsign-compare", ""); - put_help("-Wstrict-prototypes", ""); - put_help("-Wswitch-default", ""); - put_help("-Wswitch-enum", ""); - put_help("-Wtraditional", ""); - put_help("-Wuninitialized", ""); - put_help("-Wunknown-pragmas", ""); - put_help("-Wunreachable-code", ""); - put_help("-Wunused", ""); - put_help("-Wunused-function", ""); - put_help("-Wunused-label", ""); - put_help("-Wunused-parameter", ""); - put_help("-Wunused-value", ""); - put_help("-Wunused-variable", ""); - put_help("-Wwrite-strings", ""); + for (warning_switch_t* i = warning; i != endof(warning); ++i) { + put_help(i->name, ""); + } } void set_warning_opt(const char *const opt) { const char* s = opt; - bool state = true; + warn_level_t const level = + strncmp(s, "no-", 3) == 0 ? s += 3, WARN_LEVEL_OFF : /* "no-" prefix */ + strncmp(s, "error-", 6) == 0 ? s += 6, WARN_LEVEL_ERROR : /* "error-" prefix */ + WARN_LEVEL_ON; - /* "no-" prefix */ - if (s[0] == 'n' && s[1] == 'o' && s[2] == '-') { - s += 3; - state = false; + for (warning_switch_t* i = warning; i != endof(warning); ++i) { + if (strcmp(i->name, s) == 0) { + i->level = level; + return; + } } if (s[0] == '\0') { // -W is an alias for -Wextra goto extra; } #define OPTX(x) else if (strcmp(s, x) == 0) -#define SET(y) (void)(warning.y = state) -#define OPT(x, y) OPTX(x) SET(y) +#define SET(y) (void)(warning[y].level = level) OPTX("all") { /* Note: this switched on a lot more warnings than gcc's -Wall */ - SET(other); - - SET(address); - SET(attribute); - SET(char_subscripts); - SET(comment); - SET(empty_statement); - SET(format); - SET(implicit_function_declaration); - SET(implicit_int); - SET(init_self); - SET(main); - SET(missing_declarations); - SET(nonnull); - SET(parentheses); - SET(pointer_arith); - SET(redundant_decls); - SET(return_type); - SET(shadow_local); - SET(sign_compare); - SET(strict_prototypes); - SET(switch_enum); - SET(uninitialized); - SET(unknown_pragmas); - SET(unreachable_code); - SET(unused_function); - SET(unused_label); - SET(unused_parameter); - SET(unused_value); - SET(unused_variable); + SET(WARN_ADDRESS); + SET(WARN_ATTRIBUTE); + SET(WARN_CHAR_SUBSCRIPTS); + SET(WARN_COMMENT); + SET(WARN_EMPTY_STATEMENT); + SET(WARN_FORMAT); + SET(WARN_IMPLICIT_FUNCTION_DECLARATION); + SET(WARN_IMPLICIT_INT); + SET(WARN_INIT_SELF); + SET(WARN_MAIN); + SET(WARN_MISSING_DECLARATIONS); + SET(WARN_NONNULL); + SET(WARN_OTHER); + SET(WARN_PARENTHESES); + SET(WARN_POINTER_ARITH); + SET(WARN_REDUNDANT_DECLS); + SET(WARN_RETURN_TYPE); + SET(WARN_SHADOW_LOCAL); + SET(WARN_SIGN_COMPARE); + SET(WARN_STRICT_PROTOTYPES); + SET(WARN_SWITCH_ENUM); + SET(WARN_UNINITIALIZED); + SET(WARN_UNKNOWN_PRAGMAS); + SET(WARN_UNREACHABLE_CODE); + SET(WARN_UNUSED_FUNCTION); + SET(WARN_UNUSED_LABEL); + SET(WARN_UNUSED_PARAMETER); + SET(WARN_UNUSED_VALUE); + SET(WARN_UNUSED_VARIABLE); } - OPT("address", address); - OPT("aggregate-return", aggregate_return); - OPT("attribute", attribute); - OPT("cast-qual", cast_qual); - OPT("char-subscripts", char_subscripts); - OPT("comment", comment); - OPT("conversion", conversion); - OPT("declaration-after-statement", declaration_after_statement); - OPT("deprecated-declarations", deprecated_declarations); - OPT("div-by-zero", div_by_zero); - OPT("empty-statement", empty_statement); - OPT("error", s_are_errors); - OPT("error-implicit-function-declaration", error_implicit_function_declaration); OPTX("extra") { extra: /* TODO */ // TODO SET(function_end_without_return); - SET(empty_statement); + SET(WARN_EMPTY_STATEMENT); // TODO SET(incomplete_aggregate_init); // TODO SET(missing_field_initializers); // TODO SET(pointless_comparison); - SET(shadow); - SET(unused_parameter); - SET(unused_value); - } - OPT("fatal-errors", fatal_errors); - OPT("float-equal", float_equal); - OPTX("format") { - SET(format); - SET(nonnull); + SET(WARN_SHADOW); + SET(WARN_UNUSED_PARAMETER); + SET(WARN_UNUSED_VALUE); } OPTX("implicit") { - SET(implicit_function_declaration); - SET(implicit_int); + SET(WARN_IMPLICIT_FUNCTION_DECLARATION); + SET(WARN_IMPLICIT_INT); } - OPT("implicit-function-declaration", implicit_function_declaration); - OPT("implicit-int", implicit_int); - OPT("init-self", init_self); - OPT("long-long", long_long); - OPT("main", main); - OPT("missing-declarations", missing_declarations); - OPT("missing-noreturn", missing_noreturn); - OPT("missing-prototypes", missing_prototypes); - OPT("multichar", multichar); - OPT("nested-externs", nested_externs); - OPT("nonnull", nonnull); - OPT("old-style-definition", old_style_definition); - OPT("packed", packed); - OPT("padded", padded); - OPT("parentheses", parentheses); - OPT("pointer-arith", pointer_arith); - OPT("redundant-decls", redundant_decls); - OPT("return-type", return_type); - OPT("shadow", shadow); - OPT("shadow-local", shadow_local); - OPT("sign-compare", sign_compare); - OPT("strict-prototypes", strict_prototypes); - OPT("switch-default", switch_default); - OPT("switch-enum", switch_enum); - OPT("traditional", traditional); - OPT("uninitialized", uninitialized); - OPT("unknown-pragmas", unknown_pragmas); - OPT("unreachable-code", unreachable_code); OPTX("unused") { - SET(unused_function); - SET(unused_label); - SET(unused_parameter); - SET(unused_value); - SET(unused_variable); + SET(WARN_UNUSED_FUNCTION); + SET(WARN_UNUSED_LABEL); + SET(WARN_UNUSED_PARAMETER); + SET(WARN_UNUSED_VALUE); + SET(WARN_UNUSED_VARIABLE); } - OPT("unused-function", unused_function); - OPT("unused-label", unused_label); - OPT("unused-parameter", unused_parameter); - OPT("unused-value", unused_value); - OPT("unused-variable", unused_variable); - OPT("write-strings", write_strings); -#undef OPT #undef SET #undef OPT_X else { fprintf(stderr, "warning: ignoring unknown option -W%s\n", opt); } } + +void disable_all_warnings(void) +{ + for (warning_switch_t* i = warning; i != endof(warning); ++i) { + if (i != &warning[WARN_ERROR] && + i != &warning[WARN_FATAL_ERRORS]) { + i->level = WARN_LEVEL_OFF; + } + } +} diff --git a/warning.h b/warning.h index 32f4404..68ba6dd 100644 --- a/warning.h +++ b/warning.h @@ -24,96 +24,112 @@ void set_warning_opt(const char *opt); -void print_warning_opt_help(void); +void disable_all_warnings(void); -typedef struct warning_t { - bool other:1; /**< Warnings not covered by any option below */ +void print_warning_opt_help(void); - bool address:1; /**< Warn about suspicious uses of memory addresses */ - bool aggregate_return:1; /**< Warn if any functions that return structures or unions are defined or called */ - bool attribute:1; /**< Warn if an unexpected `__attribute__' is used or function attributes applied to variables, etc. */ +typedef enum warning_t { + WARN_ADDRESS, /**< Warn about suspicious uses of memory addresses */ + WARN_AGGREGATE_RETURN, /**< Warn if any functions that return structures or unions are defined or called */ + WARN_ATTRIBUTE, /**< Warn if an unexpected `__attribute__' is used or function attributes applied to variables, etc. */ #if 0 // TODO - bool bad_function_cast:1; /**< Warn whenever a function call is cast to a non-matching type */ - bool cast_align:1; /**< Warn whenever a pointer is cast such that the required alignment of the target is increased */ + WARN_BAD_FUNCTION_CAST, /**< Warn whenever a function call is cast to a non-matching type */ + WARN_CAST_ALIGN, /**< Warn whenever a pointer is cast such that the required alignment of the target is increased */ #endif - bool cast_qual:1; /**< Warn whenever a pointer is cast so as to remove a type qualifier from the target type */ - bool char_subscripts:1; /**< Warn if an array subscript has the type 'char' */ - bool comment:1; /**< Warn whenever a comment-start sequence appears in a comment, or whenever a Backslash-Newline appears in a '//' comment. */ - bool conversion:1; /**< Warn if a prototype causes a type conversion that is different from what would happen to the same argument in the absence of a prototype */ + WARN_CAST_QUAL, /**< Warn whenever a pointer is cast so as to remove a type qualifier from the target type */ + WARN_CHAR_SUBSCRIPTS, /**< Warn if an array subscript has the type 'char' */ + WARN_COMMENT, /**< Warn whenever a comment-start sequence appears in a comment, or whenever a Backslash-Newline appears in a '//' comment. */ + WARN_CONVERSION, /**< Warn if a prototype causes a type conversion that is different from what would happen to the same argument in the absence of a prototype */ #if 0 // TODO - bool cpp_compat:1; /**< Warn about ISO C constructs that are outside of the common subset of ISO C and ISO C++. */ + WARN_CPP_COMPAT, /**< Warn about ISO C constructs that are outside of the common subset of ISO C and ISO C++. */ #endif - bool declaration_after_statement:1; /**< Warn when a declaration is found after a statement in a block */ - bool deprecated_declarations:1; /* TODO implement for types */ /**< Warn about uses of functions, variables and types marked as deprecated by using the 'deprecated' attribute */ - bool div_by_zero:1; /**< Warn about compile-time integer division by zero */ - bool empty_statement:1; /**< Warn about empty statements, i.e. lone ';' */ + WARN_DECLARATION_AFTER_STATEMENT, /**< Warn when a declaration is found after a statement in a block */ + WARN_DEPRECATED_DECLARATIONS, /* TODO implement for types */ /**< Warn about uses of functions, variables and types marked as deprecated by using the 'deprecated' attribute */ + WARN_DIV_BY_ZERO, /**< Warn about compile-time integer division by zero */ + WARN_EMPTY_STATEMENT, /**< Warn about empty statements, i.e. lone ';' */ #if 0 // TODO - bool endif_labels:1; /**< Warn whenever an '#else' or an '#endif' are followed by text */ + WARN_ENDIF_LABELS, /**< Warn whenever an '#else' or an '#endif' are followed by text */ #endif - bool error_implicit_function_declaration:1; /**< Generate an error, when calling a function without a prior declaration */ - bool fatal_errors:1; /**< First error stops the compilation */ - bool float_equal:1; /**< Warn if floating point values are used in equality comparisons */ - bool format:1; /**< Check printf-style format strings */ - bool implicit_function_declaration:1; /**< Warn whenever a function is used before being declared */ - bool implicit_int:1; /**< Warn when a declaration does not specify a type */ - bool init_self:1; /**< Warn about uninitialized variables which are initialized with themselves. */ + WARN_ERROR, /**< Treat warnings as errors */ + WARN_FATAL_ERRORS, /**< First error stops the compilation */ + WARN_FLOAT_EQUAL, /**< Warn if floating point values are used in equality comparisons */ + WARN_FORMAT, /**< Check printf-style format strings */ + WARN_IMPLICIT_FUNCTION_DECLARATION, /**< Warn whenever a function is used before being declared */ + WARN_IMPLICIT_INT, /**< Warn when a declaration does not specify a type */ + WARN_INIT_SELF, /**< Warn about uninitialized variables which are initialized with themselves. */ #if 0 // TODO - bool inline:1; /**< Warn if a function can not be inlined and it was declared as inline */ - bool int_to_pointer_cast:1; /**< Warn if cast from integer to pointer of different size. */ + WARN_INLINE, /**< Warn if a function can not be inlined and it was declared as inline */ + WARN_INT_TO_POINTER_CAST, /**< Warn if cast from integer to pointer of different size. */ #endif - bool long_long:1; /**< Warn if 'long long' type is used */ - bool main:1; /**< Warn if the type of 'main' is suspicious */ + WARN_LONG_LONG, /**< Warn if 'long long' type is used */ + WARN_MAIN, /**< Warn if the type of 'main' is suspicious */ #if 0 // TODO - bool missing_braces:1; /**< Warn if an aggregate or union initializer is not fully bracketed */ + WARN_MISSING_BRACES, /**< Warn if an aggregate or union initializer is not fully bracketed */ #endif - bool missing_declarations:1; /**< Warn if a global function is defined without a previous declaration */ + WARN_MISSING_DECLARATIONS, /**< Warn if a global function is defined without a previous declaration */ #if 0 // TODO - bool missing_field_initializers:1; /**< Warn if a structure's initializer has some fields missing. */ - bool missing_format_attribute:1; /**< If '-Wformat' is enabled, also warn about functions which might be candidates for 'format' attributes */ + WARN_MISSING_FIELD_INITIALIZERS, /**< Warn if a structure's initializer has some fields missing. */ + WARN_MISSING_FORMAT_ATTRIBUTE, /**< If '-Wformat' is enabled, also warn about functions which might be candidates for 'format' attributes */ #endif - bool missing_noreturn:1; /**< Warn about functions which might be candidates for attribute 'noreturn' */ - bool missing_prototypes:1; /**< Warn if a global function is defined without a previous prototype declaration */ - bool multichar:1; /**< Warn if a multicharacter constant ('FOOF') is used. */ - bool nested_externs:1; /**< Warn if an 'extern' declaration is encountered within a function. */ - bool nonnull:1; /**< Warn about passing a null pointer for arguments marked nonnull. */ - bool old_style_definition:1; /**< Warn if an old-style function definition is used. */ - bool packed:1; /**< Warn if a structure is given the packed attribute, but the packed attribute has no effect on the layout or size of the structure */ - bool padded:1; /**< Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure */ - bool parentheses:1; /**< Warn if parentheses are omitted in certain contexts (assignment where truth value is expected, if-else-braces) */ - bool pointer_arith:1; /**< Warn about anything that depends on the "size of" a function type or of 'void' */ + WARN_MISSING_NORETURN, /**< Warn about functions which might be candidates for attribute 'noreturn' */ + WARN_MISSING_PROTOTYPES, /**< Warn if a global function is defined without a previous prototype declaration */ + WARN_MULTICHAR, /**< Warn if a multicharacter constant ('FOOF') is used. */ + WARN_NESTED_EXTERNS, /**< Warn if an 'extern' declaration is encountered within a function. */ + WARN_NONNULL, /**< Warn about passing a null pointer for arguments marked nonnull. */ + WARN_OLD_STYLE_DEFINITION, /**< Warn if an old-style function definition is used. */ + WARN_OTHER, /**< Warnings not covered by any other option */ + WARN_PACKED, /**< Warn if a structure is given the packed attribute, but the packed attribute has no effect on the layout or size of the structure */ + WARN_PADDED, /**< Warn if padding is included in a structure, either to align an element of the structure or to align the whole structure */ + WARN_PARENTHESES, /**< Warn if parentheses are omitted in certain contexts (assignment where truth value is expected, if-else-braces) */ + WARN_POINTER_ARITH, /**< Warn about anything that depends on the "size of" a function type or of 'void' */ #if 0 // TODO - bool pointer_to_int_cast:1; /**< Warn if cast from pointer to integer of different size. */ + WARN_POINTER_TO_INT_CAST, /**< Warn if cast from pointer to integer of different size. */ #endif - bool redundant_decls:1; /**< Warn about redundant declarations */ - bool return_type:1; /* TODO not fully implemented */ /**< Warn about function definitions with a return-type that defaults to 'int'. Also warn about any 'return' statement with no return-value in a function whose return-type is not 'void'. */ - bool s_are_errors:1; /**< Treat warnings as errors */ + WARN_REDUNDANT_DECLS, /**< Warn about redundant declarations */ + WARN_RETURN_TYPE, /* TODO not fully implemented */ /**< Warn about function definitions with a return-type that defaults to 'int'. Also warn about any 'return' statement with no return-value in a function whose return-type is not 'void'. */ #if 0 // TODO - bool sequence_point:1; /**< Warn about code that may have undefined semantics because of violations of sequence point rules */ + WARN_SEQUENCE_POINT, /**< Warn about code that may have undefined semantics because of violations of sequence point rules */ #endif - bool shadow:1; /**< Warn whenever a local variable shadows another local variable, parameter or global variable or whenever a built-in function is shadowed */ - bool shadow_local:1; - bool sign_compare:1; /**< Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned */ + WARN_SHADOW, /**< Warn whenever a local variable shadows another local variable, parameter or global variable or whenever a built-in function is shadowed */ + WARN_SHADOW_LOCAL, + WARN_SIGN_COMPARE, /**< Warn when a comparison between signed and unsigned values could produce an incorrect result when the signed value is converted to unsigned */ #if 0 // TODO - bool strict_aliasing:1; /**< Warn about code which might break the strict aliasing rules that the compiler is using for optimization. */ + WARN_STRICT_ALIASING, /**< Warn about code which might break the strict aliasing rules that the compiler is using for optimization. */ #endif - bool strict_prototypes:1; /**< Warn if a function declaration has an unspecified parameter list */ - bool switch_default:1; /**< Warn whenever a 'switch' statement does not have a 'default' case */ - bool switch_enum:1; /**< Warn about 'switch' statements with an enum as index type and missing case labels or case labels outside the enum range TODO has an alias -Wswitch? */ - bool traditional:1; /**< Warn about certain constructs that behave differently in traditional and ISO C */ + WARN_STRICT_PROTOTYPES, /**< Warn if a function declaration has an unspecified parameter list */ + WARN_SWITCH_DEFAULT, /**< Warn whenever a 'switch' statement does not have a 'default' case */ + WARN_SWITCH_ENUM, /**< Warn about 'switch' statements with an enum as index type and missing case labels or case labels outside the enum range TODO has an alias -Wswitch? */ + WARN_TRADITIONAL, /**< Warn about certain constructs that behave differently in traditional and ISO C */ #if 0 // TODO - bool undef:1; /**< Warn if an undefined identifier is evaluated in an '#if' directive */ + WARN_UNDEF, /**< Warn if an undefined identifier is evaluated in an '#if' directive */ #endif - bool uninitialized:1; /**< Warn if an automatic variable is used without being initialized or if a variable may be clobbered by a 'setjmp' call. */ - bool unknown_pragmas:1; /**< Warn when a #pragma directive is encountered which is not understood */ - bool unreachable_code:1; /**< Warn if the compiler detects that code will never be executed */ - bool unused_function:1; /**< Warn whenever a static function is declared but not defined or a non-inline static function is unused */ - bool unused_label:1; /**< Warn whenever a label is declared but not used */ - bool unused_parameter:1; /**< Warn whenever a function parameter is unused aside from its declaration */ - bool unused_value:1; /**< Warn whenever a statement computes a result that is explicitly not used */ - bool unused_variable:1; /**< Warn whenever a local variable or non-constant static variable is unused aside from its declaration */ - bool write_strings:1; /**< Give string constants the type 'const char[LENGTH]' so that copying the address of one into a 'char *' pointer will get a warning */ + WARN_UNINITIALIZED, /**< Warn if an automatic variable is used without being initialized or if a variable may be clobbered by a 'setjmp' call. */ + WARN_UNKNOWN_PRAGMAS, /**< Warn when a #pragma directive is encountered which is not understood */ + WARN_UNREACHABLE_CODE, /**< Warn if the compiler detects that code will never be executed */ + WARN_UNUSED_FUNCTION, /**< Warn whenever a static function is declared but not defined or a non-inline static function is unused */ + WARN_UNUSED_LABEL, /**< Warn whenever a label is declared but not used */ + WARN_UNUSED_PARAMETER, /**< Warn whenever a function parameter is unused aside from its declaration */ + WARN_UNUSED_VALUE, /**< Warn whenever a statement computes a result that is explicitly not used */ + WARN_UNUSED_VARIABLE, /**< Warn whenever a local variable or non-constant static variable is unused aside from its declaration */ + WARN_WRITE_STRINGS, /**< Give string constants the type 'const char[LENGTH]' so that copying the address of one into a 'char *' pointer will get a warning */ } warning_t; -extern warning_t warning; +typedef enum warn_level_t { + WARN_LEVEL_OFF, + WARN_LEVEL_ON, + WARN_LEVEL_ERROR +} warn_level_t; + +typedef struct warning_switch_t { + warn_level_t level; + char const* const name; +} warning_switch_t; + +warning_switch_t const *get_warn_switch(warning_t); + +static inline bool is_warn_on(warning_t const warn) +{ + return get_warn_switch(warn)->level != WARN_LEVEL_OFF; +} #endif -- 2.20.1