From: Jakub Jelinek Date: Mon, 4 Feb 2002 22:05:15 +0000 (+0100) Subject: PR c/4475, c++/3780: X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=6f9fdf4db2c68f482ec4ff3cadaea0537a4b13e1;p=gcc.git PR c/4475, c++/3780: * c-common.def (SWITCH_STMT): Add SWITCH_TYPE operand. * c-common.h (SWITCH_TYPE): Define. * c-typeck.c (c_start_case): Set SWITCH_TYPE. * stmt.c (all_cases_count): Set lastval to thisval at end of loop. Rename spareness variable to sparseness. (expand_end_case_type): Renamed from expand_end_case, use orig_type if non-NULL instead of TREE_TYPE (orig_index). * tree.h (expand_end_case_type): Renamed from expand_end_case. (expand_end_case): Define using expand_end_case_type. * c-semantics.c (genrtl_switch_stmt): Pass SWITCH_TYPE to expand_end_case_type. * doc/c-tree.texi (SWITCH_STMT): Document SWITCH_TYPE. * semantics.c (begin_switch_stmt): Clear SWITCH_TYPE. (finish_switch_cond): Set SWITCH_TYPE. * gcc.dg/Wswitch.c: Fix typos. Don't return unconditionally before all tests. Move warning one line above to match where it C frontend emits. * gcc.dg/Wswitch-2.c: New test. * g++.dg/warn/Wswitch-1.C: New test. * g++.dg/warn/Wswitch-2.C: New test. From-SVN: r49497 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a3aa6bef553..afd68d6fb02 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,19 @@ +2002-02-04 Jakub Jelinek + + PR c/4475, c++/3780: + * c-common.def (SWITCH_STMT): Add SWITCH_TYPE operand. + * c-common.h (SWITCH_TYPE): Define. + * c-typeck.c (c_start_case): Set SWITCH_TYPE. + * stmt.c (all_cases_count): Set lastval to thisval at end of loop. + Rename spareness variable to sparseness. + (expand_end_case_type): Renamed from expand_end_case, use orig_type + if non-NULL instead of TREE_TYPE (orig_index). + * tree.h (expand_end_case_type): Renamed from expand_end_case. + (expand_end_case): Define using expand_end_case_type. + * c-semantics.c (genrtl_switch_stmt): Pass SWITCH_TYPE + to expand_end_case_type. + * doc/c-tree.texi (SWITCH_STMT): Document SWITCH_TYPE. + 2002-02-04 John David Anglin * pa.h (PREFERRED_STACK_BOUNDARY): Define to match standard rounding. diff --git a/gcc/c-common.def b/gcc/c-common.def index d59a151680e..293f4b21bd3 100644 --- a/gcc/c-common.def +++ b/gcc/c-common.def @@ -71,8 +71,8 @@ DEFTREECODE (BREAK_STMT, "break_stmt", 'e', 0) DEFTREECODE (CONTINUE_STMT, "continue_stmt", 'e', 0) /* Used to represent a 'switch' statement. The operands are - SWITCH_COND and SWITCH_BODY, respectively. */ -DEFTREECODE (SWITCH_STMT, "switch_stmt", 'e', 2) + SWITCH_COND, SWITCH_BODY and SWITCH_TYPE, respectively. */ +DEFTREECODE (SWITCH_STMT, "switch_stmt", 'e', 3) /* Used to represent a 'goto' statement. The operand is GOTO_DESTINATION. */ DEFTREECODE (GOTO_STMT, "goto_stmt", 'e', 1) diff --git a/gcc/c-common.h b/gcc/c-common.h index 3aaa513ed66..c90cbfb076b 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -603,10 +603,12 @@ extern tree strip_array_types PARAMS ((tree)); #define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2) #define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3) -/* SWITCH_STMT accessors. These give access to the condition and body +/* SWITCH_STMT accessors. These give access to the condition, body and + original condition type (before any compiler conversions) of the switch statement, respectively. */ #define SWITCH_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0) #define SWITCH_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1) +#define SWITCH_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2) /* CASE_LABEL accessors. These give access to the high and low values of a case label, respectively. */ diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c index c0bbc515da8..8f99bc1f64c 100644 --- a/gcc/c-semantics.c +++ b/gcc/c-semantics.c @@ -644,7 +644,7 @@ genrtl_switch_stmt (t) emit_line_note (input_filename, lineno); expand_start_case (1, cond, TREE_TYPE (cond), "switch statement"); expand_stmt (SWITCH_BODY (t)); - expand_end_case (cond); + expand_end_case_type (cond, SWITCH_TYPE (t)); } /* Create a CASE_LABEL tree node and return it. */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index a00c7241f7e..8c34a17c5d3 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -7176,15 +7176,15 @@ c_start_case (exp) tree exp; { enum tree_code code; - tree type; + tree type, orig_type = error_mark_node; struct c_switch *cs; if (exp != error_mark_node) { code = TREE_CODE (TREE_TYPE (exp)); - type = TREE_TYPE (exp); + orig_type = TREE_TYPE (exp); - if (! INTEGRAL_TYPE_P (type) + if (! INTEGRAL_TYPE_P (orig_type) && code != ERROR_MARK) { error ("switch quantity not an integer"); @@ -7206,7 +7206,7 @@ c_start_case (exp) /* Add this new SWITCH_STMT to the stack. */ cs = (struct c_switch *) xmalloc (sizeof (*cs)); - cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, NULL_TREE); + cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type); cs->cases = splay_tree_new (case_compare, NULL, NULL); cs->next = switch_stack; switch_stack = cs; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index dfb3d4bdda2..f0cb0704b43 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2002-02-04 Jakub Jelinek + + * semantics.c (begin_switch_stmt): Clear SWITCH_TYPE. + (finish_switch_cond): Set SWITCH_TYPE. + 2002-02-04 Richard Henderson * method.c (use_thunk): Always initialize the block tree. Reindent. diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index cdc1178f338..c344a3016ef 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -500,7 +500,7 @@ tree begin_switch_stmt () { tree r; - r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE); + r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE); add_stmt (r); do_pushlevel (); return r; @@ -513,6 +513,7 @@ finish_switch_cond (cond, switch_stmt) tree cond; tree switch_stmt; { + tree orig_type = NULL; if (!processing_template_decl) { tree type; @@ -525,6 +526,7 @@ finish_switch_cond (cond, switch_stmt) error ("switch quantity not an integer"); cond = error_mark_node; } + orig_type = TREE_TYPE (cond); if (cond != error_mark_node) { cond = default_conversion (cond); @@ -542,6 +544,7 @@ finish_switch_cond (cond, switch_stmt) cond = index; } FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt)); + SWITCH_TYPE (switch_stmt) = orig_type; push_switch (switch_stmt); } diff --git a/gcc/doc/c-tree.texi b/gcc/doc/c-tree.texi index cbf01967dfa..65b39db0bb8 100644 --- a/gcc/doc/c-tree.texi +++ b/gcc/doc/c-tree.texi @@ -1631,7 +1631,8 @@ Used to represent a @code{switch} statement. The @code{SWITCH_COND} is the expression on which the switch is occurring. See the documentation for an @code{IF_STMT} for more information on the representation used for the condition. The @code{SWITCH_BODY} is the body of the switch -statement. +statement. The @code{SWITCH_TYPE} is the original type of switch +expression as given in the source, before any compiler conversions. @item TRY_BLOCK Used to represent a @code{try} block. The body of the try block is diff --git a/gcc/stmt.c b/gcc/stmt.c index 5d0e4c44388..99f910a9d21 100644 --- a/gcc/stmt.c +++ b/gcc/stmt.c @@ -4876,20 +4876,20 @@ add_case_node (low, high, label, duplicate) /* Returns the number of possible values of TYPE. Returns -1 if the number is unknown, variable, or if the number does not fit in a HOST_WIDE_INT. - Sets *SPARENESS to 2 if TYPE is an ENUMERAL_TYPE whose values + Sets *SPARSENESS to 2 if TYPE is an ENUMERAL_TYPE whose values do not increase monotonically (there may be duplicates); to 1 if the values increase monotonically, but not always by 1; otherwise sets it to 0. */ HOST_WIDE_INT -all_cases_count (type, spareness) +all_cases_count (type, sparseness) tree type; - int *spareness; + int *sparseness; { tree t; HOST_WIDE_INT count, minval, lastval; - *spareness = 0; + *sparseness = 0; switch (TREE_CODE (type)) { @@ -4928,11 +4928,12 @@ all_cases_count (type, spareness) { HOST_WIDE_INT thisval = tree_low_cst (TREE_VALUE (t), 0); - if (*spareness == 2 || thisval < lastval) - *spareness = 2; + if (*sparseness == 2 || thisval <= lastval) + *sparseness = 2; else if (thisval != minval + count) - *spareness = 1; + *sparseness = 1; + lastval = thisval; count++; } } @@ -5213,11 +5214,13 @@ free_case_nodes (cn) /* Terminate a case (Pascal) or switch (C) statement in which ORIG_INDEX is the expression to be tested. + If ORIG_TYPE is not NULL, it is the original ORIG_INDEX + type as given in the source before any compiler conversions. Generate the code to test it and jump to the right place. */ void -expand_end_case (orig_index) - tree orig_index; +expand_end_case_type (orig_index, orig_type) + tree orig_index, orig_type; { tree minval = NULL_TREE, maxval = NULL_TREE, range = NULL_TREE; rtx default_label = 0; @@ -5241,6 +5244,8 @@ expand_end_case (orig_index) index_expr = thiscase->data.case_stmt.index_expr; index_type = TREE_TYPE (index_expr); unsignedp = TREE_UNSIGNED (index_type); + if (orig_type == NULL) + orig_type = TREE_TYPE (orig_index); do_pending_stack_adjust (); @@ -5261,9 +5266,9 @@ expand_end_case (orig_index) No sense trying this if there's a default case, however. */ if (!thiscase->data.case_stmt.default_label - && TREE_CODE (TREE_TYPE (orig_index)) == ENUMERAL_TYPE + && TREE_CODE (orig_type) == ENUMERAL_TYPE && TREE_CODE (index_expr) != INTEGER_CST) - check_for_full_enumeration_handling (TREE_TYPE (orig_index)); + check_for_full_enumeration_handling (orig_type); /* If we don't have a default-label, create one here, after the body of the switch. */ @@ -5420,7 +5425,7 @@ expand_end_case (orig_index) default code is emitted. */ use_cost_table - = (TREE_CODE (TREE_TYPE (orig_index)) != ENUMERAL_TYPE + = (TREE_CODE (orig_type) != ENUMERAL_TYPE && estimate_case_costs (thiscase->data.case_stmt.case_list)); balance_case_nodes (&thiscase->data.case_stmt.case_list, NULL); emit_case_nodes (index, thiscase->data.case_stmt.case_list, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c27aab81528..6393589a19a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2002-02-04 Jakub Jelinek + + * gcc.dg/Wswitch.c: Fix typos. Don't return unconditionally + before all tests. Move warning one line above to match where it + C frontend emits. + * gcc.dg/Wswitch-2.c: New test. + * g++.dg/warn/Wswitch-1.C: New test. + * g++.dg/warn/Wswitch-2.C: New test. + 2002-02-04 Richard Henderson * g++.dg/abi/offsetof.C: Fix size comparison. diff --git a/gcc/testsuite/g++.dg/warn/Wswitch-1.C b/gcc/testsuite/g++.dg/warn/Wswitch-1.C new file mode 100644 index 00000000000..e9fcb581817 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wswitch-1.C @@ -0,0 +1,63 @@ +/* PR c/4475, PR c++/3780 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch" } */ + +enum e { e1, e2 }; + +int +foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, + enum e em, enum e en, enum e eo, enum e ep) +{ + switch (i) + { + case 1: return 1; + case 2: return 2; + } + switch (j) + { + case 3: return 4; + case 4: return 3; + default: break; + } + switch (ei) + { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" { target *-*-* } 24 } */ + } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ + switch (ej) + { + default: break; + } + switch (ek) + { + case e1: return 1; + } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ + switch (el) + { + case e1: return 1; + default: break; + } + switch (em) + { + case e1: return 1; + case e2: return 2; + } + switch (en) + { + case e1: return 1; + case e2: return 2; + default: break; + } + switch (eo) + { + case e1: return 1; + case e2: return 2; + case 3: return 3; + } /* { dg-warning "case value `3' not in enumerated type `e'" "excess 3" } */ + switch (ep) + { + case e1: return 1; + case e2: return 2; + case 3: return 3; + default: break; + } /* Since there is a default, no warning about ``case 3'' */ + return 0; +} diff --git a/gcc/testsuite/g++.dg/warn/Wswitch-2.C b/gcc/testsuite/g++.dg/warn/Wswitch-2.C new file mode 100644 index 00000000000..b151e2310c7 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wswitch-2.C @@ -0,0 +1,31 @@ +/* Further -Wswitch tests. */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch" } */ + +enum e { e1 = 0, e2 = 1, e3 = 1, e4 = 2 }; + +int +foo (enum e ei, int j) +{ + switch (ei) + { + case e1: return 1; + case e3: return 2; + case e4: return 3; + } /* No warning here since e2 has the same value as e3. */ + switch (ei) + { + case e1: return 1; + case e2: return 2; + } /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */ + switch ((int) ei) + { + case e1: return 1; + } /* No warning here since switch condition was cast to int. */ + switch ((enum e) j) + { + case e2: return 1; + case e4: return 2; + } /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ + return 0; +} diff --git a/gcc/testsuite/gcc.dg/Wswitch-2.c b/gcc/testsuite/gcc.dg/Wswitch-2.c new file mode 100644 index 00000000000..b151e2310c7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wswitch-2.c @@ -0,0 +1,31 @@ +/* Further -Wswitch tests. */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch" } */ + +enum e { e1 = 0, e2 = 1, e3 = 1, e4 = 2 }; + +int +foo (enum e ei, int j) +{ + switch (ei) + { + case e1: return 1; + case e3: return 2; + case e4: return 3; + } /* No warning here since e2 has the same value as e3. */ + switch (ei) + { + case e1: return 1; + case e2: return 2; + } /* { dg-warning "enumeration value `e4' not handled in switch" "enum e4" } */ + switch ((int) ei) + { + case e1: return 1; + } /* No warning here since switch condition was cast to int. */ + switch ((enum e) j) + { + case e2: return 1; + case e4: return 2; + } /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ + return 0; +} diff --git a/gcc/testsuite/gcc.dg/Wswitch.c b/gcc/testsuite/gcc.dg/Wswitch.c index 372b9158c16..014919b87bd 100644 --- a/gcc/testsuite/gcc.dg/Wswitch.c +++ b/gcc/testsuite/gcc.dg/Wswitch.c @@ -1,4 +1,4 @@ -/* PR gcc/4475, PR gcc/3780 */ +/* PR c/4475, PR c++/3780 */ /* { dg-do compile } */ /* { dg-options "-Wswitch" } */ @@ -17,11 +17,11 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, { case 3: return 4; case 4: return 3; - default: return 7; + default: break; } switch (ei) - { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" { target *-*-* } 24 } */ - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ + { /* { dg-warning "enumeration value `e1' not handled in switch" "enum e1" } */ + } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" { target *-*-* } 23 } */ switch (ej) { default: break; @@ -29,7 +29,7 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, switch (ek) { case e1: return 1; - } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e1" } */ + } /* { dg-warning "enumeration value `e2' not handled in switch" "enum e2" } */ switch (el) { case e1: return 1; @@ -58,6 +58,6 @@ foo (int i, int j, enum e ei, enum e ej, enum e ek, enum e el, case e2: return 2; case 3: return 3; default: break; - } /* Since there is a default, no warning about ``case 3'' } */ + } /* Since there is a default, no warning about ``case 3'' */ return 0; } diff --git a/gcc/tree.h b/gcc/tree.h index e7b634d81f2..842c0a9924f 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -2772,7 +2772,8 @@ extern struct nesting * current_nesting_level PARAMS ((void)); extern tree last_cleanup_this_contour PARAMS ((void)); extern void expand_start_case PARAMS ((int, tree, tree, const char *)); -extern void expand_end_case PARAMS ((tree)); +extern void expand_end_case_type PARAMS ((tree, tree)); +#define expand_end_case(cond) expand_end_case_type (cond, NULL) extern int add_case_node PARAMS ((tree, tree, tree, tree *)); extern int pushcase PARAMS ((tree,