From 356aba533706e40254ebb601f8cad4ed6d82e665 Mon Sep 17 00:00:00 2001 From: Michael Beck Date: Wed, 12 Dec 2007 02:39:50 +0000 Subject: [PATCH] - added check for multiple default labels - added check for undefined goto labels [r18696] --- ast_t.h | 1 + parser.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 69 insertions(+), 14 deletions(-) diff --git a/ast_t.h b/ast_t.h index 79418c5..daceed6 100644 --- a/ast_t.h +++ b/ast_t.h @@ -483,6 +483,7 @@ 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 */ }; struct case_label_statement_t { diff --git a/parser.c b/parser.c index bac60ce..7fd54f4 100644 --- a/parser.c +++ b/parser.c @@ -50,6 +50,7 @@ static declaration_t *last_declaration = NULL; static declaration_t *current_function = NULL; static switch_statement_t *current_switch = NULL; static statement_t *current_loop = NULL; +static goto_statement_t *goto_list = NULL; static struct obstack temp_obst; /** The current source position. */ @@ -2694,6 +2695,26 @@ static void parse_kr_declaration_list(declaration_t *declaration) declaration->type = type; } +/** + * Check if all labels are defined in the current function. + */ +static void check_for_missing_labels(void) +{ + const goto_statement_t *goto_statement, *next; + + for (goto_statement = goto_list; + goto_statement != NULL; + goto_statement = next) { + const declaration_t *label = goto_statement->label; + + if (label->source_position.input_name == NULL) { + errorf(goto_statement->statement.source_position, + "label '%Y' used but not defined", label->symbol); + } + } + goto_list = NULL; +} + static void parse_external_declaration(void) { /* function-definitions and declarations both start with declaration @@ -2787,6 +2808,7 @@ static void parse_external_declaration(void) current_function = declaration; declaration->init.statement = parse_compound_statement(); + check_for_missing_labels(); assert(current_function == declaration); current_function = old_current_function; @@ -4858,23 +4880,44 @@ static statement_t *parse_case_statement(void) expect(':'); - if (current_switch != NULL) { - /* link all cases into the switch statement */ - if (current_switch->last_case == NULL) { - current_switch->first_case = - current_switch->last_case = &statement->case_label; + if (! is_constant_expression(statement->case_label.expression)) { + errorf(statement->base.source_position, + "case label does not reduce to an integer constant"); + } else { + /* TODO: check if the case label is already known */ + if (current_switch != NULL) { + /* link all cases into the switch statement */ + if (current_switch->last_case == NULL) { + current_switch->first_case = + current_switch->last_case = &statement->case_label; + } else { + current_switch->last_case->next = &statement->case_label; + } } else { - current_switch->last_case->next = &statement->case_label; + errorf(statement->base.source_position, + "case label not within a switch statement"); } - } else { - errorf(statement->base.source_position, - "case label not within a switch statement"); } statement->case_label.label_statement = parse_statement(); return statement; } +/** + * Finds an existing default label of a switch statement. + */ +static case_label_statement_t * +find_default_label(const switch_statement_t *statement) +{ + for (case_label_statement_t *label = statement->first_case; + label != NULL; + label = label->next) { + if (label->expression == NULL) + return label; + } + return NULL; +} + /** * Parse a default statement. */ @@ -4888,12 +4931,19 @@ static statement_t *parse_default_statement(void) expect(':'); if (current_switch != NULL) { - /* link all cases into the switch statement */ - if (current_switch->last_case == NULL) { - current_switch->first_case = - current_switch->last_case = &statement->case_label; + const case_label_statement_t *def_label = find_default_label(current_switch); + if (def_label != NULL) { + errorf(HERE, "multiple default labels in one switch"); + errorf(def_label->statement.source_position, + "this is the first default label"); } else { - current_switch->last_case->next = &statement->case_label; + /* link all cases into the switch statement */ + if (current_switch->last_case == NULL) { + current_switch->first_case = + current_switch->last_case = &statement->case_label; + } else { + current_switch->last_case->next = &statement->case_label; + } } } else { errorf(statement->base.source_position, @@ -5142,6 +5192,10 @@ static statement_t *parse_goto(void) statement->label = label; + /* remember the goto's in a list for later checking */ + statement->next = goto_list; + goto_list = statement; + expect(';'); return (statement_t*) statement; -- 2.20.1