C++ PATCH: PR 17642

Mark Mitchell mark@codesourcery.com
Tue Sep 28 07:17:00 GMT 2004


The increased checking in fold caused aborts when presented with the
trees that G++ builds up during template processing.  There is
actually no need to call fold during template processing; we only need
to know the *types* of expressions.  In fact, we build too many nodes
already; we could be more clever about just computing the type.

(Nathan and I actually think that we shouldn't be calling fold in the
front-end at all, except to resolve integral constant expressions.
All other uses of fold should be eliminated.  The gimplifier can call
fold as necessary while gimplifying.  This would make the front end
simpler (nobody is quite sure when exactly you have to call fold) and
faster (we call fold for expressions that we never use at present).)

Because I've now prevented G++ from calling fold in templates, we have
to also work harder to prevent the back end from calling "convert"
because the back end is expecting that to do various kinds of folding.
The solution is to use fold_convert; as previously discussed, all uses
of convert in the middle-end are inaccurate at best and bugs at worst.

It's possible that the remaining calls to "convert" in the middle-end
will trip us up, and it's possible that we need to use
fold_if_not_in_template in more places in G++; in other words, this
may be one of Zack's "incomplete transitions".  However, making this
patch even more invasive at this point seems like a bad idea.

Bootstrapped and tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-09-27  Mark Mitchell  <mark@codesourcery.com>

	PR c++/17642
	* stor-layout.c (layout_decl): Use fold_convert, not convert.
	(bit_from_pos): Likewise.
	(byte_from_pos): Likewise.
	(pos_from_bit): Likewise.
	(normalize_offset): Likewise.
	(place_field): Likewise.
	(finalize_type_size): Likewise.
	(layout_type): Likewise.
	* tree.c (build_index_type): Likewise.

2004-09-27  Mark Mitchell  <mark@codesourcery.com>

	PR c++/17642
	* cp-tree.h (fold_if_not_in_template): New function.
	* call.c (build_conditional_expr): Use fold_if_not_in_template.
	(build_cxx_call): Likewise.
	* cvt.c (convert_to_complex): Likewise.
	(ocp_convert): Likewise.
	(convert): Likewise.
	(convert_force): Likewise.
	* decl.c (compute_array_index_type): Clear
	processing_template_decl while folding array bounds.
	* pt.c (convert_nontype_argument): Clear
	processing_template_decl while processing non-type argument
	initialization.
	* tree.c (fold_if_not_in_template): New function.
	* typeck.c (build_class_member_access_expr): Use
	fold_if_not_in_template.
	(build_array_ref): Likewise.
	(build_binary_op): Likewise.  Do not try to optimize computations
	when processing templates.
	(cp_pointer_int_sum): Use fold_if_not_in_template.
	(pointer_diff): Likewise.
	(build_unary_op): Likewise.
	(build_reinterpret_cast): Likewise.
	(get_delta_difference): Likewise.
	(expand_ptrmemfunc_cst): Likewise.
	(dubious_conversion_warnings): Likewise.

2004-09-27  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/template/crash23.C: New test.

Index: stor-layout.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/stor-layout.c,v
retrieving revision 1.214
diff -c -5 -p -r1.214 stor-layout.c
*** stor-layout.c	26 Sep 2004 14:58:33 -0000	1.214
--- stor-layout.c	28 Sep 2004 02:29:16 -0000
*************** layout_decl (tree decl, unsigned int kno
*** 328,339 ****
        DECL_SIZE (decl) = TYPE_SIZE (type);
        DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (type);
      }
    else if (DECL_SIZE_UNIT (decl) == 0)
      DECL_SIZE_UNIT (decl)
!       = convert (sizetype, size_binop (CEIL_DIV_EXPR, DECL_SIZE (decl),
! 				       bitsize_unit_node));
  
    if (code != FIELD_DECL)
      /* For non-fields, update the alignment from the type.  */
      do_type_align (type, decl);
    else
--- 328,339 ----
        DECL_SIZE (decl) = TYPE_SIZE (type);
        DECL_SIZE_UNIT (decl) = TYPE_SIZE_UNIT (type);
      }
    else if (DECL_SIZE_UNIT (decl) == 0)
      DECL_SIZE_UNIT (decl)
!       = fold_convert (sizetype, size_binop (CEIL_DIV_EXPR, DECL_SIZE (decl),
! 					    bitsize_unit_node));
  
    if (code != FIELD_DECL)
      /* For non-fields, update the alignment from the type.  */
      do_type_align (type, decl);
    else
