Implement a new agile warning framework.
authorChristoph Mallon <christoph.mallon@gmx.de>
Thu, 13 Dec 2007 15:26:45 +0000 (15:26 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Thu, 13 Dec 2007 15:26:45 +0000 (15:26 +0000)
[r18730]

Makefile
diagnostic.c
diagnostic.h
format_check.c
main.c
parser.c
warning.c [new file with mode: 0644]
warning.h [new file with mode: 0644]

index d0f3a6c..e9c4c30 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -36,6 +36,7 @@ SOURCES := \
        type.c \
        types.c \
        type_hash.c \
+       warning.c \
        write_fluffy.c \
        driver/firm_cmdline.c \
        driver/firm_timing.c \
index c1a4ad8..abfa8eb 100644 (file)
@@ -6,6 +6,7 @@
 #include "diagnostic.h"
 #include "token_t.h"
 #include "type.h"
+#include "warning.h"
 
 /** Number of occurred diagnostics. */
 unsigned diagnostic_count = 0;
@@ -15,10 +16,6 @@ unsigned error_count      = 0;
 unsigned warning_count    = 0;
 /** true if warnings should be inhibited */
 bool inhibit_all_warnings = false;
-/** true if warnings should be treated as errors */
-bool warnings_are_errors  = false;
-/** true if the first error should stop the compilation */
-bool fatal_errors = false;
 
 /**
  * Issue a diagnostic message.
@@ -147,18 +144,16 @@ static void errorvf(const source_position_t pos,
        diagnosticvf(fmt, ap);
        fputc('\n', stderr);
 
-       if (fatal_errors)
-               abort();
+       if (warning.fatal_errors)
+               exit(EXIT_FAILURE);
 }
+
 void errorf(const source_position_t pos, const char *const fmt, ...)
 {
        va_list ap;
        va_start(ap, fmt);
        errorvf(pos, fmt, ap);
        va_end(ap);
-
-       if (fatal_errors)
-               exit(1);
 }
 
 static void warningvf(const source_position_t pos,
@@ -177,7 +172,7 @@ void warningf(const source_position_t pos, const char *const fmt, ...)
 
        va_list ap;
        va_start(ap, fmt);
-       if (warnings_are_errors) {
+       if (warning.s_are_errors) {
                errorvf(pos, fmt, ap);
        } else {
                warningvf(pos, fmt, ap);
index cd75562..b24956b 100644 (file)
@@ -14,10 +14,4 @@ extern unsigned warning_count;
 /* true if warnings should be inhibited */
 extern bool inhibit_all_warnings;
 
-/* true if warnings should be treated as errors */
-extern bool warnings_are_errors;
-
-/* true if the first error should stop the compilation */
-extern bool fatal_errors;
-
 #endif
index 04c7018..851f41b 100644 (file)
@@ -5,6 +5,7 @@
 #include "format_check.h"
 #include "types.h"
 #include "type_t.h"
+#include "warning.h"
 
 
 typedef enum format_flag_t {
@@ -397,6 +398,9 @@ next_arg:
 
 void check_format(const call_expression_t *const call)
 {
+       if (!warning.check_format)
+               return;
+
        const expression_t *const func_expr = call->function;
        if (func_expr->kind != EXPR_REFERENCE)
                return;
diff --git a/main.c b/main.c
index 7df2b42..3ad74ba 100644 (file)
--- a/main.c
+++ b/main.c
@@ -57,6 +57,7 @@
 #include "adt/error.h"
 #include "write_fluffy.h"
 #include "revision.h"
+#include "warning.h"
 
 #ifndef PREPROCESSOR
 #define PREPROCESSOR "cpp -std=c99 -U__WCHAR_TYPE__ -D__WCHAR_TYPE__=int"
@@ -456,13 +457,7 @@ int main(int argc, char **argv)
                } else if(arg[0] == '-' && arg[1] == 'W') {
                        const char *opt;
                        GET_ARG_AFTER(opt, "-W");
-                       if (strcmp(opt, "error") == 0) {
-                               warnings_are_errors = true;
-                       } else if (strcmp(opt, "fatal-errors") == 0) {
-                               fatal_errors = true;
-                       } else {
-                               fprintf(stderr, "warning: ignoring gcc option -W%s\n", opt);
-                       }
+                       set_warning_opt(opt);
                } else if(arg[0] == '-' && arg[1] == 'm') {
                        const char *opt;
                        GET_ARG_AFTER(opt, "-m");
index a08c74c..1597599 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -14,6 +14,7 @@
 #include "type_hash.h"
 #include "ast_t.h"
 #include "lang_features.h"
+#include "warning.h"
 #include "adt/bitfiddle.h"
 #include "adt/error.h"
 #include "adt/array.h"
@@ -1746,7 +1747,9 @@ finish_specifiers:
                        /* invalid specifier combination, give an error message */
                        if(type_specifiers == 0) {
                                if (! strict_mode) {
-                                       warningf(HERE, "no type specifiers in declaration, using int");
+                                       if (warning.implicit_int) {
+                                               warningf(HERE, "no type specifiers in declaration, using 'int'");
+                                       }
                                        atomic_type = ATOMIC_TYPE_INT;
                                        break;
                                } else {
@@ -2260,7 +2263,9 @@ static declaration_t *internal_record_declaration(
        const namespace_t     namespc = (namespace_t)declaration->namespc;
 
        const type_t *const type = skip_typeref(declaration->type);
-       if (is_type_function(type) && type->function.unspecified_parameters) {
+       if (is_type_function(type) &&
+                       type->function.unspecified_parameters &&
+                       warning.strict_prototypes) {
                warningf(declaration->source_position,
                         "function declaration '%#T' is not a prototype",
                         type, declaration->symbol);
@@ -2268,68 +2273,75 @@ static declaration_t *internal_record_declaration(
 
        declaration_t *const previous_declaration = get_declaration(symbol, namespc);
        assert(declaration != previous_declaration);
-       if (previous_declaration != NULL
-                       && previous_declaration->parent_context == context) {
-               /* can happen for K&R style declarations */
-               if(previous_declaration->type == NULL) {
-                       previous_declaration->type = declaration->type;
-               }
-
-               const type_t *const prev_type = skip_typeref(previous_declaration->type);
-               if (!types_compatible(type, prev_type)) {
-                       errorf(declaration->source_position,
-                               "declaration '%#T' is incompatible with previous declaration '%#T'",
-                               type, symbol, previous_declaration->type, symbol);
-                       errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
-               } else {
-                       unsigned old_storage_class = previous_declaration->storage_class;
-                       unsigned new_storage_class = declaration->storage_class;
-
-                       /* pretend no storage class means extern for function declarations
-                        * (except if the previous declaration is neither none nor extern) */
-                       if (is_type_function(type)) {
-                               switch (old_storage_class) {
-                                       case STORAGE_CLASS_NONE:
-                                               old_storage_class = STORAGE_CLASS_EXTERN;
-
-                                       case STORAGE_CLASS_EXTERN:
-                                               if (new_storage_class == STORAGE_CLASS_NONE && !is_function_definition) {
-                                                       new_storage_class = STORAGE_CLASS_EXTERN;
-                                               }
-                                               break;
+       if (previous_declaration != NULL) {
+               if (previous_declaration->parent_context == context) {
+                       /* can happen for K&R style declarations */
+                       if(previous_declaration->type == NULL) {
+                               previous_declaration->type = declaration->type;
+                       }
 
-                                       default: break;
+                       const type_t *const prev_type = skip_typeref(previous_declaration->type);
+                       if (!types_compatible(type, prev_type)) {
+                               errorf(declaration->source_position,
+                                       "declaration '%#T' is incompatible with previous declaration '%#T'",
+                                       type, symbol, previous_declaration->type, symbol);
+                               errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+                       } else {
+                               unsigned old_storage_class = previous_declaration->storage_class;
+                               unsigned new_storage_class = declaration->storage_class;
+
+                               /* pretend no storage class means extern for function declarations
+                                * (except if the previous declaration is neither none nor extern) */
+                               if (is_type_function(type)) {
+                                       switch (old_storage_class) {
+                                               case STORAGE_CLASS_NONE:
+                                                       old_storage_class = STORAGE_CLASS_EXTERN;
+
+                                               case STORAGE_CLASS_EXTERN:
+                                                       if (new_storage_class == STORAGE_CLASS_NONE && !is_function_definition) {
+                                                               new_storage_class = STORAGE_CLASS_EXTERN;
+                                                       }
+                                                       break;
+
+                                               default: break;
+                                       }
                                }
-                       }
 
-                       if (old_storage_class == STORAGE_CLASS_EXTERN &&
-                           new_storage_class == STORAGE_CLASS_EXTERN) {
-warn_redundant_declaration:
-                                       warningf(declaration->source_position, "redundant declaration for '%Y'", symbol);
-                                       warningf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
-                       } else if (current_function == NULL) {
-                               if (old_storage_class != STORAGE_CLASS_STATIC &&
-                                   new_storage_class == STORAGE_CLASS_STATIC) {
-                                       errorf(declaration->source_position, "static declaration of '%Y' follows non-static declaration", symbol);
-                                       errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
-                               } else {
-                                       if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
-                                               goto warn_redundant_declaration;
+                               if (old_storage_class == STORAGE_CLASS_EXTERN &&
+                                               new_storage_class == STORAGE_CLASS_EXTERN) {
+       warn_redundant_declaration:
+                                       if (warning.redundant_decls) {
+                                               warningf(declaration->source_position, "redundant declaration for '%Y'", symbol);
+                                               warningf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
                                        }
-                                       if (new_storage_class == STORAGE_CLASS_NONE) {
-                                               previous_declaration->storage_class = STORAGE_CLASS_NONE;
+                               } else if (current_function == NULL) {
+                                       if (old_storage_class != STORAGE_CLASS_STATIC &&
+                                                       new_storage_class == STORAGE_CLASS_STATIC) {
+                                               errorf(declaration->source_position, "static declaration of '%Y' follows non-static declaration", symbol);
+                                               errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+                                       } else {
+                                               if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
+                                                       goto warn_redundant_declaration;
+                                               }
+                                               if (new_storage_class == STORAGE_CLASS_NONE) {
+                                                       previous_declaration->storage_class = STORAGE_CLASS_NONE;
+                                               }
                                        }
-                               }
-                       } else {
-                               if (old_storage_class == new_storage_class) {
-                                       errorf(declaration->source_position, "redeclaration of '%Y'", symbol);
                                } else {
-                                       errorf(declaration->source_position, "redeclaration of '%Y' with different linkage", symbol);
+                                       if (old_storage_class == new_storage_class) {
+                                               errorf(declaration->source_position, "redeclaration of '%Y'", symbol);
+                                       } else {
+                                               errorf(declaration->source_position, "redeclaration of '%Y' with different linkage", symbol);
+                                       }
+                                       errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
                                }
-                               errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
                        }
+                       return previous_declaration;
                }
-               return previous_declaration;
+       } else if (is_function_definition &&
+                       declaration->storage_class != STORAGE_CLASS_STATIC &&
+                       warning.missing_declarations) {
+               warningf(declaration->source_position, "no previous declaration for '%#T'", type, symbol);
        }
 
        assert(declaration->parent_context == NULL);
@@ -2594,8 +2606,10 @@ static void parse_kr_declaration_list(declaration_t *declaration)
                                errorf(HERE, "no type specified for function parameter '%Y'",
                                       parameter_declaration->symbol);
                        } else {
-                               warningf(HERE, "no type specified for function parameter '%Y', using int",
-                                        parameter_declaration->symbol);
+                               if (warning.implicit_int) {
+                                       warningf(HERE, "no type specified for function parameter '%Y', using 'int'",
+                                               parameter_declaration->symbol);
+                               }
                                parameter_type              = type_int;
                                parameter_declaration->type = parameter_type;
                        }
@@ -3086,8 +3100,10 @@ static expression_t *parse_reference(void)
        if(declaration == NULL) {
                if (! strict_mode && token.type == '(') {
                        /* an implicitly defined function */
-                       warningf(HERE, "implicit declaration of function '%Y'",
-                                ref->symbol);
+                       if (warning.implicit_function_declaration) {
+                               warningf(HERE, "implicit declaration of function '%Y'",
+                                       ref->symbol);
+                       }
 
                        declaration = create_implicit_function(ref->symbol,
                                                               source_position);
@@ -3539,14 +3555,13 @@ static expression_t *parse_primary_expression(void)
  * Check if the expression has the character type and issue a warning then.
  */
 static void check_for_char_index_type(const expression_t *expression) {
-       type_t *type      = expression->base.datatype;
-       type_t *base_type = skip_typeref(type);
+       type_t       *const type      = expression->base.datatype;
+       const type_t *const base_type = skip_typeref(type);
 
-       if (base_type->base.kind == TYPE_ATOMIC) {
-               switch (base_type->atomic.akind == ATOMIC_TYPE_CHAR) {
-                       warningf(expression->base.source_position,
-                               "array subscript has type '%T'", type);
-               }
+       if (is_type_atomic(base_type, ATOMIC_TYPE_CHAR) &&
+                       warning.char_subscripts) {
+               warningf(expression->base.source_position,
+                       "array subscript has type '%T'", type);
        }
 }
 
diff --git a/warning.c b/warning.c
new file mode 100644 (file)
index 0000000..98a4cf5
--- /dev/null
+++ b/warning.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+#include <string.h>
+#include "warning.h"
+
+void set_warning_opt(const char *const opt)
+{
+       const char* s = opt;
+
+       bool state = true;
+       /* no- modifier */
+       if (s[0] == 'n' && s[1] == 'o' && s[2] == '-') {
+               s += 3;
+               state = false;
+       }
+
+       if (0) {}
+#define OPTX(x)   else if (strcmp(s, x) == 0)
+#define SET(y)    warning.y = state;
+#define OPT(x, y) OPTX(x) SET(y)
+       OPT("char-subscripts",               char_subscripts)
+       OPT("error",                         s_are_errors)
+       OPT("fatal-errors",                  fatal_errors)
+       OPT("format",                        check_format)
+       OPTX("implicit") {
+               SET(implicit_function_declaration)
+               SET(implicit_int)
+       }
+       OPT("implicit-function-declaration", implicit_function_declaration)
+       OPT("implicit-int",                  implicit_int)
+       OPT("missing-declarations",          missing_declarations)
+       OPT("redundant-decls",               redundant_decls)
+       OPT("strict-prototypes",             strict_prototypes)
+#if 0
+       OPTX("unused") {
+               SET(unused_function)
+               SET(unused_label)
+               SET(unused_parameter)
+               SET(unused_variable)
+               SET(unused_value)
+       }
+#endif
+#undef OPT
+       else {
+               fprintf(stderr, "warning: ignoring unknown option -W%s\n", opt);
+       }
+}
+
+warning_t warning = {
+       .char_subscripts               = true,
+       .check_format                  = true,
+       .implicit_function_declaration = true,
+       .implicit_int                  = true,
+       .missing_declarations          = true,
+       .strict_prototypes             = true,
+       .redundant_decls               = true
+};
diff --git a/warning.h b/warning.h
new file mode 100644 (file)
index 0000000..ca72709
--- /dev/null
+++ b/warning.h
@@ -0,0 +1,79 @@
+#ifndef WARNING_H
+#define WARNING_H
+
+#include <stdbool.h>
+
+void set_warning_opt(const char *opt);
+
+typedef struct warning_t {
+#if 0 // TODO
+       bool aggregate_return:1;              /* Warn if any functions that return structures or unions are defined or called */
+       bool bad_function_cast:1;             /* Warn whenever a function call is cast to a non-matching type */
+#endif
+       bool char_subscripts:1;               /* Warn if an array subscript has the type 'char' */
+       bool check_format:1;                  /* Check printf-style format strings */
+#if 0 // TODO
+       bool cast_align:1;                    /* Warn whenever a pointer is cast such that the required alignment of the target is increased */
+       bool cast_qual:1;                     /* Warn whenever a pointer is cast so as to remove a type qualifier from the target type */
+       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 */
+       bool declaration_after_statement:1;   /* Warn when a declaration is found after a statement in a block */
+       bool deprecated_declarations:1;       /* 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 endif_labels:1;                  /* Warn whenever an '#else' or an '#endif' are followed by text */
+#endif
+       bool fatal_errors:1;                  /* First error stops the compilation */
+#if 0 // TODO
+       bool float_equal:1;                   /* Warn if floating point values are used in equality comparisons */
+#endif
+       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 */
+#if 0 // TODO
+       bool inline:1;                        /* Warn if a function can not be inlined and it was declared as inline */
+       bool long_long:1;                     /* Warn if 'long long' type is used */
+       bool main:1;                          /* Warn if the type of 'main' is suspicious */
+       bool missing_braces:1;                /* 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 */
+#if 0 // TODO
+       bool missing_format_attribute:1;      /* If '-Wformat' is enabled, also warn about functions which might be candidates for 'format' attributes */
+       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 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' */
+#endif
+       bool redundant_decls:1;               /* Warn about redundant declarations */
+#if 0 // TODO
+       bool return_type:1;                   /* 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'. */
+#endif
+       bool s_are_errors:1;                  /* Treat warnings as errors */
+#if 0 // TODO
+       bool sequence_point:1;                /* Warn about code that may have undefined semantics because of violations of sequence point rules */
+       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 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 */
+       bool strict_aliasing:1;               /* 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 */
+#if 0 // TODO
+       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 */
+       bool undef:1;                         /* Warn if an undefined identifier is evaluated in an '#if' directive */
+       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 by GCC */
+       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_variable:1;               /* Warn whenever a local variable or non-constant static variable is unused aside from its declaration */
+       bool unused_value:1;                  /* Warn whenever a statement computes a result that is explicitly not used */
+       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 */
+#endif
+} warning_t;
+
+extern warning_t warning;
+
+#endif