As reported at: https://sourceforge.net/tracker/index.php?func=detail&aid=1266135&group_id=2435&atid=102435 int main() { int value=1; !(value?true:throw); return 0; } main.cc: In function 'int main()': main.cc:4: internal compiler error: in invert_truthvalue, at fold-const.c:3064 This also fails with 3.4.2 Danny
Confirmed, I am deciding if we can declare this as a regression as this did not ICE in 2.95.3 but was rejected which is just as bad. But since we decided before ICE from any thing is a regression, we can declare this as a regression.
Ho humm, we had this before. invert_truthvalue is supposed to be called with sth that passes the truth_value_p check... But the real problem is the COND_EXPR has wrong types: <cond_expr 0x4019b140 type <boolean_type 0x4019f4ac bool public unsigned QI size <integer_cst 0x4018d1f8 constant invariant 8> unit size <integer_cst 0x4018d210 constant invariant 1> align 8 symtab 0 alias set -1 precision 1 min <integer_cst 0x4018d5e8 0> max <integer_cst 0x4018d618 1>> side-effects arg 0 <eq_expr 0x40195144 type <boolean_type 0x4019f4ac bool> arg 0 <var_decl 0x4019a210 value type <integer_type 0x4019f284 int> used tree_1 tree_2 tree_3 decl_5 SI file t.C line 3 size <integer_cst 0x4018d3f0 constant invariant 32> unit size <integer_cst 0x4018d180 constant invariant 4> align 32 context <function_decl 0x40231e00 foo> initial <integer_cst 0x4018da08 1>> arg 1 <integer_cst 0x4018d9f0 constant invariant 0>> arg 1 <throw_expr 0x4020f3a0 type <void_type 0x4019f8a0 void VOID align 8 symtab 0 alias set -1 pointer_to_this <pointer_type 0x4019f8fc>> side-effects arg 0 <call_expr 0x4019b0f0 type <void_type 0x4019f8a0 void> side-effects arg 0 <addr_expr 0x4020f380 type <pointer_type 0x402328fc> constant invariant arg 0 <function_decl 0x40231e80 __cxa_rethrow>>>> arg 2 <integer_cst 0x4018d618 type <boolean_type 0x4019f4ac bool> constant invariant 1>> it pretends to have boolean_type, but the first operand is of void_type! I don't think we want to "fix" invert_truthvalue here, but rather the C++ frontend generating this crap tree node.
Of course we _can_ fix this in the middle-end, simply by allowing COND_EXPRs that satisfy the needs of C++ /* [expr.cond] One of the following shall hold: --The second or the third operand (but not both) is a throw-expression (_except.throw_); the result is of the type of the other and is an rvalue. --Both the second and the third operands have type void; the result is of type void and is an rvalue. We must avoid calling force_rvalue for expressions of type "void" because it will complain that their value is being used. */ but I expect more fallout than only in invert_truthvalue. Maybe the C++ frontend can emit something like !(value?true:(throw,bool())) in these cases. CC'ing Mark.
Like so: Index: cp/call.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v retrieving revision 1.560 diff -c -3 -p -r1.560 call.c *** cp/call.c 18 Oct 2005 05:56:04 -0000 1.560 --- cp/call.c 19 Oct 2005 10:02:58 -0000 *************** build_conditional_expr (tree arg1, tree *** 3226,3231 **** --- 3226,3233 ---- arg3 = force_rvalue (arg3); arg3_type = TREE_TYPE (arg3); result_type = arg3_type; + arg2 = build_compound_expr (arg2, build_int_cst (result_type, 0)); + arg2_type = result_type; } else if (TREE_CODE (arg2) != THROW_EXPR && TREE_CODE (arg3) == THROW_EXPR) *************** build_conditional_expr (tree arg1, tree *** 3234,3239 **** --- 3236,3243 ---- arg2 = force_rvalue (arg2); arg2_type = TREE_TYPE (arg2); result_type = arg2_type; + arg3 = build_compound_expr (arg3, build_int_cst (result_type, 0)); + arg3_type = result_type; } else if (VOID_TYPE_P (arg2_type) && VOID_TYPE_P (arg3_type)) result_type = void_type_node; s/build_int_cst/create_default_constructed_temporary_target_expr/ whatever that will be. At least we don't ICE even for struct Foo { bool operator!=(int) { return true; } bool operator!() { return false; }}; void foo(void) { int value=1; !(value?Foo():throw); } but we create funny integer constants with type Foo, which is bad.
If you don't want to fix this in the middle-end, the right way to handle this is in the C++ gimplifier. At that point, create a COMPOUND_EXPR whose second argument is "*((T*) 0)" for non-pointer types, or just "((T *) 0)" for pointer/reference types.
Unfortunately we call into the middle-ends invert_truthvalue right in cp/typeck.c:build_unary_op as we build the TRUTH_NOT_EXPR, so at the time we reach the gimplifier we already crashed. So the other solution is to not use the middle-ends invert_truthvalue here, but unconditionally build a TRUTH_NOT_EXPR. And then fix it at gimplification time. But the solution with (T*)0 or *(T*)0 sounds nice ;)
Subject: Re: [3.4/4.0/4.1 Regression] ICE with invert conditional containing throw rguenth at gcc dot gnu dot org wrote: > ------- Comment #6 from rguenth at gcc dot gnu dot org 2005-10-19 20:40 ------- > Unfortunately we call into the middle-ends invert_truthvalue right in > cp/typeck.c:build_unary_op as we build the TRUTH_NOT_EXPR, so at the time we > reach the gimplifier we already crashed. In that case, I think we should fix the middle end to handle this case; it's not a very major change to the semantics of GIMPLE/GENERIC to handle this case. (I'm assuming that aren't massive ripple effects throughout the middle-end...) In the longer term, the solution of just creating a TRUTH_NOT_EXPR in the C++ front end might be the right one; all this folding-on-the-fly stuff is a mistake. But, it's too risky to try to do that now. And, changing the type of the operands to the COND_EXPR in the C++ front-end before gimplification is just wrong; the language says those operands have void type.
Subject: Re: [3.4/4.0/4.1 Regression] ICE with invert conditional containing throw On Oct 19, 2005, at 4:50 PM, mark at codesourcery dot com wrote: > > > ------- Comment #7 from mark at codesourcery dot com 2005-10-19 20:50 > ------- > Subject: Re: [3.4/4.0/4.1 Regression] ICE with invert conditional > containing throw > > rguenth at gcc dot gnu dot org wrote: >> ------- Comment #6 from rguenth at gcc dot gnu dot org 2005-10-19 >> 20:40 ------- >> Unfortunately we call into the middle-ends invert_truthvalue right in >> cp/typeck.c:build_unary_op as we build the TRUTH_NOT_EXPR, so at the >> time we >> reach the gimplifier we already crashed. > > In that case, I think we should fix the middle end to handle this case; > it's not a very major change to the semantics of GIMPLE/GENERIC to > handle this case. (I'm assuming that aren't massive ripple effects > throughout the middle-end...) Mark did you look how long this bug as been here, it predates tree-ssa by a year. So I don't think we should change TRUTH_NOT_EXPR/COND_EXPR semantics. The C++ front-end needs just stop doing bad stuff like this. -- Pinski
Subject: Re: [3.4/4.0/4.1 Regression] ICE with invert conditional containing throw > Mark did you look how long this bug as been here, it predates tree-ssa > by a year. So I don't think we should change TRUTH_NOT_EXPR/COND_EXPR > semantics. The C++ front-end needs just stop doing bad stuff like this. I don't consider this to be a bad representation; I consider it a perfectly reasonable expression of the program.
Ok, I'll see how big the middle-end change would get. The easiest way would be to change invert_truthvalue to ignore void types and do nothing for them. Like + if (VOID_TYPE_P (TREE_TYPE (arg))) + return arg; gcc_assert (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE); return build1 (TRUTH_NOT_EXPR, type, arg); but auditing all other places we look at COND_EXPR is a big task.
Subject: Re: [3.4/4.0/4.1 Regression] ICE with invert conditional containing throw rguenth at gcc dot gnu dot org wrote: > ------- Comment #10 from rguenth at gcc dot gnu dot org 2005-10-19 21:51 ------- > Ok, I'll see how big the middle-end change would get. The easiest way would > be to change invert_truthvalue to ignore void types and do nothing for them. > Like > > + if (VOID_TYPE_P (TREE_TYPE (arg))) > + return arg; > gcc_assert (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE); > return build1 (TRUTH_NOT_EXPR, type, arg); > > but auditing all other places we look at COND_EXPR is a big task. Yes, that looks like the right change to invert_truthvalue, or you could even bury that in the COND_EXPR case, since that's the only place we expect that. To be clear, I have no problem whatsoever with adding the *((T*) 0) stuff during gimplification, and that will protect all the optimizers from this case. But, invert_truthvalue has to operate on more than just GENERIC/GIMPLE; it's designed to be called from the front ends, so it has to be tolerant of front-end stuff.
Subject: Bug 24439 CVSROOT: /cvs/gcc Module name: gcc Changes by: rguenth@gcc.gnu.org 2005-10-20 15:19:03 Modified files: gcc : ChangeLog fold-const.c gcc/testsuite : ChangeLog Added files: gcc/testsuite/g++.dg/tree-ssa: pr24439.C Log message: 2005-10-20 Richard Guenther <rguenther@suse.de> PR c++/24439 * fold-const.c (invert_truthvalue): Handle COND_EXPR with void type operands. * g++.dg/tree-ssa/pr24439.C: New testcase. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/ChangeLog.diff?cvsroot=gcc&r1=2.10192&r2=2.10193 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/fold-const.c.diff?cvsroot=gcc&r1=1.628&r2=1.629 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.6217&r2=1.6218 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/tree-ssa/pr24439.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
Fixed in mainline.
This is not really a regression, since evn with 2.95.3 we get an ICE (with --enable-checking): bug.cc: In function `int main()': bug.cc:4: converting to `void' from `int' bug.cc:4: void value not ignored as it ought to be bug.cc:4: ../../gcc-2.95.3/gcc/fold-const.c:2095: Expect 't', have 'error_mark' The last line is in fact an ICE. So 2.95.3 wrongly reports an error and ICE's afterwards. Since we don't have a regression, I'm closing the PR.