From ca1f2e9ebf33e78c77c79eb695fe88d843b4f978 Mon Sep 17 00:00:00 2001 From: Morten Welinder Date: Tue, 28 Mar 2006 15:10:58 -0500 Subject: [PATCH] [PATCH] Warning for mixing enums of different types This adds a warning when enums of different types are mixed. I found a handful of problems with this in my own code -- nothing that testing could have revealed at this point, but if someone has added an extra flag to an enum, things would have gone "boom!" typedef enum { A1, A2 } enumA; typedef enum { B1 = 10, B2 } enumB; static void Afunc (enumA a) { } int main (int argc, char **argv) { enumA a = A1; switch (A1) { case A1: break; case A2: break; case B1: break; // Warn case B2: break; // Warn default: break; } switch (1) { case A1: break; case A2: break; case B1: break; // Warn case B2: break; // Warn default: break; } switch (1) { case A1 ... B2: break; // Warn default: break; } (void)(1 ? a : B1); // Warn (void)(A1 == B1); // Warn (void)(A1 << B1); // No warning wanted a = B1; // Warn Afunc (B1); // Warn return 0; } Signed-off-by: Morten Welinder Signed-off-by: Linus Torvalds --- evaluate.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++------- symbol.h | 7 +++++++ 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/evaluate.c b/evaluate.c index 1a12b676..2c70cee9 100644 --- a/evaluate.c +++ b/evaluate.c @@ -238,6 +238,23 @@ static int is_same_type(struct expression *expr, struct symbol *new) return 0; } +static void +warn_for_different_enum_types (struct position pos, + struct symbol *typea, + struct symbol *typeb) +{ + if (typea->type == SYM_NODE) + typea = typea->ctype.base_type; + if (typeb->type == SYM_NODE) + typeb = typeb->ctype.base_type; + + if (typea == typeb) + return; + + if (typea->type == SYM_ENUM && typeb->type == SYM_ENUM) + warning(pos, "mixing different enum types"); +} + /* * This gets called for implicit casts in assignments and * integer promotion. We often want to try to move the @@ -249,6 +266,8 @@ static struct expression * cast_to(struct expression *old, struct symbol *type) { struct expression *expr; + warn_for_different_enum_types (old->pos, old->ctype, type); + if (is_same_type(old, type)) return old; @@ -267,6 +286,8 @@ static struct expression * cast_to(struct expression *old, struct symbol *type) break; case EXPR_IMPLIED_CAST: + warn_for_different_enum_types(old->pos, old->ctype, type); + if (old->ctype->bit_size >= type->bit_size) { struct expression *orig = old->cast_expression; if (same_cast_type(orig->ctype, type)) @@ -441,12 +462,16 @@ static struct symbol *compatible_restricted_binop(int op, struct expression **lp if (ltype->type == SYM_NODE) ltype = ltype->ctype.base_type; - if (ltype->type == SYM_ENUM) - ltype = ltype->ctype.base_type; if (rtype->type == SYM_NODE) rtype = rtype->ctype.base_type; + + warn_for_different_enum_types(right->pos, ltype, rtype); + + if (ltype->type == SYM_ENUM) + ltype = ltype->ctype.base_type; if (rtype->type == SYM_ENUM) rtype = rtype->ctype.base_type; + if (is_restricted_type(ltype)) { if (is_restricted_type(rtype)) { if (ltype == rtype) @@ -2604,7 +2629,9 @@ static void evaluate_case_statement(struct statement *stmt) evaluate_statement(stmt->case_statement); } -static void check_case_type(struct expression *switch_expr, struct expression *case_expr) +static void check_case_type(struct expression *switch_expr, + struct expression *case_expr, + struct expression **enumcase) { struct symbol *switch_type, *case_type; if (!case_expr) @@ -2613,11 +2640,18 @@ static void check_case_type(struct expression *switch_expr, struct expression *c case_type = evaluate_expression(case_expr); if (case_type && switch_type) { + if (enumcase) { + if (*enumcase) + warn_for_different_enum_types(case_expr->pos, case_type, (*enumcase)->ctype); + else if (is_enum_type(case_type)) + *enumcase = case_expr; + } + /* Both integer types? */ - if (is_int_type(switch_type) && is_int_type(case_type)) - return; if (compatible_restricted_binop(SPECIAL_EQUAL, &switch_expr, &case_expr)) return; + if (is_int_type(switch_type) && is_int_type(case_type)) + return; } sparse_error(case_expr->pos, "incompatible types for 'case' statement"); @@ -2626,15 +2660,21 @@ static void check_case_type(struct expression *switch_expr, struct expression *c static void evaluate_switch_statement(struct statement *stmt) { struct symbol *sym; + struct expression *enumcase = NULL; + struct expression **enumcase_holder; evaluate_expression(stmt->switch_expression); evaluate_statement(stmt->switch_statement); if (!stmt->switch_expression) return; + enumcase_holder = is_enum_type(stmt->switch_expression->ctype) + ? NULL /* Only check cases against switch */ + : &enumcase; + FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) { struct statement *case_stmt = sym->stmt; - check_case_type(stmt->switch_expression, case_stmt->case_expression); - check_case_type(stmt->switch_expression, case_stmt->case_to); + check_case_type(stmt->switch_expression, case_stmt->case_expression, enumcase_holder); + check_case_type(stmt->switch_expression, case_stmt->case_to, enumcase_holder); } END_FOR_EACH_PTR(sym); } diff --git a/symbol.h b/symbol.h index 986a9ccc..a773a0a8 100644 --- a/symbol.h +++ b/symbol.h @@ -242,6 +242,13 @@ static inline int is_int_type(const struct symbol *type) type->ctype.base_type == &int_type; } +static inline int is_enum_type(const struct symbol *type) +{ + if (type->type == SYM_NODE) + type = type->ctype.base_type; + return (type->type == SYM_ENUM); +} + static inline int get_sym_type(struct symbol *type) { if (type->type == SYM_NODE) -- 2.11.4.GIT