Improve diagnostic handling: Add [-Wfoo] and -Werror-foo.
authorChristoph Mallon <christoph.mallon@gmx.de>
Tue, 21 Jun 2011 13:43:56 +0000 (15:43 +0200)
committerChristoph Mallon <christoph.mallon@gmx.de>
Tue, 21 Jun 2011 13:54:45 +0000 (15:54 +0200)
- 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.

14 files changed:
adt/util.h
ast2firm.c
attribute.c
cparser.1
diagnostic.c
diagnostic.h
format_check.c
lexer.c
main.c
parser.c
preprocessor.c
type.c
warning.c
warning.h

index 61c3c7d..54dfc83 100644 (file)
@@ -52,4 +52,6 @@
 
 #define lengthof(x) (sizeof(x) / sizeof(*(x)))
 
+#define endof(x) ((x) + lengthof(x))
+
 #endif
index 4e9efa5..559b1c2 100644 (file)
@@ -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);
        }
index 3e2101b..07f152b 100644 (file)
@@ -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;
        }
 
index 3700bd9..1b7a266 100644 (file)
--- 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 )
index 5fb6677..6376abb 100644 (file)
 #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, ...)
index 7f00a43..313a2a9 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <stdbool.h>
 #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;
index 38423d9..16eafd1 100644 (file)
@@ -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 (file)
--- 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 (file)
--- 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");
index d9397d9..90e8ca4 100644 (file)
--- 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, "<builtin>") != 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 = &current_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;
index 95743dc..2b077bb 100644 (file)
@@ -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 (file)
--- 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;
index 6804537..65e39dd 100644 (file)
--- a/warning.c
+++ b/warning.c
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
  * 02111-1307, USA.
  */
+#include <assert.h>
 #include <stdio.h>
 #include <string.h>
+
+#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;
+               }
+       }
+}
index 32f4404..68ba6dd 100644 (file)
--- a/warning.h
+++ b/warning.h
 
 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