Bug 24439 - ICE with invert conditional containing throw
Summary: ICE with invert conditional containing throw
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.1.0
: P2 normal
Target Milestone: 4.1.0
Assignee: Not yet assigned to anyone
URL: http://gcc.gnu.org/ml/gcc-patches/200...
Keywords: ice-on-valid-code, patch
Depends on:
Blocks:
 
Reported: 2005-10-18 23:01 UTC by Danny Smith
Modified: 2005-11-17 11:24 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 4.1.0
Known to fail: 3.0.4 3.2.3 3.3.3 3.4.0 4.0.0
Last reconfirmed: 2005-10-18 23:07:09


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Danny Smith 2005-10-18 23:01:40 UTC
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
Comment 1 Andrew Pinski 2005-10-18 23:07:09 UTC
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.
Comment 2 Richard Biener 2005-10-19 09:45:22 UTC
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.

Comment 3 Richard Biener 2005-10-19 09:52:58 UTC
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.
Comment 4 Richard Biener 2005-10-19 10:06:06 UTC
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.
Comment 5 Mark Mitchell 2005-10-19 20:11:55 UTC
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.
Comment 6 Richard Biener 2005-10-19 20:40:38 UTC
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 ;)
Comment 7 Mark Mitchell 2005-10-19 20:50:27 UTC
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.

Comment 8 Andrew Pinski 2005-10-19 20:55:28 UTC
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

Comment 9 Mark Mitchell 2005-10-19 20:58:30 UTC
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.

Comment 10 Richard Biener 2005-10-19 21:51:14 UTC
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.
Comment 11 Mark Mitchell 2005-10-19 22:14:50 UTC
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.

Comment 12 GCC Commits 2005-10-20 15:19:08 UTC
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

Comment 13 Richard Biener 2005-10-20 15:45:27 UTC
Fixed in mainline.
Comment 14 Volker Reichelt 2005-11-17 11:24:25 UTC
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.