Summary: | [4.0 regression] Bitwise AND is lost when used within a cast to an enum of the same precision | ||
---|---|---|---|
Product: | gcc | Reporter: | Paul Gotch <p.r.gotch> |
Component: | middle-end | Assignee: | roger |
Status: | RESOLVED FIXED | ||
Severity: | critical | CC: | gcc-bugs, mmitchel, reichelt, roger |
Priority: | P2 | Keywords: | monitored, wrong-code |
Version: | 3.4.1 | ||
Target Milestone: | 3.4.2 | ||
Host: | i686-pc-linux-gnu | Target: | |
Build: | i686-pc-linux-gnu | Known to work: | 3.3.3 3.3.4 3.4.2 4.0.0 |
Known to fail: | 3.4.0 3.4.1 | Last reconfirmed: | 2004-07-23 19:04:45 |
Attachments: | Preprocessed output of the code in the defect report |
Description
Paul Gotch
2004-07-23 17:15:25 UTC
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. |