[PATCH] PR middle-end/20539: More tree type safety issues

Roger Sayle roger@eyesopen.com
Sun Mar 20 06:05:00 GMT 2005


The following patch is my proposed solution to PR middle-end/20539
which is an ICE on valid regression on both mainline and the 4.0
branch.  Unfortunately, the fix required a change to the C front-end,
so I'm posting (the c-common.c bits of the) the patch for approval.


Ahh, what a tangled web...  It turns out that PR middle-end/13066
was actually a C/C++ front-end issue, related to my clean-ups for
PR middle-end/19100, but the erroneous fix for PR13066 inadvertantly
introduced PR20539.  [I won't even mention PR tree-optimization/17512]

This issue is the type safety of the TRUTH_x_EXPR operators, were x
is one of ANDIF, ORIF, AND, OR or XOR.  As documented in c-tree.texi
these tree nodes can be either of integer type *or* of Boolean type.
The problem is that not all of the places that handle these nodes
are prepared to handle the non-Boolean cases.

I'd considered limiting these tree codes to be BOOLEAN_TYPE only,
but the C/C++ parser clearly create these nodes with integer types
following the standard promotion rules.  Hence, we have to fix the
places that incorrectly assume unconditional Boolean-ness.

The major offender is the C/C++ front-end's truthvalue_conversion
langhook, which when asked to convert a tree to boolean_type_node,
simply changes the top-level node without adjusting the types of
it's operands.  This ends up creating the invalid trees which then
caused PR13066, which is an ICE in invert_truthvalue, which itself
assumes that if the top-level tree node has BOOLEAN_TYPE, then it's
operands must also have BOOLEAN_TYPE.

To unintentionally work-around this problem (on the tree-ssa branch),
Andrew Pinki's solution was to tweak fold the other way, creating
invalid TRUTH_x_EXPR nodes, with integer result type, but with Boolean
type operands.  This prevented the invert truthvalue abort, but alas
introduced PR20539.  By not ensuring the result type of these tree
codes match their operand types, we managed to create trees with
Boolean QImode operands returning a DImode result.  Ultimately, we
reach RTL expansion, and expr.c leads to an ICE trying to use
and_optab/ior_optab to directly implement TRUTH_AND_EXPR/TRUTH_OR_EXPR
where the modes are fatally mismatched.


The following patch attempts to address these problems by always
ensuring that the operands of TRUTH_x_EXPR have types that match
the result type.  My apologies to Andrew for not spotting the
type mismatch when I approved his solution to PR13066.  I've also
taken the liberty of adding the two testcases attached to PR13066's
bugzilla PR to the testsuite, to confirm that this fix doesn't
regress the original problem.


The following patch has been tested on i686-pc-linux-gnu with a
full "make bootstrap" and regression tested with a top-level
"make -k check" with no new failures.

Ok for mainline and the 4.0 branch?



2005-03-19  Roger Sayle  <roger@eyesopen.com>

	PR middle-end/20539
	* fold-const.c (fold_binary): Fix type mismatch between
	TRUTH_{AND,OR,XOR}_EXPR nodes and their operands' types.
	(fold_binary) <TRUTH_XOR_EXPR>: Avoid calling invert_truthvalue
	for non-truth-valued expressions.

	* c-common.c (c_common_truthvalue_conversion): Handle ERROR_MARK
	and FUNCTION_DECL in the main switch.
	<TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR, TRUTH_AND_EXPR, TRUTH_OR_EXPR,
	TRUTH_XOR_EXPR>: When changing the result type of these tree nodes,
	we also need to convert their operands to match.
	<TRUTH_NOT_EXPR>: Likewise.

	* gcc.c-torture/compile/pr13066-1.c: New test case.
	* gcc.c-torture/compile/pr20539-1.c: Likewise.
	* g++.dg/opt/pr13066-1.C: Likewise.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.542
diff -c -3 -p -r1.542 fold-const.c
*** fold-const.c	13 Mar 2005 22:34:03 -0000	1.542
--- fold-const.c	19 Mar 2005 23:07:16 -0000
*************** fold_binary (enum tree_code code, tree t
*** 7141,7153 ****
        tem = fold (build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
  			  : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
  			  : TRUTH_XOR_EXPR,
! 			  type, fold_convert (boolean_type_node, arg0),
  			  fold_convert (boolean_type_node, arg1)));

        if (code == EQ_EXPR)
  	tem = invert_truthvalue (tem);

!       return tem;
      }

    if (TREE_CODE_CLASS (code) == tcc_comparison
--- 7141,7154 ----
        tem = fold (build2 (code == BIT_AND_EXPR ? TRUTH_AND_EXPR
  			  : code == BIT_IOR_EXPR ? TRUTH_OR_EXPR
  			  : TRUTH_XOR_EXPR,
! 			  boolean_type_node,
! 			  fold_convert (boolean_type_node, arg0),
  			  fold_convert (boolean_type_node, arg1)));

        if (code == EQ_EXPR)
  	tem = invert_truthvalue (tem);

!       return fold_convert (type, tem);
      }

    if (TREE_CODE_CLASS (code) == tcc_comparison
*************** fold_binary (enum tree_code code, tree t
*** 8699,8705 ****
  	return non_lvalue (fold_convert (type, arg0));
        /* If the second arg is constant true, this is a logical inversion.  */
        if (integer_onep (arg1))
! 	return non_lvalue (fold_convert (type, invert_truthvalue (arg0)));
        /* Identical arguments cancel to zero.  */
        if (operand_equal_p (arg0, arg1, 0))
  	return omit_one_operand (type, integer_zero_node, arg0);
--- 8700,8713 ----
  	return non_lvalue (fold_convert (type, arg0));
        /* If the second arg is constant true, this is a logical inversion.  */
        if (integer_onep (arg1))
! 	{
! 	  /* Only call invert_truthvalue if operand is a truth value.  */
! 	  if (TREE_CODE (TREE_TYPE (arg0)) != BOOLEAN_TYPE)
! 	    tem = fold (build1 (TRUTH_NOT_EXPR, TREE_TYPE (arg0), arg0));
! 	  else
! 	    tem = invert_truthvalue (arg0);
! 	  return non_lvalue (fold_convert (type, tem));
! 	}
        /* Identical arguments cancel to zero.  */
        if (operand_equal_p (arg0, arg1, 0))
  	return omit_one_operand (type, integer_zero_node, arg0);

Index: c-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.c,v
retrieving revision 1.610
diff -c -3 -p -r1.610 c-common.c
*** c-common.c	14 Mar 2005 16:21:03 -0000	1.610
--- c-common.c	19 Mar 2005 16:37:20 -0000
*************** pointer_int_sum (enum tree_code resultco
*** 2327,2359 ****
  tree
  c_common_truthvalue_conversion (tree expr)
  {
-   if (TREE_CODE (expr) == ERROR_MARK)
-     return expr;
-
-   if (TREE_CODE (expr) == FUNCTION_DECL)
-     expr = build_unary_op (ADDR_EXPR, expr, 0);
-
    switch (TREE_CODE (expr))
      {
      case EQ_EXPR:   case NE_EXPR:   case UNEQ_EXPR: case LTGT_EXPR:
      case LE_EXPR:   case GE_EXPR:   case LT_EXPR:   case GT_EXPR:
      case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
      case ORDERED_EXPR: case UNORDERED_EXPR:
      case TRUTH_ANDIF_EXPR:
      case TRUTH_ORIF_EXPR:
      case TRUTH_AND_EXPR:
      case TRUTH_OR_EXPR:
      case TRUTH_XOR_EXPR:
!       if (TREE_TYPE (expr) != truthvalue_type_node)
! 	return build2 (TREE_CODE (expr), truthvalue_type_node,
! 		       TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
!       return expr;

      case TRUTH_NOT_EXPR:
!       if (TREE_TYPE (expr) != truthvalue_type_node)
! 	return build1 (TREE_CODE (expr), truthvalue_type_node,
! 		       TREE_OPERAND (expr, 0));
!       return expr;

      case ERROR_MARK:
        return expr;
--- 2327,2359 ----
  tree
  c_common_truthvalue_conversion (tree expr)
  {
    switch (TREE_CODE (expr))
      {
      case EQ_EXPR:   case NE_EXPR:   case UNEQ_EXPR: case LTGT_EXPR:
      case LE_EXPR:   case GE_EXPR:   case LT_EXPR:   case GT_EXPR:
      case UNLE_EXPR: case UNGE_EXPR: case UNLT_EXPR: case UNGT_EXPR:
      case ORDERED_EXPR: case UNORDERED_EXPR:
+       if (TREE_TYPE (expr) == truthvalue_type_node)
+ 	return expr;
+       return build2 (TREE_CODE (expr), truthvalue_type_node,
+ 		     TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+
      case TRUTH_ANDIF_EXPR:
      case TRUTH_ORIF_EXPR:
      case TRUTH_AND_EXPR:
      case TRUTH_OR_EXPR:
      case TRUTH_XOR_EXPR:
!       if (TREE_TYPE (expr) == truthvalue_type_node)
! 	return expr;
!       return build2 (TREE_CODE (expr), truthvalue_type_node,
! 		 lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0)),
! 		 lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 1)));

      case TRUTH_NOT_EXPR:
!       if (TREE_TYPE (expr) == truthvalue_type_node)
! 	return expr;
!       return build1 (TREE_CODE (expr), truthvalue_type_node,
! 		 lang_hooks.truthvalue_conversion (TREE_OPERAND (expr, 0)));

      case ERROR_MARK:
        return expr;
*************** c_common_truthvalue_conversion (tree exp
*** 2369,2374 ****
--- 2369,2378 ----
  	     ? truthvalue_true_node
  	     : truthvalue_false_node;

+     case FUNCTION_DECL:
+       expr = build_unary_op (ADDR_EXPR, expr, 0);
+       /* Fall through.  */
+
      case ADDR_EXPR:
        {
  	if (TREE_CODE (TREE_OPERAND (expr, 0)) == FUNCTION_DECL


char l7_en;
long long l6_data_Z_0th;
int t;
void f()
{
  if (((char )(l6_data_Z_0th>>1 & 1U)) & ((l6_data_Z_0th & 1U)
     | !(((char )(l6_data_Z_0th>>35 & 15U))==14U)))
    t = 0ULL;
}


/* { dg-do compile } */
/* { dg-options "-O2" } */

class nsIURI;

struct nsCOMPtr
{
  operator nsIURI*() const
  {
    return mRawPtr;
  }

  nsIURI *mRawPtr;
};

void func()
{
  nsCOMPtr u1;
  if (!u1 == !u1)
    return;
}


void *g, *c;
int a, b;

int f()
{
  if ((0 == a) != (b || g == c))
    return 1;
  return 0;
}


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833



More information about the Gcc-patches mailing list