- implemented -Wunused-label
authorMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 15 Dec 2007 02:49:56 +0000 (02:49 +0000)
committerMichael Beck <beck@ipd.info.uni-karlsruhe.de>
Sat, 15 Dec 2007 02:49:56 +0000 (02:49 +0000)
[r18759]

ast_t.h
parser.c
warning.c
warning.h

diff --git a/ast_t.h b/ast_t.h
index 89a9f59..7efa194 100644 (file)
--- a/ast_t.h
+++ b/ast_t.h
@@ -397,6 +397,7 @@ struct declaration_t {
        decl_modifiers_t    modifiers;
        unsigned int        address_taken : 1;
        unsigned int        is_inline     : 1;
+       unsigned int        used          : 1;  /**< Set if the declaration is used. */
        type_t             *type;
        symbol_t           *symbol;
        source_position_t   source_position;
@@ -482,8 +483,8 @@ struct switch_statement_t {
 
 struct goto_statement_t {
        statement_base_t  statement;
-       declaration_t    *label;
-       goto_statement_t *next; /**< link all goto statements in a function */
+       declaration_t    *label;     /**< The destination label. */
+       goto_statement_t *next;      /**< links all goto statements of a function */
 };
 
 struct case_label_statement_t {
@@ -494,9 +495,10 @@ struct case_label_statement_t {
 };
 
 struct label_statement_t {
-       statement_base_t  statement;
-       declaration_t    *label;
-       statement_t      *label_statement;
+       statement_base_t   statement;
+       declaration_t     *label;
+       statement_t       *label_statement;
+       label_statement_t *next;            /**< links all label statements of a function */
 };
 
 struct expression_statement_t {
index f95d1af..c769d34 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -52,6 +52,8 @@ static switch_statement_t *current_switch    = NULL;
 static statement_t        *current_loop      = NULL;
 static goto_statement_t   *goto_first        = NULL;
 static goto_statement_t   *goto_last         = NULL;
+static label_statement_t  *label_first       = NULL;
+static label_statement_t  *label_last        = NULL;
 static struct obstack  temp_obst;
 
 /** The current source position. */
@@ -2713,27 +2715,49 @@ static void parse_kr_declaration_list(declaration_t *declaration)
 
 /**
  * Check if all labels are defined in the current function.
+ * Check if all labels are used in the current function.
  */
-static void check_for_missing_labels(void)
+static void check_labels(void)
 {
        bool first_err = true;
        for (const goto_statement_t *goto_statement = goto_first;
-            goto_statement != NULL;
-            goto_statement = goto_statement->next) {
-                const declaration_t *label = goto_statement->label;
-
-                if (label->source_position.input_name == NULL) {
-                        if (first_err) {
-                                first_err = false;
-                                diagnosticf("%s: In function '%Y':\n",
-                                        current_function->source_position.input_name,
-                                        current_function->symbol);
-                        }
-                        errorf(goto_statement->statement.source_position,
-                                "label '%Y' used but not defined", label->symbol);
+           goto_statement != NULL;
+           goto_statement = goto_statement->next) {
+               declaration_t *label = goto_statement->label;
+
+               label->used = true;
+               if (label->source_position.input_name == NULL) {
+                       if (first_err) {
+                               first_err = false;
+                               diagnosticf("%s: In function '%Y':\n",
+                                       current_function->source_position.input_name,
+                                       current_function->symbol);
+                       }
+                       errorf(goto_statement->statement.source_position,
+                               "label '%Y' used but not defined", label->symbol);
                 }
        }
        goto_first = goto_last = NULL;
+
+       if (warning.unused_label) {
+               for (const label_statement_t *label_statement = label_first;
+                        label_statement != NULL;
+                        label_statement = label_statement->next) {
+                       const declaration_t *label = label_statement->label;
+
+                       if (! label->used) {
+                               if (first_err) {
+                                       first_err = false;
+                                       diagnosticf("%s: In function '%Y':\n",
+                                               current_function->source_position.input_name,
+                                               current_function->symbol);
+                               }
+                               warningf(label_statement->statement.source_position,
+                                       "label '%Y' defined but not used", label->symbol);
+                       }
+               }
+       }
+       label_first = label_last = NULL;
 }
 
 static void parse_external_declaration(void)
@@ -2827,7 +2851,7 @@ static void parse_external_declaration(void)
                current_function                    = declaration;
 
                declaration->init.statement = parse_compound_statement();
-               check_for_missing_labels();
+               check_labels();
 
                assert(current_function == declaration);
                current_function = old_current_function;
@@ -5105,6 +5129,13 @@ static statement_t *parse_label_statement(void)
                }
        }
 
+       /* remember the labels's in a list for later checking */
+       if (label_last == NULL) {
+               label_first = label_last = label_statement;
+       } else {
+               label_last->next = label_statement;
+       }
+
        return (statement_t*) label_statement;
 }
 
index f39e16c..63cbeac 100644 (file)
--- a/warning.c
+++ b/warning.c
@@ -36,6 +36,7 @@ void set_warning_opt(const char *const opt)
        OPT("strict-prototypes",             strict_prototypes)
        OPT("switch-default",                switch_default)
        OPT("unknown-pragmas",               unknown_pragmas)
+       OPT("unused-label",                  unused_label)
 #if 0
        OPTX("unused") {
                SET(unused_function)
index 6ebcd40..c251a70 100644 (file)
--- a/warning.h
+++ b/warning.h
@@ -73,7 +73,9 @@ typedef struct warning_t {
 #if 0 // TODO
        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 */
+#endif
        bool unused_label:1;                  /**< Warn whenever a label is declared but not used */
+#if 0 // TODO
        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 */
 #endif