Commit 94d6511c by Per Bothner

stmt.c (all_cases_count, [...]): New functions.

* stmt.c (all_cases_count, mark_seen_cases):  New functions.
(BITARRAY_TEST, BITARRAY_SET):  New macros.  Used (mainly by
Chill) to check all cases are covered (for enums and ranges).
(check_for_full_enumeration_handling):  Re-write to use the
new functions, now that we have them.

From-SVN: r8009
parent 91378b76
...@@ -4077,6 +4077,193 @@ bc_pushcase (value, label) ...@@ -4077,6 +4077,193 @@ bc_pushcase (value, label)
return 0; return 0;
} }
/* Returns the number of possible values of TYPE.
Returns -1 if the number is unknown or variable.
Returns -2 if the number does not fit in a HOST_WIDE_INT.
Sets *SPARENESS 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)
tree type;
int *spareness;
{
HOST_WIDE_INT count, count_high = 0;
*spareness = 0;
switch (TREE_CODE (type))
{
tree t;
case BOOLEAN_TYPE:
count = 2;
break;
case CHAR_TYPE:
count = 1 << BITS_PER_UNIT;
break;
default:
case INTEGER_TYPE:
if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
|| TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST)
return -1;
else
{
/* count
= TREE_INT_CST_LOW (TYPE_MAX_VALUE (type))
- TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + 1
but with overflow checking. */
tree mint = TYPE_MIN_VALUE (type);
tree maxt = TYPE_MAX_VALUE (type);
HOST_WIDE_INT lo, hi;
neg_double(TREE_INT_CST_LOW (mint), TREE_INT_CST_HIGH (mint),
&lo, &hi);
add_double(TREE_INT_CST_LOW (maxt), TREE_INT_CST_HIGH (maxt),
lo, hi, &lo, &hi);
add_double (lo, hi, 1, 0, &lo, &hi);
if (hi != 0 || lo < 0)
return -2;
count = lo;
}
break;
case ENUMERAL_TYPE:
count = 0;
for (t = TYPE_VALUES (type); t != NULL_TREE; t = TREE_CHAIN (t))
{
if (TREE_CODE (TYPE_MIN_VALUE (type)) != INTEGER_CST
|| TREE_CODE (TREE_VALUE (t)) != INTEGER_CST
|| TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) + count
!= TREE_INT_CST_LOW (TREE_VALUE (t)))
*spareness = 1;
count++;
}
if (*spareness == 1)
{
tree prev = TREE_VALUE (TYPE_VALUES (type));
for (t = TYPE_VALUES (type); t = TREE_CHAIN (t), t != NULL_TREE; )
{
if (! tree_int_cst_lt (prev, TREE_VALUE (t)))
{
*spareness = 2;
break;
}
prev = TREE_VALUE (t);
}
}
}
return count;
}
#define BITARRAY_TEST(ARRAY, INDEX) \
((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
& (1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR)))
#define BITARRAY_SET(ARRAY, INDEX) \
((ARRAY)[(unsigned)(INDEX) / HOST_BITS_PER_CHAR]\
|= 1 << ((unsigned)(INDEX) % HOST_BITS_PER_CHAR))
/* Set the elements of the bitstring CASES_SEEN (which has length COUNT),
with the case values we have seen, assuming the case expression
has the given TYPE.
SPARSENESS is as determined by all_cases_count.
The time needed is propotional to COUNT, unless
SPARSENESS is 2, in which case quadratic time is needed. */
void
mark_seen_cases (type, cases_seen, count, sparseness)
tree type;
unsigned char *cases_seen;
long count;
int sparseness;
{
long i;
tree next_node_to_try = NULL_TREE;
long next_node_offset = 0;
register struct case_node *n;
tree val = make_node (INTEGER_CST);
TREE_TYPE (val) = type;
for (n = case_stack->data.case_stmt.case_list; n;
n = n->right)
{
TREE_INT_CST_LOW (val) = TREE_INT_CST_LOW (n->low);
TREE_INT_CST_HIGH (val) = TREE_INT_CST_HIGH (n->low);
while ( ! tree_int_cst_lt (n->high, val))
{
/* Calculate (into xlo) the "offset" of the integer (val).
The element with lowest value has offset 0, the next smallest
element has offset 1, etc. */
HOST_WIDE_INT xlo, xhi;
tree t;
if (sparseness == 2)
{
/* This less efficient loop is only needed to handle
duplicate case values (multiple enum constants
with the same value). */
for (t = TYPE_VALUES (type), xlo = 0; t != NULL_TREE;
t = TREE_CHAIN (t), xlo++)
{
if (tree_int_cst_equal (val, TREE_VALUE (t)))
BITARRAY_SET (cases_seen, xlo);
}
}
else
{
if (sparseness && TYPE_VALUES (type) != NULL_TREE)
{
/* The TYPE_VALUES will be in increasing order, so
starting searching where we last ended. */
t = next_node_to_try;
xlo = next_node_offset;
xhi = 0;
for (;;)
{
if (t == NULL_TREE)
{
t = TYPE_VALUES (type);
xlo = 0;
}
if (tree_int_cst_equal (val, TREE_VALUE (t)))
{
next_node_to_try = TREE_CHAIN (t);
next_node_offset = xlo + 1;
break;
}
xlo++;
t = TREE_CHAIN (t);
if (t == next_node_to_try)
break;
}
}
else
{
t = TYPE_MIN_VALUE (type);
if (t)
neg_double (TREE_INT_CST_LOW (t), TREE_INT_CST_HIGH (t),
&xlo, &xhi);
else
xlo = xhi = 0;
add_double (xlo, xhi,
TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
&xlo, &xhi);
}
if (xhi != 0 || xlo < 0 || xlo >= count)
fatal ("internal error - mark_cases_seen");
else
BITARRAY_SET (cases_seen, xlo);
}
add_double (TREE_INT_CST_LOW (val), TREE_INT_CST_HIGH (val),
1, 0,
&TREE_INT_CST_LOW (val), &TREE_INT_CST_HIGH (val));
}
}
}
/* Called when the index of a switch statement is an enumerated type /* Called when the index of a switch statement is an enumerated type
and there is no default label. and there is no default label.
...@@ -4097,37 +4284,55 @@ check_for_full_enumeration_handling (type) ...@@ -4097,37 +4284,55 @@ check_for_full_enumeration_handling (type)
register tree chain; register tree chain;
int all_values = 1; int all_values = 1;
/* True iff the selector type is a numbered set mode. */
int sparseness = 0;
/* The number of possible selector values. */
HOST_WIDE_INT size;
/* For each possible selector value. a one iff it has been matched
by a case value alternative. */
unsigned char *cases_seen;
/* The allocated size of cases_seen, in chars. */
long bytes_needed;
tree t;
if (output_bytecode) if (output_bytecode)
{ {
bc_check_for_full_enumeration_handling (type); bc_check_for_full_enumeration_handling (type);
return; return;
} }
/* The time complexity of this loop is currently O(N * M), with if (! warn_switch)
N being the number of members in the enumerated type, and return;
M being the number of case expressions in the switch. */
for (chain = TYPE_VALUES (type); size = all_cases_count (type, &sparseness);
chain; bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
chain = TREE_CHAIN (chain))
if (size > 0 && size < 600000
/* We deliberately use malloc here - not xmalloc. */
&& (cases_seen = (char*) malloc (bytes_needed)) != NULL)
{ {
/* Find a match between enumeral and case expression, if possible. long i;
Quit looking when we've gone too far (since case expressions tree v = TYPE_VALUES (type);
are kept sorted in ascending order). Warn about enumerators not bzero (cases_seen, bytes_needed);
handled in the switch statement case expression list. */
for (n = case_stack->data.case_stmt.case_list; /* The time complexity of this code is normally O(N), where
n && tree_int_cst_lt (n->high, TREE_VALUE (chain)); N being the number of members in the enumerated type.
n = n->right) However, if type is a ENUMERAL_TYPE whose values do not
; increase monotonically, quadratic time may be needed. */
mark_seen_cases (type, cases_seen, size, sparseness);
if (!n || tree_int_cst_lt (TREE_VALUE (chain), n->low)) for (i = 0; v != NULL_TREE && i < size; i++, v = TREE_CHAIN (v))
{ {
if (warn_switch) if (BITARRAY_TEST(cases_seen, i) == 0)
warning ("enumeration value `%s' not handled in switch", warning ("enumeration value `%s' not handled in switch",
IDENTIFIER_POINTER (TREE_PURPOSE (chain))); IDENTIFIER_POINTER (TREE_PURPOSE (v)));
all_values = 0;
} }
free (cases_seen);
} }
/* Now we go the other way around; we warn if there are case /* Now we go the other way around; we warn if there are case
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment