diff options
author | Ian Lance Taylor <iant@google.com> | 2009-04-15 15:51:26 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2009-04-15 15:51:26 +0000 |
commit | 6866c6e8ff0cbc1d57f9ae603b5af155def03484 (patch) | |
tree | 1f0d9f50c4eb35dde54f0cbacee826d856fe8113 /gcc | |
parent | f116fecf890dbc4aaacd256eb26459d7ece30e99 (diff) | |
download | gcc-6866c6e8ff0cbc1d57f9ae603b5af155def03484.zip gcc-6866c6e8ff0cbc1d57f9ae603b5af155def03484.tar.gz gcc-6866c6e8ff0cbc1d57f9ae603b5af155def03484.tar.bz2 |
c.opt (Wenum-compare): Enable for C and Objc.
gcc/:
* c.opt (Wenum-compare): Enable for C and Objc. Initialize to -1.
* c-opts.c (c_common_handle_option): For C, set warn_enum_compare
for -Wall and for -Wc++-compat.
(c_common_post_options): For C++, set warn_enum_compare if not
already set.
* c-tree.h (struct c_expr): Add field original_type.
(build_external_ref): Update declaration.
* c-parser.c (c_parser_braced_init): Set original_type.
(c_parser_initelt): Likewise.
(c_parser_expr_no_commas): Likewise.
(c_parser_conditional_expression): Likewise.
(c_parser_cast_expression): Likewise.
(c_parser_unary_expression): Likewise. Pull setting of
original_code to top of function.
(c_parser_sizeof_expression): Set original_type.
(c_parser_alignof_expression): Likewise.
(c_parser_postfix_expression): Likewise. Pull setting of
original_code to top of function.
(c_parser_postfix_expression_after_paren_type): Set
original_type.
(c_parser_postfix_expression_after_primary): Likewise.
(c_parser_expression): Likewise.
* c-typeck.c (build_external_ref): Add type parameter. Change all
callers.
(c_expr_sizeof_expr): Set original_type field.
(parser_build_unary_op): Likewise.
(parser_build_binary_op): Likewise. Optionally warn about
comparisons of enums of different types.
(digest_init): Set original_type field.
(really_start_incremental_init): Likewise.
(push_init_level, pop_init_level): Likewise.
* doc/invoke.texi (Warning Options): -Wenum-compare now
supported in C.
gcc/testsuite/:
* gcc.dg/Wenum-compare-1.c: New testcase.
From-SVN: r146127
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 36 | ||||
-rw-r--r-- | gcc/c-opts.c | 19 | ||||
-rw-r--r-- | gcc/c-parser.c | 107 | ||||
-rw-r--r-- | gcc/c-tree.h | 7 | ||||
-rw-r--r-- | gcc/c-typeck.c | 40 | ||||
-rw-r--r-- | gcc/c.opt | 2 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 8 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wenum-compare-1.c | 33 |
9 files changed, 208 insertions, 48 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6898c7c..eb0ccb1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,39 @@ +2009-04-15 Ian Lance Taylor <iant@google.com> + + * c.opt (Wenum-compare): Enable for C and Objc. Initialize to -1. + * c-opts.c (c_common_handle_option): For C, set warn_enum_compare + for -Wall and for -Wc++-compat. + (c_common_post_options): For C++, set warn_enum_compare if not + already set. + * c-tree.h (struct c_expr): Add field original_type. + (build_external_ref): Update declaration. + * c-parser.c (c_parser_braced_init): Set original_type. + (c_parser_initelt): Likewise. + (c_parser_expr_no_commas): Likewise. + (c_parser_conditional_expression): Likewise. + (c_parser_cast_expression): Likewise. + (c_parser_unary_expression): Likewise. Pull setting of + original_code to top of function. + (c_parser_sizeof_expression): Set original_type. + (c_parser_alignof_expression): Likewise. + (c_parser_postfix_expression): Likewise. Pull setting of + original_code to top of function. + (c_parser_postfix_expression_after_paren_type): Set + original_type. + (c_parser_postfix_expression_after_primary): Likewise. + (c_parser_expression): Likewise. + * c-typeck.c (build_external_ref): Add type parameter. Change all + callers. + (c_expr_sizeof_expr): Set original_type field. + (parser_build_unary_op): Likewise. + (parser_build_binary_op): Likewise. Optionally warn about + comparisons of enums of different types. + (digest_init): Set original_type field. + (really_start_incremental_init): Likewise. + (push_init_level, pop_init_level): Likewise. + * doc/invoke.texi (Warning Options): -Wenum-compare now + supported in C. + 2009-04-15 Richard Guenther <rguenther@suse.de> * tree-ssa-pre.c (eliminate): When replacing a PHI node carry diff --git a/gcc/c-opts.c b/gcc/c-opts.c index 54edf30..f619522 100644 --- a/gcc/c-opts.c +++ b/gcc/c-opts.c @@ -412,6 +412,12 @@ c_common_handle_option (size_t scode, const char *arg, int value) can turn it off only if it's not explicit. */ if (warn_main == -1) warn_main = (value ? 2 : 0); + + /* In C, -Wall turns on -Wenum-compare, which we do here. + In C++ it is on by default, which is done in + c_common_post_options. */ + if (warn_enum_compare == -1) + warn_enum_compare = value; } else { @@ -438,6 +444,13 @@ c_common_handle_option (size_t scode, const char *arg, int value) cpp_opts->warn_comments = value; break; + case OPT_Wc___compat: + /* Because -Wenum-compare is the default in C++, -Wc++-compat + implies -Wenum-compare. */ + if (warn_enum_compare == -1 && value) + warn_enum_compare = value; + break; + case OPT_Wdeprecated: cpp_opts->warn_deprecated = value; break; @@ -1099,6 +1112,12 @@ c_common_post_options (const char **pfilename) if (warn_sign_conversion == -1) warn_sign_conversion = (c_dialect_cxx ()) ? 0 : warn_conversion; + /* In C, -Wall and -Wc++-compat enable -Wenum-compare, which we do + in c_common_handle_option; if it has not yet been set, it is + disabled by default. In C++, it is enabled by default. */ + if (warn_enum_compare == -1) + warn_enum_compare = c_dialect_cxx () ? 1 : 0; + /* -Wpacked-bitfield-compat is on by default for the C languages. The warning is issued in stor-layout.c which is not part of the front-end so we need to selectively turn it on here. */ diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 7887391..9b3ace5 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -3044,6 +3044,7 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p) struct c_expr ret; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, "expected %<}%>"); pop_init_level (0); return ret; @@ -3100,6 +3101,7 @@ c_parser_initelt (c_parser *parser) struct c_expr init; init.value = error_mark_node; init.original_code = ERROR_MARK; + init.original_type = NULL; c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_COMMA, NULL); process_init_element (init, false); @@ -3174,6 +3176,7 @@ c_parser_initelt (c_parser *parser) mexpr.value = objc_build_message_expr (build_tree_list (rec, args)); mexpr.original_code = ERROR_MARK; + mexpr.original_type = NULL; /* Now parse and process the remainder of the initializer, starting with this message expression as a primary-expression. */ @@ -3223,6 +3226,7 @@ c_parser_initelt (c_parser *parser) struct c_expr init; init.value = error_mark_node; init.original_code = ERROR_MARK; + init.original_type = NULL; c_parser_error (parser, "expected %<=%>"); c_parser_skip_until_found (parser, CPP_COMMA, NULL); process_init_element (init, false); @@ -4438,6 +4442,7 @@ c_parser_expr_no_commas (c_parser *parser, struct c_expr *after) TREE_NO_WARNING (ret.value) = 1; ret.original_code = ERROR_MARK; } + ret.original_type = NULL; return ret; } @@ -4485,6 +4490,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) exp1.value = c_save_expr (default_conversion (cond.value)); if (eptype) exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value); + exp1.original_type = NULL; cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value); skip_evaluation += cond.value == truthvalue_true_node; } @@ -4503,6 +4509,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) skip_evaluation -= cond.value == truthvalue_true_node; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } exp2 = c_parser_conditional_expression (parser, NULL); @@ -4512,6 +4519,24 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after) cond.original_code == C_MAYBE_CONST_EXPR, exp1.value, exp2.value); ret.original_code = ERROR_MARK; + if (exp1.value == error_mark_node || exp2.value == error_mark_node) + ret.original_type = NULL; + else + { + tree t1, t2; + + /* If both sides are enum type, the default conversion will have + made the type of the result be an integer type. We want to + remember the enum types we started with. */ + t1 = exp1.original_type ? exp1.original_type : TREE_TYPE (exp1.value); + t2 = exp2.original_type ? exp2.original_type : TREE_TYPE (exp2.value); + ret.original_type = ((t1 != error_mark_node + && t2 != error_mark_node + && (TYPE_MAIN_VARIANT (t1) + == TYPE_MAIN_VARIANT (t2))) + ? t1 + : NULL); + } return ret; } @@ -4800,6 +4825,7 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) { ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } @@ -4813,6 +4839,7 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after) expr = default_function_array_conversion (expr); ret.value = c_cast_expr (type_name, expr.value); ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } else @@ -4852,6 +4879,8 @@ c_parser_unary_expression (c_parser *parser) int ext; struct c_expr ret, op; location_t loc = c_parser_peek_token (parser)->location; + ret.original_code = ERROR_MARK; + ret.original_type = NULL; switch (c_parser_peek_token (parser)->type) { case CPP_PLUS_PLUS: @@ -4874,7 +4903,6 @@ c_parser_unary_expression (c_parser *parser) op = c_parser_cast_expression (parser, NULL); op = default_function_array_conversion (op); ret.value = build_indirect_ref (loc, op.value, "unary *"); - ret.original_code = ERROR_MARK; return ret; case CPP_PLUS: if (!c_dialect_objc () && !in_system_header) @@ -4914,7 +4942,6 @@ c_parser_unary_expression (c_parser *parser) c_parser_error (parser, "expected identifier"); ret.value = error_mark_node; } - ret.original_code = ERROR_MARK; return ret; case CPP_KEYWORD: switch (c_parser_peek_token (parser)->keyword) @@ -4975,6 +5002,7 @@ c_parser_sizeof_expression (c_parser *parser) in_sizeof--; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) @@ -5029,6 +5057,7 @@ c_parser_alignof_expression (c_parser *parser) in_alignof--; ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } if (c_parser_next_token_is (parser, CPP_OPEN_BRACE)) @@ -5042,6 +5071,7 @@ c_parser_alignof_expression (c_parser *parser) in_alignof--; ret.value = c_alignof (groktypename (type_name, NULL, NULL)); ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } else @@ -5053,6 +5083,7 @@ c_parser_alignof_expression (c_parser *parser) in_alignof--; ret.value = c_alignof_expr (expr.value); ret.original_code = ERROR_MARK; + ret.original_type = NULL; return ret; } } @@ -5116,11 +5147,12 @@ c_parser_postfix_expression (c_parser *parser) struct c_expr expr, e1, e2, e3; struct c_type_name *t1, *t2; location_t loc; + expr.original_code = ERROR_MARK; + expr.original_type = NULL; switch (c_parser_peek_token (parser)->type) { case CPP_NUMBER: expr.value = c_parser_peek_token (parser)->value; - expr.original_code = ERROR_MARK; loc = c_parser_peek_token (parser)->location; c_parser_consume_token (parser); if (TREE_CODE (expr.value) == FIXED_CST @@ -5135,7 +5167,6 @@ c_parser_postfix_expression (c_parser *parser) case CPP_CHAR32: case CPP_WCHAR: expr.value = c_parser_peek_token (parser)->value; - expr.original_code = ERROR_MARK; c_parser_consume_token (parser); break; case CPP_STRING: @@ -5150,7 +5181,6 @@ c_parser_postfix_expression (c_parser *parser) gcc_assert (c_dialect_objc ()); expr.value = objc_build_string_object (c_parser_peek_token (parser)->value); - expr.original_code = ERROR_MARK; c_parser_consume_token (parser); break; case CPP_NAME: @@ -5158,7 +5188,6 @@ c_parser_postfix_expression (c_parser *parser) { c_parser_error (parser, "expected expression"); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } { @@ -5167,8 +5196,8 @@ c_parser_postfix_expression (c_parser *parser) c_parser_consume_token (parser); expr.value = build_external_ref (id, (c_parser_peek_token (parser)->type - == CPP_OPEN_PAREN), loc); - expr.original_code = ERROR_MARK; + == CPP_OPEN_PAREN), loc, + &expr.original_type); } break; case CPP_OPEN_PAREN: @@ -5189,7 +5218,6 @@ c_parser_postfix_expression (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_BRACE, NULL); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } stmt = c_begin_stmt_expr (); @@ -5199,7 +5227,6 @@ c_parser_postfix_expression (c_parser *parser) pedwarn (here, OPT_pedantic, "ISO C forbids braced-groups within expressions"); expr.value = c_finish_stmt_expr (stmt); - expr.original_code = ERROR_MARK; } else if (c_token_starts_typename (c_parser_peek_2nd_token (parser))) { @@ -5215,7 +5242,6 @@ c_parser_postfix_expression (c_parser *parser) if (type_name == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; } else expr = c_parser_postfix_expression_after_paren_type (parser, @@ -5230,6 +5256,7 @@ c_parser_postfix_expression (c_parser *parser) TREE_NO_WARNING (expr.value) = 1; if (expr.original_code != C_MAYBE_CONST_EXPR) expr.original_code = ERROR_MARK; + /* Don't change EXPR.ORIGINAL_TYPE. */ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); } @@ -5243,7 +5270,6 @@ c_parser_postfix_expression (c_parser *parser) expr.value = fname_decl (c_parser_peek_token (parser)->location, c_parser_peek_token (parser)->keyword, c_parser_peek_token (parser)->value); - expr.original_code = ERROR_MARK; c_parser_consume_token (parser); break; case RID_VA_ARG: @@ -5251,7 +5277,6 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } e1 = c_parser_expr_no_commas (parser, NULL); @@ -5260,7 +5285,6 @@ c_parser_postfix_expression (c_parser *parser) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t1 = c_parser_type_name (parser); @@ -5269,7 +5293,6 @@ c_parser_postfix_expression (c_parser *parser) if (t1 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; } else { @@ -5284,7 +5307,6 @@ c_parser_postfix_expression (c_parser *parser) expr.value); C_MAYBE_CONST_EXPR_NON_CONST (expr.value) = true; } - expr.original_code = ERROR_MARK; } break; case RID_OFFSETOF: @@ -5292,21 +5314,18 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } { @@ -5371,7 +5390,6 @@ c_parser_postfix_expression (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); expr.value = fold_offsetof (offsetof_ref, NULL_TREE); - expr.original_code = ERROR_MARK; } break; case RID_CHOOSE_EXPR: @@ -5379,7 +5397,6 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } loc = c_parser_peek_token (parser)->location; @@ -5388,7 +5405,6 @@ c_parser_postfix_expression (c_parser *parser) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } e2 = c_parser_expr_no_commas (parser, NULL); @@ -5396,7 +5412,6 @@ c_parser_postfix_expression (c_parser *parser) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } e3 = c_parser_expr_no_commas (parser, NULL); @@ -5420,28 +5435,24 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>")) { c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t2 = c_parser_type_name (parser); if (t2 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, @@ -5455,7 +5466,6 @@ c_parser_postfix_expression (c_parser *parser) expr.value = comptypes (e1, e2) ? build_int_cst (NULL_TREE, 1) : build_int_cst (NULL_TREE, 0); - expr.original_code = ERROR_MARK; } break; case RID_AT_SELECTOR: @@ -5464,7 +5474,6 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } { @@ -5472,7 +5481,6 @@ c_parser_postfix_expression (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); expr.value = objc_build_selector_expr (sel); - expr.original_code = ERROR_MARK; } break; case RID_AT_PROTOCOL: @@ -5481,7 +5489,6 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } if (c_parser_next_token_is_not (parser, CPP_NAME)) @@ -5489,7 +5496,6 @@ c_parser_postfix_expression (c_parser *parser) c_parser_error (parser, "expected identifier"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } { @@ -5498,7 +5504,6 @@ c_parser_postfix_expression (c_parser *parser) c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); expr.value = objc_build_protocol_expr (id); - expr.original_code = ERROR_MARK; } break; case RID_AT_ENCODE: @@ -5508,14 +5513,12 @@ c_parser_postfix_expression (c_parser *parser) if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>")) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } t1 = c_parser_type_name (parser); if (t1 == NULL) { expr.value = error_mark_node; - expr.original_code = ERROR_MARK; c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); break; } @@ -5524,13 +5527,11 @@ c_parser_postfix_expression (c_parser *parser) { tree type = groktypename (t1, NULL, NULL); expr.value = objc_build_encode_expr (type); - expr.original_code = ERROR_MARK; } break; default: c_parser_error (parser, "expected expression"); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } break; @@ -5545,14 +5546,12 @@ c_parser_postfix_expression (c_parser *parser) "expected %<]%>"); expr.value = objc_build_message_expr (build_tree_list (receiver, args)); - expr.original_code = ERROR_MARK; break; } /* Else fall through to report error. */ default: c_parser_error (parser, "expected expression"); expr.value = error_mark_node; - expr.original_code = ERROR_MARK; break; } return c_parser_postfix_expression_after_primary (parser, expr); @@ -5597,6 +5596,7 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, non_const |= !type_expr_const; expr.value = build_compound_literal (type, init.value, non_const); expr.original_code = ERROR_MARK; + expr.original_type = NULL; if (type_expr) { if (TREE_CODE (expr.value) == C_MAYBE_CONST_EXPR) @@ -5637,6 +5637,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, "expected %<]%>"); expr.value = build_array_ref (expr.value, idx, loc); expr.original_code = ERROR_MARK; + expr.original_type = NULL; break; case CPP_OPEN_PAREN: /* Function call. */ @@ -5655,6 +5656,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, && DECL_BUILT_IN_CLASS (orig_expr.value) == BUILT_IN_NORMAL && DECL_FUNCTION_CODE (orig_expr.value) == BUILT_IN_CONSTANT_P) expr.original_code = C_MAYBE_CONST_EXPR; + expr.original_type = NULL; break; case CPP_DOT: /* Structure element reference. */ @@ -5667,11 +5669,23 @@ c_parser_postfix_expression_after_primary (c_parser *parser, c_parser_error (parser, "expected identifier"); expr.value = error_mark_node; expr.original_code = ERROR_MARK; + expr.original_type = NULL; return expr; } c_parser_consume_token (parser); expr.value = build_component_ref (expr.value, ident); expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } break; case CPP_DEREF: /* Structure element reference. */ @@ -5684,6 +5698,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, c_parser_error (parser, "expected identifier"); expr.value = error_mark_node; expr.original_code = ERROR_MARK; + expr.original_type = NULL; return expr; } c_parser_consume_token (parser); @@ -5692,6 +5707,17 @@ c_parser_postfix_expression_after_primary (c_parser *parser, "->"), ident); expr.original_code = ERROR_MARK; + if (TREE_CODE (expr.value) != COMPONENT_REF) + expr.original_type = NULL; + else + { + /* Remember the original type of a bitfield. */ + tree field = TREE_OPERAND (expr.value, 1); + if (TREE_CODE (field) != FIELD_DECL) + expr.original_type = NULL; + else + expr.original_type = DECL_BIT_FIELD_TYPE (field); + } break; case CPP_PLUS_PLUS: /* Postincrement. */ @@ -5700,6 +5726,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.value = build_unary_op (loc, POSTINCREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; + expr.original_type = NULL; break; case CPP_MINUS_MINUS: /* Postdecrement. */ @@ -5708,6 +5735,7 @@ c_parser_postfix_expression_after_primary (c_parser *parser, expr.value = build_unary_op (loc, POSTDECREMENT_EXPR, expr.value, 0); expr.original_code = ERROR_MARK; + expr.original_type = NULL; break; default: return expr; @@ -5735,6 +5763,7 @@ c_parser_expression (c_parser *parser) next = default_function_array_conversion (next); expr.value = build_compound_expr (expr.value, next.value); expr.original_code = COMPOUND_EXPR; + expr.original_type = NULL; } return expr; } diff --git a/gcc/c-tree.h b/gcc/c-tree.h index ac9586b..6b9fcc7 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -163,6 +163,11 @@ struct c_expr initializers, or ERROR_MARK for other expressions (including parenthesized expressions). */ enum tree_code original_code; + /* If not NULL, the original type of an expression. This will + differ from the type of the value field for an enum constant. + The type of an enum constant is a plain integer type, but this + field will be the enum type. */ + tree original_type; }; /* A kind of type specifier. Note that this information is currently @@ -577,7 +582,7 @@ extern struct c_expr default_function_array_conversion (struct c_expr); extern tree composite_type (tree, tree); extern tree build_component_ref (tree, tree); extern tree build_array_ref (tree, tree, location_t); -extern tree build_external_ref (tree, int, location_t); +extern tree build_external_ref (tree, int, location_t, tree *); extern void pop_maybe_used (bool); extern struct c_expr c_expr_sizeof_expr (struct c_expr); extern struct c_expr c_expr_sizeof_type (struct c_type_name *); diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 9c74bf3..c6bb9f8 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -2202,9 +2202,12 @@ build_array_ref (tree array, tree index, location_t loc) /* Build an external reference to identifier ID. FUN indicates whether this will be used for a function call. LOC is the source - location of the identifier. */ + location of the identifier. This sets *TYPE to the type of the + identifier, which is not the same as the type of the returned value + for CONST_DECLs defined as enum constants. If the type of the + identifier is not available, *TYPE is set to NULL. */ tree -build_external_ref (tree id, int fun, location_t loc) +build_external_ref (tree id, int fun, location_t loc, tree *type) { tree ref; tree decl = lookup_name (id); @@ -2213,8 +2216,12 @@ build_external_ref (tree id, int fun, location_t loc) whatever lookup_name() found. */ decl = objc_lookup_ivar (decl, id); + *type = NULL; if (decl && decl != error_mark_node) - ref = decl; + { + ref = decl; + *type = TREE_TYPE (ref); + } else if (fun) /* Implicit function declaration. */ ref = implicitly_declare (id); @@ -2346,6 +2353,7 @@ c_expr_sizeof_expr (struct c_expr expr) { ret.value = error_mark_node; ret.original_code = ERROR_MARK; + ret.original_type = NULL; pop_maybe_used (false); } else @@ -2355,6 +2363,7 @@ c_expr_sizeof_expr (struct c_expr expr) &expr_const_operands); ret.value = c_sizeof (TREE_TYPE (folded_expr)); ret.original_code = ERROR_MARK; + ret.original_type = NULL; if (c_vla_type_p (TREE_TYPE (folded_expr))) { /* sizeof is evaluated when given a vla (C99 6.5.3.4p2). */ @@ -2380,6 +2389,7 @@ c_expr_sizeof_type (struct c_type_name *t) type = groktypename (t, &type_expr, &type_expr_const); ret.value = c_sizeof (type); ret.original_code = ERROR_MARK; + ret.original_type = NULL; if (type_expr && c_vla_type_p (type)) { ret.value = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (ret.value), @@ -2856,7 +2866,8 @@ parser_build_unary_op (enum tree_code code, struct c_expr arg, location_t loc) result.value = build_unary_op (loc, code, arg.value, 0); result.original_code = code; - + result.original_type = NULL; + if (TREE_OVERFLOW_P (result.value) && !TREE_OVERFLOW_P (arg.value)) overflow_warning (result.value); @@ -2879,10 +2890,17 @@ parser_build_binary_op (location_t location, enum tree_code code, enum tree_code code1 = arg1.original_code; enum tree_code code2 = arg2.original_code; + tree type1 = (arg1.original_type + ? arg1.original_type + : TREE_TYPE (arg1.value)); + tree type2 = (arg2.original_type + ? arg2.original_type + : TREE_TYPE (arg2.value)); result.value = build_binary_op (location, code, arg1.value, arg2.value, 1); result.original_code = code; + result.original_type = NULL; if (TREE_CODE (result.value) == ERROR_MARK) return result; @@ -2915,6 +2933,16 @@ parser_build_binary_op (location_t location, enum tree_code code, && !TREE_OVERFLOW_P (arg2.value)) overflow_warning (result.value); + /* Warn about comparisons of different enum types. */ + if (warn_enum_compare + && TREE_CODE_CLASS (code) == tcc_comparison + && TREE_CODE (type1) == ENUMERAL_TYPE + && TREE_CODE (type2) == ENUMERAL_TYPE + && TYPE_MAIN_VARIANT (type1) != TYPE_MAIN_VARIANT (type2)) + warning_at (location, OPT_Wenum_compare, + "comparison between %qT and %qT", + type1, type2); + return result; } @@ -5171,6 +5199,7 @@ digest_init (tree type, tree init, bool null_pointer_constant, tree typ2 = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init))); expr.value = inside_init; expr.original_code = (strict_string ? STRING_CST : ERROR_MARK); + expr.original_type = NULL; maybe_warn_string_init (type, expr); if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)), @@ -5690,6 +5719,7 @@ really_start_incremental_init (tree type) p->depth = constructor_depth; p->replacement_value.value = 0; p->replacement_value.original_code = ERROR_MARK; + p->replacement_value.original_type = NULL; p->implicit = 0; p->range_stack = 0; p->outer = 0; @@ -5833,6 +5863,7 @@ push_init_level (int implicit) p->depth = constructor_depth; p->replacement_value.value = 0; p->replacement_value.original_code = ERROR_MARK; + p->replacement_value.original_type = NULL; p->implicit = implicit; p->outer = 0; p->incremental = constructor_incremental; @@ -5989,6 +6020,7 @@ pop_init_level (int implicit) struct c_expr ret; ret.value = 0; ret.original_code = ERROR_MARK; + ret.original_type = NULL; if (implicit == 0) { @@ -204,7 +204,7 @@ C ObjC C++ ObjC++ Warning Warn about stray tokens after #elif and #endif Wenum-compare -C++ ObjC++ Var(warn_enum_compare) Init(1) Warning +C ObjC C++ ObjC++ Var(warn_enum_compare) Init(-1) Warning Warn about comparison of different enum types Werror diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 554b6d9..12262f2 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -2758,6 +2758,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}. -Warray-bounds @r{(only with} @option{-O2}@r{)} @gol -Wc++0x-compat @gol -Wchar-subscripts @gol +-Wenum-compare @r{(in C/Objc; this is on by default in C++)} @gol -Wimplicit-int @gol -Wimplicit-function-declaration @gol -Wcomment @gol @@ -3743,11 +3744,12 @@ integers are disabled by default in C++ unless Warn if an empty body occurs in an @samp{if}, @samp{else} or @samp{do while} statement. This warning is also enabled by @option{-Wextra}. -@item -Wenum-compare @r{(C++ and Objective-C++ only)} +@item -Wenum-compare @opindex Wenum-compare @opindex Wno-enum-compare -Warn about a comparison between values of different enum types. This -warning is enabled by default. +Warn about a comparison between values of different enum types. In C++ +this warning is enabled by default. In C this warning is enabled by +@option{-Wall}. @item -Wsign-compare @opindex Wsign-compare diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f1a02b0..ffcd888 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2009-04-15 Ian Lance Taylor <iant@google.com> + + * gcc.dg/Wenum-compare-1.c: New testcase. + 2009-04-15 Richard Guenther <rguenther@suse.de> PR tree-optimization/39764 diff --git a/gcc/testsuite/gcc.dg/Wenum-compare-1.c b/gcc/testsuite/gcc.dg/Wenum-compare-1.c new file mode 100644 index 0000000..dd321e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wenum-compare-1.c @@ -0,0 +1,33 @@ +/* { dg-do compile } */ +/* { dg-options "-Wenum-compare" } */ +enum E1 { A, B, C }; +enum E2 { D, E, F }; +extern void f2 (); +void +f1 () +{ + int a = A; + int d = D; + enum E1 e1 = A; + enum E2 e2 = D; + if (A > D) /* { dg-warning "comparison between .enum E1. and .enum E2." } */ + f2 (); + if (e1 > e2) /* { dg-warning "comparison between .enum E1. and .enum E2." } */ + f2 (); + if (e1 > e2 + 1) + f2 (); + if (A > 0) + f2 (); + if (e1 > 0) + f2 (); + if (A + D > 0) + f2 (); + if (e1 > 0) + f2 (); + if (A + D > 0) + f2 (); + if ((int) A > D) + f2 (); + if ((int) e1 > e2) + f2 (); +} |