The following code produces incorrect results when compiled with GCC 3.4.0 and 3.4.1. With both of these compilers the bitwise "AND" gets ignored and the value of "r1" ends up as 0x66 rather than 0x6. GCC 3.3.3 generates the correct answer as does GCC 3.5.0 snapshot taken on 20040717. The console output of the compiler during this run was: Reading specs from /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/lib/gcc/i686-pc -linux-gnu/3.4.1/specs Configured with: ./configure --prefix=/arm/eda/tools/gnu/gcc/3_4_1 --exec-prefix =/arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86 --program-suffix=-3_4_1 -v --with -dwarf2 --enable-version-specific-runtime-libs --with-gnu-as --with-as=/arm/eda/ tools/gnu/binutils/2_15_90_0_3/linux_rh_7_2-x86/bin/as-2_15_90_0_3 --with-gnu-ld --with-ld=/arm/eda/tools/gnu/binutils/2_15_90_0_3/linux_rh_7_2-x86/bin/ld-2_15_ 90_0_3 Thread model: posix gcc version 3.4.1 /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/libexec/gcc/i686-pc-linux-gnu/3.4 .1/cc1plus -E -quiet -v -D_GNU_SOURCE tst_gcc.cpp -mtune=pentiumpro -o tst_gcc.i i ignoring nonexistent directory "/arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/li b/gcc/i686-pc-linux-gnu/3.4.1/../../../../i686-pc-linux-gnu/include" #include "..." search starts here: #include <...> search starts here: /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/lib/gcc/i686-pc-linux-gnu/3.4.1/i nclude/c++ /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/lib/gcc/i686-pc-linux-gnu/3.4.1/i nclude/c++/i686-pc-linux-gnu /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/lib/gcc/i686-pc-linux-gnu/3.4.1/i nclude/c++/backward /usr/local/include /arm/eda/tools/gnu/gcc/3_4_1/include /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/lib/gcc/i686-pc-linux-gnu/3.4.1/i nclude /usr/include End of search list. /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/libexec/gcc/i686-pc-linux-gnu/3.4 .1/cc1plus -fpreprocessed tst_gcc.ii -quiet -dumpbase tst_gcc.cpp -mtune=pentium pro -auxbase tst_gcc -version -o tst_gcc.s GNU C++ version 3.4.1 (i686-pc-linux-gnu) compiled by GNU C version 3.4.1. GGC heuristics: --param ggc-min-expand=98 --param ggc-min-heapsize=129190 /arm/eda/tools/gnu/binutils/2_15_90_0_3/linux_rh_7_2-x86/bin/as-2_15_90_0_3 -V -Qy -o tst_gcc.o tst_gcc.s GNU assembler version 2.15.90.0.3 (i686-pc-linux-gnu) using BFD version 2.15.90. 0.3 20040415 /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/libexec/gcc/i686-pc-linux-gnu/3.4 .1/collect2 --eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 -o tst _gcc /usr/lib/crt1.o /usr/lib/crti.o /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x 86/lib/gcc/i686-pc-linux-gnu/3.4.1/crtbegin.o -L/arm/eda/tools/gnu/gcc/3_4_1/lin ux_rh_7_2-x86/lib/gcc/i686-pc-linux-gnu/3.4.1 -L/arm/eda/tools/gnu/gcc/3_4_1/lin ux_rh_7_2-x86/lib/gcc/i686-pc-linux-gnu/3.4.1/../../.. tst_gcc.o -lstdc++ -lm -l gcc_s -lgcc -lc -lgcc_s -lgcc /arm/eda/tools/gnu/gcc/3_4_1/linux_rh_7_2-x86/lib/ gcc/i686-pc-linux-gnu/3.4.1/crtend.o /usr/lib/crtn.o ---- #include <iostream> unsigned short ret6666(int) { return 0x66; } typedef enum { a = 0x0, b = 0x1, c = 0x2, d = 0x3, e = 0x4, f = 0x5, g = 0x6, h = 0x7, i = 0x8, j = 0x9, k = 0xa, l = 0xb, m = 0xc, n = 0xd, o = 0xe, p = 0xf } Test_Enum; int main(void) { unsigned char r1; r1 = static_cast<Test_Enum>(0xf & ret6666(44)); if(r1 == 0x6) { std::cout << "Passed" << std::endl; exit(0); } else { std::cout << "Failed" << std::endl; exit(1); } }
Created attachment 6814 [details] Preprocessed output of the code in the defect report
Confirmed. A regression in 3.4 and mainline against 3.3.4. W.
BTW, my mainline snapshot from 2004-07-21 fails this testcase, too. W.
I've now tried this on SPARC as well as i686 and I get the same results which suggests this is a front end rather than a target specific problem.
A collegue has done some more investigation and come up with the following additional constraints. If the enum pushes into the top nibble then the problem does not occur. A similar problem occurs with unsigned short where the problem occurs if the enumeration fits into a byte. If the target variable is an unsigned int rather than a unsigned char or short the problem does not occur.
I think this is caused by fold which does the following transformation: (cast)(a & constant) -> ((cast)a) & ((cast)constant).
Here's a condensed version (which should return 0): ===================================== char foo() { return 0x10; } enum E { e = 0x0f }; int main() { return (char)(E)(e & foo()); } ===================================== Btw, the bug only occurs with the C++ frontend and not with plain C.
This is a duplicate of some other PR -- I'm just not sure which. In C++, the compiler can assume that there will be no values of the enum greater than 0xf, given the declaration. That is why the compiler omits the bitwise-and.
The bitwise and is applied to something that isn't an enumerated type (it's wider than that), and it's whole purpose is to reduce the value to something that then *can* be cast to the enumerated type. It's not as if the user had written 0xf & static_cast<Test_Enum>(ret6666(44)); Which would be incorrect.
I agree. Roger, I think this is a problem in fold with this code: /* Convert (T)(x & c) into (T)x & (T)c, if c is an integer constants (if x has signed type, the sign bit cannot be set in c). This folds extension into the BIT_AND_EXPR. */ if (INTEGRAL_TYPE_P (type) && TREE_CODE (type) != BOOLEAN_TYPE && TREE_CODE (TREE_OPERAND (t, 0)) == BIT_AND_EXPR && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == INTEGER_CST) The problem is that we turn: (enum E) ((unsigned int) (expr) & 0xf) into: (E) (unsigned int) (expr) & (E) 0xf which is not valid because "expr" may not be within the range of "E". (In this case "E" has the range [0, 0xf].) The original code has a well-defined meaning; the resulting code has an "unspecified" meaning according to the C++ standard. I think this transformation is only safe if the values can be shown to be in range, as would be the case if the TYPE_PRECISION of "E" was as big as that of "unsigned int". Therefore, I've assigned this bug to you.
Subject: Bug 16693 CVSROOT: /cvs/gcc Module name: gcc Branch: gcc-3_4-branch Changes by: sayle@gcc.gnu.org 2004-08-25 17:22:10 Modified files: gcc/cp : ChangeLog decl.c gcc/testsuite : ChangeLog Added files: gcc/testsuite/g++.dg/opt: pr16372-1.C pr16693-1.C pr16693-2.C Log message: PR middle-end/16693 PR tree-optimization/16372 * decl.c (finish_enum): Make the precision of the enumerated type the same width as the underlying integer type. * g++.dg/opt/pr16372-1.C: New test case. * g++.dg/opt/pr16693-1.C: New test case. * g++.dg/opt/pr16693-2.C: New test case. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3892.2.153&r2=1.3892.2.154 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/decl.c.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.1174.2.22&r2=1.1174.2.23 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=1.3389.2.260&r2=1.3389.2.261 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr16372-1.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.2.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr16693-1.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.2.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr16693-2.C.diff?cvsroot=gcc&only_with_tag=gcc-3_4-branch&r1=NONE&r2=1.1.2.1
Subject: Bug 16693 CVSROOT: /cvs/gcc Module name: gcc Changes by: sayle@gcc.gnu.org 2004-08-25 20:51:02 Modified files: gcc/cp : ChangeLog decl.c gcc/testsuite : ChangeLog Added files: gcc/testsuite/g++.dg/opt: pr16372-1.C pr16693-1.C pr16693-2.C Log message: PR middle-end/16693 PR tree-optimization/16372 * decl.c (finish_enum): Make the precision of the enumerated type the same width as the underlying integer type. * g++.dg/opt/pr16372-1.C: New test case. * g++.dg/opt/pr16693-1.C: New test case. * g++.dg/opt/pr16693-2.C: New test case. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&r1=1.4308&r2=1.4309 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/decl.c.diff?cvsroot=gcc&r1=1.1278&r2=1.1279 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.4192&r2=1.4193 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr16372-1.C.diff?cvsroot=gcc&r1=1.1&r2=1.2 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr16693-1.C.diff?cvsroot=gcc&r1=1.1&r2=1.2 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/opt/pr16693-2.C.diff?cvsroot=gcc&r1=1.1&r2=1.2
Fixed.
Milestone update for release note extraction.