*************** start_record_layout (tree t)
*** 538,568 ****
  
  tree
  bit_from_pos (tree offset, tree bitpos)
  {
    return size_binop (PLUS_EXPR, bitpos,
! 		     size_binop (MULT_EXPR, convert (bitsizetype, offset),
  				 bitsize_unit_node));
  }
  
  tree
  byte_from_pos (tree offset, tree bitpos)
  {
    return size_binop (PLUS_EXPR, offset,
! 		     convert (sizetype,
! 			      size_binop (TRUNC_DIV_EXPR, bitpos,
! 					  bitsize_unit_node)));
  }
  
  void
  pos_from_bit (tree *poffset, tree *pbitpos, unsigned int off_align,
  	      tree pos)
  {
    *poffset = size_binop (MULT_EXPR,
! 			 convert (sizetype,
! 				  size_binop (FLOOR_DIV_EXPR, pos,
! 					      bitsize_int (off_align))),
  			 size_int (off_align / BITS_PER_UNIT));
    *pbitpos = size_binop (FLOOR_MOD_EXPR, pos, bitsize_int (off_align));
  }
  
  /* Given a pointer to bit and byte offsets and an offset alignment,
--- 538,569 ----
  
  tree
  bit_from_pos (tree offset, tree bitpos)
  {
    return size_binop (PLUS_EXPR, bitpos,
! 		     size_binop (MULT_EXPR, 
! 				 fold_convert (bitsizetype, offset),
  				 bitsize_unit_node));
  }
  
  tree
  byte_from_pos (tree offset, tree bitpos)
  {
    return size_binop (PLUS_EXPR, offset,
! 		     fold_convert (sizetype,
! 				   size_binop (TRUNC_DIV_EXPR, bitpos,
! 					       bitsize_unit_node)));
  }
  
  void
  pos_from_bit (tree *poffset, tree *pbitpos, unsigned int off_align,
  	      tree pos)
  {
    *poffset = size_binop (MULT_EXPR,
! 			 fold_convert (sizetype,
! 				       size_binop (FLOOR_DIV_EXPR, pos,
! 						   bitsize_int (off_align))),
  			 size_int (off_align / BITS_PER_UNIT));
    *pbitpos = size_binop (FLOOR_MOD_EXPR, pos, bitsize_int (off_align));
  }
  
  /* Given a pointer to bit and byte offsets and an offset alignment,
*************** normalize_offset (tree *poffset, tree *p
*** 578,588 ****
        tree extra_aligns = size_binop (FLOOR_DIV_EXPR, *pbitpos,
  				      bitsize_int (off_align));
  
        *poffset
  	= size_binop (PLUS_EXPR, *poffset,
! 		      size_binop (MULT_EXPR, convert (sizetype, extra_aligns),
  				  size_int (off_align / BITS_PER_UNIT)));
  
        *pbitpos
  	= size_binop (FLOOR_MOD_EXPR, *pbitpos, bitsize_int (off_align));
      }
--- 579,590 ----
        tree extra_aligns = size_binop (FLOOR_DIV_EXPR, *pbitpos,
  				      bitsize_int (off_align));
  
        *poffset
  	= size_binop (PLUS_EXPR, *poffset,
! 		      size_binop (MULT_EXPR, 
! 				  fold_convert (sizetype, extra_aligns),
  				  size_int (off_align / BITS_PER_UNIT)));
  
        *pbitpos
  	= size_binop (FLOOR_MOD_EXPR, *pbitpos, bitsize_int (off_align));
      }
*************** place_field (record_layout_info rli, tre
*** 867,879 ****
        else
  	{
  	  /* First adjust OFFSET by the partial bits, then align.  */
  	  rli->offset
  	    = size_binop (PLUS_EXPR, rli->offset,
! 			  convert (sizetype,
! 				   size_binop (CEIL_DIV_EXPR, rli->bitpos,
! 					       bitsize_unit_node)));
  	  rli->bitpos = bitsize_zero_node;
  
  	  rli->offset = round_up (rli->offset, desired_align / BITS_PER_UNIT);
  	}
  
--- 869,881 ----
        else
  	{
  	  /* First adjust OFFSET by the partial bits, then align.  */
  	  rli->offset
  	    = size_binop (PLUS_EXPR, rli->offset,
! 			  fold_convert (sizetype,
! 					size_binop (CEIL_DIV_EXPR, rli->bitpos,
! 						    bitsize_unit_node)));
  	  rli->bitpos = bitsize_zero_node;
  
  	  rli->offset = round_up (rli->offset, desired_align / BITS_PER_UNIT);
  	}
  
*************** place_field (record_layout_info rli, tre
*** 1145,1157 ****
    else if (TREE_CODE (DECL_SIZE_UNIT (field)) != INTEGER_CST
  	   || TREE_CONSTANT_OVERFLOW (DECL_SIZE_UNIT (field)))
      {
        rli->offset
  	= size_binop (PLUS_EXPR, rli->offset,
! 		      convert (sizetype,
! 			       size_binop (CEIL_DIV_EXPR, rli->bitpos,
! 					   bitsize_unit_node)));
        rli->offset
  	= size_binop (PLUS_EXPR, rli->offset, DECL_SIZE_UNIT (field));
        rli->bitpos = bitsize_zero_node;
        rli->offset_align = MIN (rli->offset_align, desired_align);
      }
--- 1147,1159 ----
    else if (TREE_CODE (DECL_SIZE_UNIT (field)) != INTEGER_CST
  	   || TREE_CONSTANT_OVERFLOW (DECL_SIZE_UNIT (field)))
      {
        rli->offset
  	= size_binop (PLUS_EXPR, rli->offset,
! 		      fold_convert (sizetype,
! 				    size_binop (CEIL_DIV_EXPR, rli->bitpos,
! 						bitsize_unit_node)));
        rli->offset
  	= size_binop (PLUS_EXPR, rli->offset, DECL_SIZE_UNIT (field));
        rli->bitpos = bitsize_zero_node;
        rli->offset_align = MIN (rli->offset_align, desired_align);
      }
*************** finalize_type_size (tree type)
*** 1351,1363 ****
    if (TYPE_SIZE_UNIT (type) == 0 && TYPE_SIZE (type) != 0)
      /* TYPE_SIZE (type) is computed in bitsizetype.  After the division, the
         result will fit in sizetype.  We will get more efficient code using
         sizetype, so we force a conversion.  */
      TYPE_SIZE_UNIT (type)
!       = convert (sizetype,
! 		 size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (type),
! 			     bitsize_unit_node));
  
    if (TYPE_SIZE (type) != 0)
      {
        TYPE_SIZE (type) = round_up (TYPE_SIZE (type), TYPE_ALIGN (type));
        TYPE_SIZE_UNIT (type) = round_up (TYPE_SIZE_UNIT (type),
--- 1353,1365 ----
    if (TYPE_SIZE_UNIT (type) == 0 && TYPE_SIZE (type) != 0)
      /* TYPE_SIZE (type) is computed in bitsizetype.  After the division, the
         result will fit in sizetype.  We will get more efficient code using
         sizetype, so we force a conversion.  */
      TYPE_SIZE_UNIT (type)
!       = fold_convert (sizetype,
! 		      size_binop (FLOOR_DIV_EXPR, TYPE_SIZE (type),
! 				  bitsize_unit_node));
  
    if (TYPE_SIZE (type) != 0)
      {
        TYPE_SIZE (type) = round_up (TYPE_SIZE (type), TYPE_ALIGN (type));
        TYPE_SIZE_UNIT (type) = round_up (TYPE_SIZE_UNIT (type),
*************** layout_type (tree type)
*** 1636,1649 ****
  	    tree element_size;
  
  	    /* The initial subtraction should happen in the original type so
  	       that (possible) negative values are handled appropriately.  */
  	    length = size_binop (PLUS_EXPR, size_one_node,
! 				 convert (sizetype,
! 					  fold (build2 (MINUS_EXPR,
! 							TREE_TYPE (lb),
! 							ub, lb))));
  
  	    /* Special handling for arrays of bits (for Chill).  */
  	    element_size = TYPE_SIZE (element);
  	    if (TYPE_PACKED (type) && INTEGRAL_TYPE_P (element)
  		&& (integer_zerop (TYPE_MAX_VALUE (element))
--- 1638,1651 ----
  	    tree element_size;
  
  	    /* The initial subtraction should happen in the original type so
  	       that (possible) negative values are handled appropriately.  */
  	    length = size_binop (PLUS_EXPR, size_one_node,
! 				 fold_convert (sizetype,
! 					       fold (build2 (MINUS_EXPR,
! 							     TREE_TYPE (lb),
! 							     ub, lb))));
  
  	    /* Special handling for arrays of bits (for Chill).  */
  	    element_size = TYPE_SIZE (element);
  	    if (TYPE_PACKED (type) && INTEGRAL_TYPE_P (element)
  		&& (integer_zerop (TYPE_MAX_VALUE (element))
*************** layout_type (tree type)
*** 1668,1678 ****
  		&& TREE_CODE (TYPE_MIN_VALUE (index)) != INTEGER_CST
  		&& TREE_CODE (TYPE_MAX_VALUE (index)) != INTEGER_CST)
  	      length = size_binop (MAX_EXPR, length, size_zero_node);
  
  	    TYPE_SIZE (type) = size_binop (MULT_EXPR, element_size,
! 					   convert (bitsizetype, length));
  
  	    /* If we know the size of the element, calculate the total
  	       size directly, rather than do some division thing below.
  	       This optimization helps Fortran assumed-size arrays
  	       (where the size of the array is determined at runtime)
--- 1670,1681 ----
  		&& TREE_CODE (TYPE_MIN_VALUE (index)) != INTEGER_CST
  		&& TREE_CODE (TYPE_MAX_VALUE (index)) != INTEGER_CST)
  	      length = size_binop (MAX_EXPR, length, size_zero_node);
  
  	    TYPE_SIZE (type) = size_binop (MULT_EXPR, element_size,
! 					   fold_convert (bitsizetype, 
! 							 length));
  
  	    /* If we know the size of the element, calculate the total
  	       size directly, rather than do some division thing below.
  	       This optimization helps Fortran assumed-size arrays
  	       (where the size of the array is determined at runtime)
Index: tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.435
diff -c -5 -p -r1.435 tree.c
*** tree.c	23 Sep 2004 18:22:15 -0000	1.435
--- tree.c	28 Sep 2004 02:29:17 -0000
*************** build_index_type (tree maxval)
*** 4216,4226 ****
    tree itype = make_node (INTEGER_TYPE);
  
    TREE_TYPE (itype) = sizetype;
    TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
    TYPE_MIN_VALUE (itype) = size_zero_node;
!   TYPE_MAX_VALUE (itype) = convert (sizetype, maxval);
    TYPE_MODE (itype) = TYPE_MODE (sizetype);
    TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
    TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
    TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
    TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (sizetype);
--- 4216,4226 ----
    tree itype = make_node (INTEGER_TYPE);
  
    TREE_TYPE (itype) = sizetype;
    TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
    TYPE_MIN_VALUE (itype) = size_zero_node;
!   TYPE_MAX_VALUE (itype) = fold_convert (sizetype, maxval);
    TYPE_MODE (itype) = TYPE_MODE (sizetype);
    TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
    TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
    TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
    TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (sizetype);
Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.509
diff -c -5 -p -r1.509 call.c
*** cp/call.c	21 Sep 2004 15:38:49 -0000	1.509
--- cp/call.c	28 Sep 2004 02:29:18 -0000
*************** build_conditional_expr (tree arg1, tree 
*** 3440,3450 ****
        error ("operands to ?: have different types");
        return error_mark_node;
      }
  
   valid_operands:
!   result = fold (build3 (COND_EXPR, result_type, arg1, arg2, arg3));
    /* We can't use result_type below, as fold might have returned a
       throw_expr.  */
  
    /* Expand both sides into the same slot, hopefully the target of the
       ?: expression.  We used to check for TARGET_EXPRs here, but now we
--- 3440,3451 ----
        error ("operands to ?: have different types");
        return error_mark_node;
      }
  
   valid_operands:
!   result = fold_if_not_in_template (build3 (COND_EXPR, result_type, arg1, 
! 					    arg2, arg3));
    /* We can't use result_type below, as fold might have returned a
       throw_expr.  */
  
    /* Expand both sides into the same slot, hopefully the target of the
       ?: expression.  We used to check for TARGET_EXPRs here, but now we
*************** build_cxx_call (tree fn, tree args)
*** 4867,4877 ****
        && cfun)
      cp_function_chain->can_throw = 1;
  
    /* Some built-in function calls will be evaluated at compile-time in
       fold ().  */
!   fn = fold (fn);
  
    if (VOID_TYPE_P (TREE_TYPE (fn)))
      return fn;
  
    fn = require_complete_type (fn);
--- 4868,4878 ----
        && cfun)
      cp_function_chain->can_throw = 1;
  
    /* Some built-in function calls will be evaluated at compile-time in
       fold ().  */
!   fn = fold_if_not_in_template (fn);
  
    if (VOID_TYPE_P (TREE_TYPE (fn)))
      return fn;
  
    fn = require_complete_type (fn);
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1054
diff -c -5 -p -r1.1054 cp-tree.h
*** cp/cp-tree.h	27 Sep 2004 18:47:28 -0000	1.1054
--- cp/cp-tree.h	28 Sep 2004 02:29:18 -0000
*************** extern tree cp_walk_subtrees (tree*, int
*** 4205,4214 ****
--- 4205,4215 ----
  extern int cp_cannot_inline_tree_fn (tree*);
  extern tree cp_add_pending_fn_decls (void*,tree);
  extern int cp_is_overload_p (tree);
  extern int cp_auto_var_in_fn_p (tree,tree);
  extern void cp_update_decl_after_saving (tree, void *);
+ extern tree fold_if_not_in_template             (tree);
  
  /* in typeck.c */
  extern int string_conv_p			(tree, tree, int);
  extern tree cp_truthvalue_conversion		(tree);
  extern tree condition_conversion		(tree);
Index: cp/cvt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cvt.c,v
retrieving revision 1.166
diff -c -5 -p -r1.166 cvt.c
*** cp/cvt.c	23 Sep 2004 20:04:21 -0000	1.166
--- cp/cvt.c	28 Sep 2004 02:29:18 -0000
*************** ocp_convert (tree type, tree expr, int c
*** 641,651 ****
  	   convert, which will call ocp_convert, etc.  */
  	return e;
        /* For complex data types, we need to perform componentwise
           conversion.  */
        else if (TREE_CODE (type) == COMPLEX_TYPE)
!         return fold (convert_to_complex (type, e));
        else if (TREE_CODE (e) == TARGET_EXPR)
  	{
  	  /* Don't build a NOP_EXPR of class type.  Instead, change the
  	     type of the temporary.  Only allow this for cv-qual changes,
  	     though.  */
--- 641,651 ----
  	   convert, which will call ocp_convert, etc.  */
  	return e;
        /* For complex data types, we need to perform componentwise
           conversion.  */
        else if (TREE_CODE (type) == COMPLEX_TYPE)
!         return fold_if_not_in_template (convert_to_complex (type, e));
        else if (TREE_CODE (e) == TARGET_EXPR)
  	{
  	  /* Don't build a NOP_EXPR of class type.  Instead, change the
  	     type of the temporary.  Only allow this for cv-qual changes,
  	     though.  */
*************** ocp_convert (tree type, tree expr, int c
*** 657,667 ****
        else
  	{
  	  /* We shouldn't be treating objects of ADDRESSABLE type as
  	     rvalues.  */
  	  gcc_assert (!TREE_ADDRESSABLE (type));
! 	  return fold (build1 (NOP_EXPR, type, e));
  	}
      }
  
    if (code == VOID_TYPE && (convtype & CONV_STATIC))
      {
--- 657,667 ----
        else
  	{
  	  /* We shouldn't be treating objects of ADDRESSABLE type as
  	     rvalues.  */
  	  gcc_assert (!TREE_ADDRESSABLE (type));
! 	  return fold_if_not_in_template (build_nop (type, e));
  	}
      }
  
    if (code == VOID_TYPE && (convtype & CONV_STATIC))
      {
*************** ocp_convert (tree type, tree expr, int c
*** 694,707 ****
  	  return error_mark_node;
  	}
        if (code == BOOLEAN_TYPE)
  	return cp_truthvalue_conversion (e);
  
!       return fold (convert_to_integer (type, e));
      }
    if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
!     return fold (cp_convert_to_pointer (type, e, false));
    if (code == VECTOR_TYPE)
      {
        tree in_vtype = TREE_TYPE (e);
        if (IS_AGGR_TYPE (in_vtype))
  	{
--- 694,707 ----
  	  return error_mark_node;
  	}
        if (code == BOOLEAN_TYPE)
  	return cp_truthvalue_conversion (e);
  
!       return fold_if_not_in_template (convert_to_integer (type, e));
      }
    if (POINTER_TYPE_P (type) || TYPE_PTR_TO_MEMBER_P (type))
!     return fold_if_not_in_template (cp_convert_to_pointer (type, e, false));
    if (code == VECTOR_TYPE)
      {
        tree in_vtype = TREE_TYPE (e);
        if (IS_AGGR_TYPE (in_vtype))
  	{
*************** ocp_convert (tree type, tree expr, int c
*** 711,721 ****
              return ret_val;
            if (flags & LOOKUP_COMPLAIN)
              error ("`%#T' used where a `%T' was expected", in_vtype, type);
            return error_mark_node;
  	}
!       return fold (convert_to_vector (type, e));
      }
    if (code == REAL_TYPE || code == COMPLEX_TYPE)
      {
        if (IS_AGGR_TYPE (TREE_TYPE (e)))
  	{
--- 711,721 ----
              return ret_val;
            if (flags & LOOKUP_COMPLAIN)
              error ("`%#T' used where a `%T' was expected", in_vtype, type);
            return error_mark_node;
  	}
!       return fold_if_not_in_template (convert_to_vector (type, e));
      }
    if (code == REAL_TYPE || code == COMPLEX_TYPE)
      {
        if (IS_AGGR_TYPE (TREE_TYPE (e)))
  	{
*************** ocp_convert (tree type, tree expr, int c
*** 727,739 ****
  	    if (flags & LOOKUP_COMPLAIN)
  	      error ("`%#T' used where a floating point value was expected",
  			TREE_TYPE (e));
  	}
        if (code == REAL_TYPE)
! 	return fold (convert_to_real (type, e));
        else if (code == COMPLEX_TYPE)
! 	return fold (convert_to_complex (type, e));
      }
  
    /* New C++ semantics:  since assignment is now based on
       memberwise copying,  if the rhs type is derived from the
       lhs type, then we may still do a conversion.  */
--- 727,739 ----
  	    if (flags & LOOKUP_COMPLAIN)
  	      error ("`%#T' used where a floating point value was expected",
  			TREE_TYPE (e));
  	}
        if (code == REAL_TYPE)
! 	return fold_if_not_in_template (convert_to_real (type, e));
        else if (code == COMPLEX_TYPE)
! 	return fold_if_not_in_template (convert_to_complex (type, e));
      }
  
    /* New C++ semantics:  since assignment is now based on
       memberwise copying,  if the rhs type is derived from the
       lhs type, then we may still do a conversion.  */
*************** convert (tree type, tree expr)
*** 943,953 ****
    intype = TREE_TYPE (expr);
  
    if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
      {
        expr = decl_constant_value (expr);
!       return fold (build1 (NOP_EXPR, type, expr));
      }
  
    return ocp_convert (type, expr, CONV_OLD_CONVERT,
  		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
  }
--- 943,953 ----
    intype = TREE_TYPE (expr);
  
    if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
      {
        expr = decl_constant_value (expr);
!       return fold_if_not_in_template (build_nop (type, expr));
      }
  
    return ocp_convert (type, expr, CONV_OLD_CONVERT,
  		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
  }
*************** convert_force (tree type, tree expr, int
*** 961,977 ****
  {
    tree e = expr;
    enum tree_code code = TREE_CODE (type);
  
    if (code == REFERENCE_TYPE)
!     return fold (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_COMPLAIN,
! 				       NULL_TREE));
    else if (TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
      e = convert_from_reference (e);
  
    if (code == POINTER_TYPE)
!     return fold (convert_to_pointer_force (type, e));
  
    /* From typeck.c convert_for_assignment */
    if (((TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE && TREE_CODE (e) == ADDR_EXPR
  	&& TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
  	&& TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE)
--- 961,978 ----
  {
    tree e = expr;
    enum tree_code code = TREE_CODE (type);
  
    if (code == REFERENCE_TYPE)
!     return (fold_if_not_in_template 
! 	    (convert_to_reference (type, e, CONV_C_CAST, LOOKUP_COMPLAIN,
! 				   NULL_TREE)));
    else if (TREE_CODE (TREE_TYPE (e)) == REFERENCE_TYPE)
      e = convert_from_reference (e);
  
    if (code == POINTER_TYPE)
!     return fold_if_not_in_template (convert_to_pointer_force (type, e));
  
    /* From typeck.c convert_for_assignment */
    if (((TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE && TREE_CODE (e) == ADDR_EXPR
  	&& TREE_CODE (TREE_TYPE (e)) == POINTER_TYPE
  	&& TREE_CODE (TREE_TYPE (TREE_TYPE (e))) == METHOD_TYPE)
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1305
diff -c -5 -p -r1.1305 decl.c
*** cp/decl.c	23 Sep 2004 21:27:08 -0000	1.1305
--- cp/decl.c	28 Sep 2004 02:29:18 -0000
*************** compute_array_index_type (tree name, tre
*** 6194,6209 ****
    if (processing_template_decl && !TREE_CONSTANT (size))
      /* A variable sized array.  */
      itype = build_min (MINUS_EXPR, sizetype, size, integer_one_node);
    else
      {
        /* Compute the index of the largest element in the array.  It is
!      	 one less than the number of elements in the array.  */
!       itype
! 	= fold (cp_build_binary_op (MINUS_EXPR,
! 				    cp_convert (ssizetype, size),
! 				    cp_convert (ssizetype, integer_one_node)));
        if (!TREE_CONSTANT (itype))
  	/* A variable sized array.  */
  	itype = variable_size (itype);
        /* Make sure that there was no overflow when creating to a signed
       	 index type.  (For example, on a 32-bit machine, an array with
--- 6194,6217 ----
    if (processing_template_decl && !TREE_CONSTANT (size))
      /* A variable sized array.  */
      itype = build_min (MINUS_EXPR, sizetype, size, integer_one_node);
    else
      {
+       HOST_WIDE_INT saved_processing_template_decl;
+ 
        /* Compute the index of the largest element in the array.  It is
!      	 one less than the number of elements in the array.  We save
!      	 and restore PROCESSING_TEMPLATE_DECL so that computations in
!      	 cp_build_binary_op will be appropriately folded.  */
!       saved_processing_template_decl = processing_template_decl;
!       processing_template_decl = 0;
!       itype = cp_build_binary_op (MINUS_EXPR,
! 				  cp_convert (ssizetype, size),
! 				  cp_convert (ssizetype, integer_one_node));
!       itype = fold (itype);
!       processing_template_decl = saved_processing_template_decl;
! 
        if (!TREE_CONSTANT (itype))
  	/* A variable sized array.  */
  	itype = variable_size (itype);
        /* Make sure that there was no overflow when creating to a signed
       	 index type.  (For example, on a 32-bit machine, an array with
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.927
diff -c -5 -p -r1.927 pt.c
*** cp/pt.c	27 Sep 2004 12:00:07 -0000	1.927
--- cp/pt.c	28 Sep 2004 02:29:18 -0000
*************** convert_nontype_argument (tree type, tre
*** 3379,3388 ****
--- 3379,3390 ----
        return NULL_TREE;
      }
  
    switch (TREE_CODE (type))
      {
+       HOST_WIDE_INT saved_processing_template_decl;
+ 
      case INTEGER_TYPE:
      case BOOLEAN_TYPE:
      case ENUMERAL_TYPE:
        /* For a non-type template-parameter of integral or enumeration
           type, integral promotions (_conv.prom_) and integral
*************** convert_nontype_argument (tree type, tre
*** 3396,3407 ****
  	  && TREE_CODE (expr_type) == ENUMERAL_TYPE
  	  && !same_type_ignoring_top_level_qualifiers_p (type, expr_type))
  	  return error_mark_node;
  
        /* It's safe to call digest_init in this case; we know we're
! 	 just converting one integral constant expression to another.  */
        expr = digest_init (type, expr, (tree*) 0);
  
        if (TREE_CODE (expr) != INTEGER_CST)
  	/* Curiously, some TREE_CONSTANT integral expressions do not
  	   simplify to integer constants.  For example, `3 % 0',
  	   remains a TRUNC_MOD_EXPR.  */
--- 3398,3413 ----
  	  && TREE_CODE (expr_type) == ENUMERAL_TYPE
  	  && !same_type_ignoring_top_level_qualifiers_p (type, expr_type))
  	  return error_mark_node;
  
        /* It's safe to call digest_init in this case; we know we're
! 	 just converting one integral constant expression to another.
! 	 */
!       saved_processing_template_decl = processing_template_decl;
!       processing_template_decl = 0;
        expr = digest_init (type, expr, (tree*) 0);
+       processing_template_decl = saved_processing_template_decl;
  
        if (TREE_CODE (expr) != INTEGER_CST)
  	/* Curiously, some TREE_CONSTANT integral expressions do not
  	   simplify to integer constants.  For example, `3 % 0',
  	   remains a TRUNC_MOD_EXPR.  */
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.411
diff -c -5 -p -r1.411 tree.c
*** cp/tree.c	21 Sep 2004 16:20:03 -0000	1.411
--- cp/tree.c	28 Sep 2004 02:29:18 -0000
*************** stabilize_init (tree init, tree *initp)
*** 2329,2338 ****
--- 2329,2351 ----
      }
  
    return true;
  }
  
+ /* Like "fold", but should be used whenever we might be processing the
+    body of a template.  */
+ 
+ tree
+ fold_if_not_in_template (tree expr)
+ {
+   /* In the body of a template, there is never any need to call
+      "fold".  We will call fold later when actually instantiating the
+      template.  Integral constant expressions in templates will be
+      evaluted via fold_non_dependent_expr, as necessary.  */
+   return (processing_template_decl ? expr : fold (expr));
+ }
+ 
  
  #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
  /* Complain that some language-specific thing hanging off a tree
     node has been accessed improperly.  */
  
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.578
diff -c -5 -p -r1.578 typeck.c
*** cp/typeck.c	21 Sep 2004 16:20:04 -0000	1.578
--- cp/typeck.c	28 Sep 2004 02:29:18 -0000
*************** build_class_member_access_expr (tree obj
*** 1766,1777 ****
  	  if (DECL_MUTABLE_P (member))
  	    type_quals &= ~TYPE_QUAL_CONST;
  	  member_type = cp_build_qualified_type (member_type, type_quals);
  	}
  
!       result = fold (build3 (COMPONENT_REF, member_type, object, member,
! 			     NULL_TREE));
  
        /* Mark the expression const or volatile, as appropriate.  Even
  	 though we've dealt with the type above, we still have to mark the
  	 expression itself.  */
        if (type_quals & TYPE_QUAL_CONST)
--- 1766,1778 ----
  	  if (DECL_MUTABLE_P (member))
  	    type_quals &= ~TYPE_QUAL_CONST;
  	  member_type = cp_build_qualified_type (member_type, type_quals);
  	}
  
!       result = build3 (COMPONENT_REF, member_type, object, member,
! 		       NULL_TREE);
!       result = fold_if_not_in_template (result);
  
        /* Mark the expression const or volatile, as appropriate.  Even
  	 though we've dealt with the type above, we still have to mark the
  	 expression itself.  */
        if (type_quals & TYPE_QUAL_CONST)
*************** build_array_ref (tree array, tree idx)
*** 2270,2280 ****
  	|= (CP_TYPE_CONST_P (type) | TREE_READONLY (array));
        TREE_SIDE_EFFECTS (rval)
  	|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
        TREE_THIS_VOLATILE (rval)
  	|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
!       return require_complete_type (fold (rval));
      }
  
    {
      tree ar = default_conversion (array);
      tree ind = default_conversion (idx);
--- 2271,2281 ----
  	|= (CP_TYPE_CONST_P (type) | TREE_READONLY (array));
        TREE_SIDE_EFFECTS (rval)
  	|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
        TREE_THIS_VOLATILE (rval)
  	|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
!       return require_complete_type (fold_if_not_in_template (rval));
      }
  
    {
      tree ar = default_conversion (array);
      tree ind = default_conversion (idx);
*************** build_binary_op (enum tree_code code, tr
*** 2760,2769 ****
--- 2761,2772 ----
  
    /* Nonzero means after finally constructing the expression
       convert it to this type.  */
    tree final_type = 0;
  
+   tree result;
+ 
    /* Nonzero if this is an operation like MIN or MAX which can
       safely be computed in short if both args are promoted shorts.
       Also implies COMMON.
       -1 indicates a bitwise operation; this makes a difference
       in the exact conditions for when it is safe to do the operation
*************** build_binary_op (enum tree_code code, tr
*** 2780,2789 ****
--- 2783,2795 ----
    int short_shift = 0;
  
    /* Nonzero means set RESULT_TYPE to the common type of the args.  */
    int common = 0;
  
+   /* True if both operands have arithmetic type.  */
+   bool arithmetic_types_p;
+ 
    /* Apply default conversions.  */
    op0 = orig_op0;
    op1 = orig_op1;
    
    if (code == TRUTH_AND_EXPR || code == TRUTH_ANDIF_EXPR
*************** build_binary_op (enum tree_code code, tr
*** 3167,3184 ****
  
      default:
        break;
      }
  
!   if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
!       &&
!       (code1 == INTEGER_TYPE || code1 == REAL_TYPE || code1 == COMPLEX_TYPE))
      {
!       int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
  
!       if (shorten || common || short_compare)
! 	result_type = common_type (type0, type1);
  
        /* For certain operations (which identify themselves by shorten != 0)
  	 if both args were extended from the same smaller type,
  	 do the arithmetic in that type and then extend.
  
--- 3173,3207 ----
  
      default:
        break;
      }
  
!   arithmetic_types_p = 
!     ((code0 == INTEGER_TYPE || code0 == REAL_TYPE || code0 == COMPLEX_TYPE)
!      && (code1 == INTEGER_TYPE || code1 == REAL_TYPE 
! 	 || code1 == COMPLEX_TYPE));
!   /* Determine the RESULT_TYPE, if it is not already known.  */
!   if (!result_type
!       && arithmetic_types_p 
!       && (shorten || common || short_compare))
!     result_type = common_type (type0, type1);
! 
!   if (!result_type)
      {
!       error ("invalid operands of types `%T' and `%T' to binary `%O'",
! 	     TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
!       return error_mark_node;
!     }
  
!   /* If we're in a template, the only thing we need to know is the
!      RESULT_TYPE.  */
!   if (processing_template_decl)
!     return build2 (resultcode, result_type, op0, op1);
! 
!   if (arithmetic_types_p)
!     {
!       int none_complex = (code0 != COMPLEX_TYPE && code1 != COMPLEX_TYPE);
  
        /* For certain operations (which identify themselves by shorten != 0)
  	 if both args were extended from the same smaller type,
  	 do the arithmetic in that type and then extend.
  
*************** build_binary_op (enum tree_code code, tr
*** 3417,3439 ****
  		warning ("comparison of promoted ~unsigned with unsigned");
  	    }
  	}
      }
  
!   /* At this point, RESULT_TYPE must be nonzero to avoid an error message.
!      If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
       Then the expression will be built.
       It will be given type FINAL_TYPE if that is nonzero;
       otherwise, it will be given type RESULT_TYPE.  */
  
-   if (!result_type)
-     {
-       error ("invalid operands of types `%T' and `%T' to binary `%O'",
- 		TREE_TYPE (orig_op0), TREE_TYPE (orig_op1), code);
-       return error_mark_node;
-     }
- 
    /* Issue warnings about peculiar, but valid, uses of NULL.  */
    if (/* It's reasonable to use pointer values as operands of &&
  	 and ||, so NULL is no exception.  */
        !(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
        && (/* If OP0 is NULL and OP1 is not a pointer, or vice versa.  */
--- 3440,3454 ----
  		warning ("comparison of promoted ~unsigned with unsigned");
  	    }
  	}
      }
  
!   /* If CONVERTED is zero, both args will be converted to type RESULT_TYPE.
       Then the expression will be built.
       It will be given type FINAL_TYPE if that is nonzero;
       otherwise, it will be given type RESULT_TYPE.  */
  
    /* Issue warnings about peculiar, but valid, uses of NULL.  */
    if (/* It's reasonable to use pointer values as operands of &&
  	 and ||, so NULL is no exception.  */
        !(code == TRUTH_ANDIF_EXPR || code == TRUTH_ORIF_EXPR)
        && (/* If OP0 is NULL and OP1 is not a pointer, or vice versa.  */
*************** build_binary_op (enum tree_code code, tr
*** 3463,3478 ****
      }
  
    if (build_type == NULL_TREE)
      build_type = result_type;
  
!   {
!     tree result = fold (build2 (resultcode, build_type, op0, op1));
!     if (final_type != 0)
!       result = cp_convert (final_type, result);
!     return result;
!   }
  }
  
  /* Return a tree for the sum or difference (RESULTCODE says which)
     of pointer PTROP and integer INTOP.  */
  
--- 3478,3492 ----
      }
  
    if (build_type == NULL_TREE)
      build_type = result_type;
  
!   result = build2 (resultcode, build_type, op0, op1);
!   result = fold_if_not_in_template (result);
!   if (final_type != 0)
!     result = cp_convert (final_type, result);
!   return result;
  }
  
  /* Return a tree for the sum or difference (RESULTCODE says which)
     of pointer PTROP and integer INTOP.  */
  
*************** cp_pointer_int_sum (enum tree_code resul
*** 3486,3496 ****
       to make sure it's complete.  We don't need to check here, if we
       can actually complete it at all, as those checks will be done in
       pointer_int_sum() anyway.  */
    complete_type (TREE_TYPE (res_type));
  
!   return pointer_int_sum (resultcode, ptrop, fold (intop));
  }
  
  /* Return a tree for the difference of pointers OP0 and OP1.
     The resulting tree has type int.  */
  
--- 3500,3511 ----
       to make sure it's complete.  We don't need to check here, if we
       can actually complete it at all, as those checks will be done in
       pointer_int_sum() anyway.  */
    complete_type (TREE_TYPE (res_type));
  
!   return pointer_int_sum (resultcode, ptrop,
! 			  fold_if_not_in_template (intop));
  }
  
  /* Return a tree for the difference of pointers OP0 and OP1.
     The resulting tree has type int.  */
  
*************** pointer_diff (tree op0, tree op1, tree p
*** 3530,3540 ****
  	 : integer_one_node);
  
    /* Do the division.  */
  
    result = build2 (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
!   return fold (result);
  }
  
  /* Construct and perhaps optimize a tree representation
     for a unary operation.  CODE, a tree_code, specifies the operation
     and XARG is the operand.  */
--- 3545,3555 ----
  	 : integer_one_node);
  
    /* Do the division.  */
  
    result = build2 (EXACT_DIV_EXPR, restype, op0, cp_convert (restype, op1));
!   return fold_if_not_in_template (result);
  }
  
  /* Construct and perhaps optimize a tree representation
     for a unary operation.  CODE, a tree_code, specifies the operation
     and XARG is the operand.  */
*************** build_unary_op (enum tree_code code, tre
*** 3780,3798 ****
        
      case REALPART_EXPR:
        if (TREE_CODE (arg) == COMPLEX_CST)
  	return TREE_REALPART (arg);
        else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
! 	return fold (build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
        else
  	return arg;
  
      case IMAGPART_EXPR:
        if (TREE_CODE (arg) == COMPLEX_CST)
  	return TREE_IMAGPART (arg);
        else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
! 	return fold (build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg));
        else
  	return cp_convert (TREE_TYPE (arg), integer_zero_node);
        
      case PREINCREMENT_EXPR:
      case POSTINCREMENT_EXPR:
--- 3795,3819 ----
        
      case REALPART_EXPR:
        if (TREE_CODE (arg) == COMPLEX_CST)
  	return TREE_REALPART (arg);
        else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
! 	{
! 	  arg = build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
! 	  return fold_if_not_in_template (arg);
! 	}
        else
  	return arg;
  
      case IMAGPART_EXPR:
        if (TREE_CODE (arg) == COMPLEX_CST)
  	return TREE_IMAGPART (arg);
        else if (TREE_CODE (TREE_TYPE (arg)) == COMPLEX_TYPE)
! 	{
! 	  arg = build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
! 	  return fold_if_not_in_template (arg);
! 	}
        else
  	return cp_convert (TREE_TYPE (arg), integer_zero_node);
        
      case PREINCREMENT_EXPR:
      case POSTINCREMENT_EXPR:
*************** build_unary_op (enum tree_code code, tre
*** 4131,4141 ****
  
    if (!errstring)
      {
        if (argtype == 0)
  	argtype = TREE_TYPE (arg);
!       return fold (build1 (code, argtype, arg));
      }
  
    error ("%s", errstring);
    return error_mark_node;
  }
--- 4152,4162 ----
  
    if (!errstring)
      {
        if (argtype == 0)
  	argtype = TREE_TYPE (arg);
!       return fold_if_not_in_template (build1 (code, argtype, arg));
      }
  
    error ("%s", errstring);
    return error_mark_node;
  }
*************** build_reinterpret_cast (tree type, tree 
*** 4719,4743 ****
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
  	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
      {
        expr = decl_constant_value (expr);
!       return fold (build1 (NOP_EXPR, type, expr));
      }
    else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
  	   || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
      {
        check_for_casting_away_constness (intype, type, "reinterpret_cast");
        expr = decl_constant_value (expr);
!       return fold (build1 (NOP_EXPR, type, expr));
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
  	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
      {
        pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
        expr = decl_constant_value (expr);
!       return fold (build1 (NOP_EXPR, type, expr));
      }
    else
      {
        error ("invalid reinterpret_cast from type `%T' to type `%T'",
                  intype, type);
--- 4740,4764 ----
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
  	   || (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
      {
        expr = decl_constant_value (expr);
!       return fold_if_not_in_template (build_nop (type, expr));
      }
    else if ((TYPE_PTRMEM_P (type) && TYPE_PTRMEM_P (intype))
  	   || (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
      {
        check_for_casting_away_constness (intype, type, "reinterpret_cast");
        expr = decl_constant_value (expr);
!       return fold_if_not_in_template (build_nop (type, expr));
      }
    else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
  	   || (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
      {
        pedwarn ("ISO C++ forbids casting between pointer-to-function and pointer-to-object");
        expr = decl_constant_value (expr);
!       return fold_if_not_in_template (build_nop (type, expr));
      }
    else
      {
        error ("invalid reinterpret_cast from type `%T' to type `%T'",
                  intype, type);
*************** get_delta_difference (tree from, tree to
*** 5380,5390 ****
  	    error ("pointer to member conversion via virtual base `%T'",
  		   BINFO_TYPE (virt_binfo));
  	}
      }
  
!   return fold (convert_to_integer (ptrdiff_type_node, result));
  }
  
  /* Return a constructor for the pointer-to-member-function TYPE using
     the other components as specified.  */
  
--- 5401,5412 ----
  	    error ("pointer to member conversion via virtual base `%T'",
  		   BINFO_TYPE (virt_binfo));
  	}
      }
  
!   return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node, 
! 						      result));
  }
  
  /* Return a constructor for the pointer-to-member-function TYPE using
     the other components as specified.  */
  
*************** expand_ptrmemfunc_cst (tree cst, tree *d
*** 5538,5577 ****
        /* If we're dealing with a virtual function, we have to adjust 'this'
           again, to point to the base which provides the vtable entry for
           fn; the call will do the opposite adjustment.  */
        tree orig_class = DECL_CONTEXT (fn);
        tree binfo = binfo_or_else (orig_class, fn_class);
!       *delta = fold (build2 (PLUS_EXPR, TREE_TYPE (*delta),
! 			     *delta, BINFO_OFFSET (binfo)));
  
        /* We set PFN to the vtable offset at which the function can be
  	 found, plus one (unless ptrmemfunc_vbit_in_delta, in which
  	 case delta is shifted left, and then incremented).  */
        *pfn = DECL_VINDEX (fn);
!       *pfn = fold (build2 (MULT_EXPR, integer_type_node, *pfn,
! 			   TYPE_SIZE_UNIT (vtable_entry_type)));
  
        switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
  	{
  	case ptrmemfunc_vbit_in_pfn:
! 	  *pfn = fold (build2 (PLUS_EXPR, integer_type_node, *pfn,
! 			       integer_one_node));
  	  break;
  
  	case ptrmemfunc_vbit_in_delta:
! 	  *delta = fold (build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
! 				 *delta, integer_one_node));
! 	  *delta = fold (build2 (PLUS_EXPR, TREE_TYPE (*delta),
! 				 *delta, integer_one_node));
  	  break;
  
  	default:
  	  gcc_unreachable ();
  	}
  
!       *pfn = fold (build1 (NOP_EXPR, TYPE_PTRMEMFUNC_FN_TYPE (type),
! 			   *pfn));
      }
  }
  
  /* Return an expression for PFN from the pointer-to-member function
     given by T.  */
--- 5560,5604 ----
        /* If we're dealing with a virtual function, we have to adjust 'this'
           again, to point to the base which provides the vtable entry for
           fn; the call will do the opposite adjustment.  */
        tree orig_class = DECL_CONTEXT (fn);
        tree binfo = binfo_or_else (orig_class, fn_class);
!       *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
! 		       *delta, BINFO_OFFSET (binfo));
!       *delta = fold_if_not_in_template (*delta);
  
        /* We set PFN to the vtable offset at which the function can be
  	 found, plus one (unless ptrmemfunc_vbit_in_delta, in which
  	 case delta is shifted left, and then incremented).  */
        *pfn = DECL_VINDEX (fn);
!       *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
! 		     TYPE_SIZE_UNIT (vtable_entry_type));
!       *pfn = fold_if_not_in_template (*pfn);
  
        switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
  	{
  	case ptrmemfunc_vbit_in_pfn:
! 	  *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
! 			 integer_one_node);
! 	  *pfn = fold_if_not_in_template (*pfn);
  	  break;
  
  	case ptrmemfunc_vbit_in_delta:
! 	  *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
! 			   *delta, integer_one_node);
! 	  *delta = fold_if_not_in_template (*delta);
! 	  *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
! 			   *delta, integer_one_node);
! 	  *delta = fold_if_not_in_template (*delta);
  	  break;
  
  	default:
  	  gcc_unreachable ();
  	}
  
!       *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
!       *pfn = fold_if_not_in_template (*pfn);
      }
  }
  
  /* Return an expression for PFN from the pointer-to-member function
     given by T.  */
*************** dubious_conversion_warnings (tree type, 
*** 5637,5647 ****
  	}
  
        overflow_warning (expr);
  
        if (TREE_CONSTANT (expr))
! 	expr = fold (expr);
      }
    return expr;
  }
  
  /* Convert value RHS to type TYPE as preparation for an assignment to
--- 5664,5674 ----
  	}
  
        overflow_warning (expr);
  
        if (TREE_CONSTANT (expr))
! 	expr = fold_if_not_in_template (expr);
      }
    return expr;
  }
  
  /* Convert value RHS to type TYPE as preparation for an assignment to
Index: testsuite/g++.dg/template/crash23.C
===================================================================
RCS file: testsuite/g++.dg/template/crash23.C
diff -N testsuite/g++.dg/template/crash23.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/crash23.C	28 Sep 2004 02:29:19 -0000
***************
*** 0 ****
--- 1,9 ----
+ // PR c++/17642
+ 
+ template<int dim>
+ int f(const int* const lsh, const int* const bbox, const int* const nghostzones, int d)
+ {
+   for (int d=0; d<dim; ++d)
+     lsh[d] - (bbox[2*d+1] ? 0 : nghostzones[d]);
+ }
+ 



More information about the Gcc-patches mailing list