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)
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
and there is no default label.
......@@ -4097,37 +4284,55 @@ check_for_full_enumeration_handling (type)
register tree chain;
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)
{
bc_check_for_full_enumeration_handling (type);
return;
}
/* The time complexity of this loop is currently O(N * M), with
N being the number of members in the enumerated type, and
M being the number of case expressions in the switch. */
if (! warn_switch)
return;
size = all_cases_count (type, &sparseness);
bytes_needed = (size + HOST_BITS_PER_CHAR) / HOST_BITS_PER_CHAR;
for (chain = TYPE_VALUES (type);
chain;
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.
Quit looking when we've gone too far (since case expressions
are kept sorted in ascending order). Warn about enumerators not
handled in the switch statement case expression list. */
for (n = case_stack->data.case_stmt.case_list;
n && tree_int_cst_lt (n->high, TREE_VALUE (chain));
n = n->right)
;
long i;
tree v = TYPE_VALUES (type);
bzero (cases_seen, bytes_needed);
/* The time complexity of this code is normally O(N), where
N being the number of members in the enumerated type.
However, if type is a ENUMERAL_TYPE whose values do not
increase monotonically, quadratic time may be needed. */
if (!n || tree_int_cst_lt (TREE_VALUE (chain), n->low))
mark_seen_cases (type, cases_seen, size, sparseness);
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",
IDENTIFIER_POINTER (TREE_PURPOSE (chain)));
all_values = 0;
IDENTIFIER_POINTER (TREE_PURPOSE (v)));
}
free (cases_seen);
}
/* 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