diff options
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 85 |
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); |