aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-common.c
diff options
context:
space:
mode:
authorSteven Bosscher <stevenb@suse.de>2004-07-20 09:57:13 +0000
committerSteven Bosscher <steven@gcc.gnu.org>2004-07-20 09:57:13 +0000
commita6c0a76c5f9eb216b5f08ffc4624a6d039ca3977 (patch)
tree134a4370313a4f575f6aa704b0deb37112d1b859 /gcc/c-common.c
parent5794581363d5c74938f0e200b4c899a5b26229e9 (diff)
downloadgcc-a6c0a76c5f9eb216b5f08ffc4624a6d039ca3977.zip
gcc-a6c0a76c5f9eb216b5f08ffc4624a6d039ca3977.tar.gz
gcc-a6c0a76c5f9eb216b5f08ffc4624a6d039ca3977.tar.bz2
c-common.h (check_case_value): Remove prototype.
* c-common.h (check_case_value): Remove prototype. (c_add_case_label): Adjust prototype. * c-common.c (check_case_value): Make static. (check_case_bounds): New function. (c_add_case_label): Use it. Take new argument orig_type. * c-typeck.c (struct c_switch): New orig_type field. (c_start_case): Set it. (do_case): Pass it to c_add_case_label. * expr.c (expand_expr_real_1): Don't warn for out-of-bounds cases from here. Add the labels in reverse order. * stmt.c (struct case_node): Adjust comment. Remove balance field. (add_case_node): Return nothing, don't check for duplicate cases. Insert new case nodes in a list, not in an AVL tree. (expand_end_case_type): Don't turn a case tree into a case list. (case_tree2list): Remove. * tree.h (add_case_node): Adjust prototype. cp/ * cp-tree.h (struct lang_decl_flags): Unify the template_info and thunk_alias, and the access and virtual_offset fields. (THUNK_VIRTUAL_OFFSET, THUNK_ALIAS): Adjust. * decl.c (finish_case_label): Update c_add_case_node call. testsuite/ * testsuite/gcc.dg/switch-warn-1.c: New test. * testsuite/gcc.dg/switch-warn-2.c: New test. * gcc.c-torture/compile/pr14730.c: Update From-SVN: r84947
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r--gcc/c-common.c85
1 files changed, 82 insertions, 3 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 1966b0d..093e839 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -510,6 +510,8 @@ const struct fname_var_t fname_vars[] =
};
static int constant_fits_type_p (tree, tree);
+static tree check_case_value (tree);
+static bool check_case_bounds (tree, tree, tree *, tree *);
static tree handle_packed_attribute (tree *, tree, tree, int, bool *);
static tree handle_nocommon_attribute (tree *, tree, tree, int, bool *);
@@ -1400,7 +1402,7 @@ verify_sequence_points (tree expr)
/* Validate the expression after `case' and apply default promotions. */
-tree
+static tree
check_case_value (tree value)
{
if (value == NULL_TREE)
@@ -1436,6 +1438,75 @@ check_case_value (tree value)
return value;
}
+/* See if the case values LOW and HIGH are in the range of the original
+ type (ie. before the default conversion to int) of the switch testing
+ expression.
+ TYPE is the promoted type of the testing expression, and ORIG_TYPE is
+ the type before promiting it. CASE_LOW_P is a pointer to the lower
+ bound of the case label, and CASE_HIGH_P is the upper bound or NULL
+ if the case is not a case range.
+ The caller has to make sure that we are not called with NULL for
+ CASE_LOW_P (ie. the defualt case).
+ Returns true if the case label is in range of ORIG_TYPE (satured or
+ untouched) or false if the label is out of range. */
+
+static bool
+check_case_bounds (tree type, tree orig_type,
+ tree *case_low_p, tree *case_high_p)
+{
+ tree min_value, max_value;
+ tree case_low = *case_low_p;
+ tree case_high = case_high_p ? *case_high_p : case_low;
+
+ /* If there was a problem with the original type, do nothing. */
+ if (orig_type == error_mark_node)
+ return true;
+
+ min_value = TYPE_MIN_VALUE (orig_type);
+ max_value = TYPE_MAX_VALUE (orig_type);
+
+ /* Case label is less than minimum for type. */
+ if (tree_int_cst_compare (case_low, min_value) < 0
+ && tree_int_cst_compare (case_high, min_value) < 0)
+ {
+ warning ("case label value is less than minimum value for type");
+ return false;
+ }
+
+ /* Case value is greater than maximum for type. */
+ if (tree_int_cst_compare (case_low, max_value) > 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning ("case label value exceeds maximum value for type");
+ return false;
+ }
+
+ /* Saturate lower case label value to minimum. */
+ if (tree_int_cst_compare (case_high, min_value) >= 0
+ && tree_int_cst_compare (case_low, min_value) < 0)
+ {
+ warning ("lower value in case label range"
+ " less than minimum value for type");
+ case_low = min_value;
+ }
+
+ /* Saturate upper case label value to maximum. */
+ if (tree_int_cst_compare (case_low, max_value) <= 0
+ && tree_int_cst_compare (case_high, max_value) > 0)
+ {
+ warning ("upper value in case label range"
+ " exceeds maximum value for type");
+ case_high = max_value;
+ }
+
+ if (*case_low_p != case_low)
+ *case_low_p = convert (type, case_low);
+ if (case_high_p && *case_high_p != case_high)
+ *case_high_p = convert (type, case_high);
+
+ return true;
+}
+
/* Return an integer type with BITS bits of precision,
that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */
@@ -3402,8 +3473,8 @@ case_compare (splay_tree_key k1, splay_tree_key k2)
ERROR_MARK_NODE if no CASE_LABEL_EXPR is created. */
tree
-c_add_case_label (splay_tree cases, tree cond, tree low_value,
- tree high_value)
+c_add_case_label (splay_tree cases, tree cond, tree orig_type,
+ tree low_value, tree high_value)
{
tree type;
tree label;
@@ -3453,6 +3524,14 @@ c_add_case_label (splay_tree cases, tree cond, tree low_value,
&& !tree_int_cst_lt (low_value, high_value))
warning ("empty range specified");
+ /* See if the case is in range of the type of the original testing
+ expression. If both low_value and high_value are out of range,
+ don't insert the case label and return NULL_TREE. */
+ if (low_value
+ && ! check_case_bounds (type, orig_type,
+ &low_value, high_value ? &high_value : NULL))
+ return NULL_TREE;
+
/* Look up the LOW_VALUE in the table of case labels we already
have. */
node = splay_tree_lookup (cases, (splay_tree_key) low_value);