This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix C++ enums handling in build_range_check
- From: Jakub Jelinek <jakub at redhat dot com>
- To: Richard Henderson <rth at redhat dot com>, Roger Sayle <roger at eyesopen dot com>
- Cc: gcc-patches at gcc dot gnu dot org, dcbw at redhat dot com
- Date: Fri, 9 Jul 2004 12:22:55 -0400
- Subject: [PATCH] Fix C++ enums handling in build_range_check
- Reply-to: Jakub Jelinek <jakub at redhat dot com>
Hi!
This bug has been caught in OOo, present in both 3.4.x and on the trunk.
Surprisingly it has not been introduced by my recent build_range_check
patch and exists on vanilla 3.4.x where that patch has not been commited.
extern "C" void abort (void);
enum E { E0, E1, E2, E3, E4, E5 };
void
test (enum E e)
{
if (e == E2 || e == E3 || e == E1)
abort ();
}
int
main (void)
{
test (E4);
test (E5);
test (E0);
return 0;
}
The above testcase will abort with -O1 and above.
The problem is that this enum has TYPE_PRECISION 3 and build_range_check
special cases c >= 1 && c <= 127 range comparisons (where 127 stands
for largest signed value in that type).
This results in "optimizing" the e >= 1 && e <= 3 test into
(signed E) e > 0, but as the comparison is in the end not done in the
3 bit type but in SImode which is the underlying enum's TYPE_MODE,
we get it wrong.
Ok for trunk and 3.4?
For 3.4 where the range-test-1.[cC] tests don't exist I'd like to commit
the whole tests instead of commiting a testcase like above.
2004-07-09 Jakub Jelinek <jakub@redhat.com>
* fold-const.c (build_range_check): Use TYPE_MODE's precision for
enumerals.
* g++.dg/opt/range-test-1.C: Add new test (#26).
--- gcc/fold-const.c.jj 2004-07-09 13:50:54.000000000 +0200
+++ gcc/fold-const.c 2004-07-09 18:10:52.945905468 +0200
@@ -3844,7 +3844,13 @@ build_range_check (tree type, tree exp,
HOST_WIDE_INT hi;
int prec;
- prec = TYPE_PRECISION (etype);
+ /* For enums the comparison will be done in the underlying type,
+ so using enum's precision is wrong here.
+ Consider e.g. enum { A, B, C, D, E }, low == B and high == D. */
+ if (TREE_CODE (etype) == ENUMERAL_TYPE)
+ prec = GET_MODE_BITSIZE (TYPE_MODE (etype));
+ else
+ prec = TYPE_PRECISION (etype);
if (prec <= HOST_BITS_PER_WIDE_INT)
{
hi = 0;
--- gcc/testsuite/g++.dg/opt/range-test-1.C.jj 2004-06-19 00:38:06.000000000 +0200
+++ gcc/testsuite/g++.dg/opt/range-test-1.C 2004-07-09 18:06:27.501797366 +0200
@@ -176,6 +176,9 @@ T(24, signed char, x == SCHAR_MIN || x =
T(25, integers, x == int_smallest || x == int_largest,
{ int_smallest C int_largest }, { int_minus1 C int_zero C int_one
C int_2ndsmallest C int_2ndlargest C int_3rdsmallest C int_3rdlargest })
+T(26, enum3, x == enum3_one || x == enum3_two || x == enum3_three,
+ { enum3_one C enum3_two C enum3_three }, { enum3_zero C enum3_four
+ C enum3_five C enum3_six C enum3_seven })
/* These should be optimized into unconditional jumps. */
T(o1, unsigned long, x <= 16 || (x >= 17 && x <= -1UL),
Jakub