This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] Fix bug 160


Hi,
this fixes bug 160 where we incorrectly initialized a reference member
to a temporary, rather then the object we should have.  build_modify_expr
had a remarkable amount of cruft in it, which I've removed and tidied up.

In a member initializer of the form 'ref ((Foo (), m))' where 'ref' is a
reference type, we'd create a SAVE_EXPR for the expression which would
create a temporary for m and we'd bind the reference to that, rather
than 'm'. Other kinds of reference initializers don't go via
build_modify_expr.

built & tested on i686-pc-linux-gnu, ok?

nathan

-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
2001-12-21  Nathan Sidwell  <nathan@codesourcery.com>

	PR c++/160
	* typeck.c (build_modify_expr): Remove old unreachable code & tidy
	up. Don't stabilize_references when initializing a reference.

Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.377
diff -c -3 -p -r1.377 typeck.c
*** typeck.c	2001/12/19 11:52:57	1.377
--- typeck.c	2001/12/21 11:31:20
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5494,5506 ****
    if (lhs == error_mark_node || rhs == error_mark_node)
      return error_mark_node;
  
-   /* Types that aren't fully specified cannot be used in assignments.  */
-   lhs = require_complete_type (lhs);
- 
-   newrhs = rhs;
- 
    /* Handle control structure constructs used as "lvalues".  */
- 
    switch (TREE_CODE (lhs))
      {
        /* Handle --foo = 5; as these are valid constructs in C++ */
--- 5494,5500 ----
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5532,5544 ****
  
        /* Handle (a ? b : c) used as an "lvalue".  */
      case COND_EXPR:
-       rhs = save_expr (rhs);
        {
  	/* Produce (a ? (b = rhs) : (c = rhs))
  	   except that the RHS goes through a save-expr
  	   so the code to compute it is only emitted once.  */
  	tree cond;
  
  	/* Check this here to avoid odd errors when trying to convert
  	   a throw to the type of the COND_EXPR.  */
  	if (!lvalue_or_else (lhs, "assignment"))
--- 5526,5539 ----
  
        /* Handle (a ? b : c) used as an "lvalue".  */
      case COND_EXPR:
        {
  	/* Produce (a ? (b = rhs) : (c = rhs))
  	   except that the RHS goes through a save-expr
  	   so the code to compute it is only emitted once.  */
  	tree cond;
  
+ 	rhs = save_expr (rhs);
+ 	
  	/* Check this here to avoid odd errors when trying to convert
  	   a throw to the type of the COND_EXPR.  */
  	if (!lvalue_or_else (lhs, "assignment"))
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5558,5611 ****
  	/* Make sure the code to compute the rhs comes out
  	   before the split.  */
  	return build (COMPOUND_EXPR, TREE_TYPE (lhs),
! 		      /* Case to void to suppress warning
  			 from warn_if_unused_value.  */
  		      cp_convert (void_type_node, rhs), cond);
        }
! 
      default:
        break;
      }
  
-   if (TREE_CODE (lhs) == OFFSET_REF)
-     {
-       if (TREE_OPERAND (lhs, 0) == NULL_TREE)
- 	{
- 	  /* Static class member?  */
- 	  tree member = TREE_OPERAND (lhs, 1);
- 	  if (TREE_CODE (member) == VAR_DECL)
- 	    lhs = member;
- 	  else
- 	    {
- 	      compiler_error ("invalid static class member");
- 	      return error_mark_node;
- 	    }
- 	}
-       else
- 	lhs = resolve_offset_ref (lhs);
- 
-       olhstype = lhstype = TREE_TYPE (lhs);
-     }
- 
-   if (lhs == error_mark_node)
-     return lhs;
- 
-   if (TREE_CODE (lhstype) == REFERENCE_TYPE
-       && modifycode != INIT_EXPR)
-     {
-       lhs = convert_from_reference (lhs);
-       olhstype = lhstype = TREE_TYPE (lhs);
-     }
- 
-   /* If a binary op has been requested, combine the old LHS value with the RHS
-      producing the value we should actually store into the LHS.  */
- 
    if (modifycode == INIT_EXPR)
      {
        if (TREE_CODE (rhs) == CONSTRUCTOR)
  	{
! 	  if (! same_type_p (TREE_TYPE (rhs), lhstype))
! 	    abort ();
  	  result = build (INIT_EXPR, lhstype, lhs, rhs);
  	  TREE_SIDE_EFFECTS (result) = 1;
  	  return result;
--- 5553,5579 ----
  	/* Make sure the code to compute the rhs comes out
  	   before the split.  */
  	return build (COMPOUND_EXPR, TREE_TYPE (lhs),
! 		      /* Cast to void to suppress warning
  			 from warn_if_unused_value.  */
  		      cp_convert (void_type_node, rhs), cond);
        }
!       
!     case OFFSET_REF:
!       lhs = resolve_offset_ref (lhs);
!       if (lhs == error_mark_node)
! 	return error_mark_node;
!       olhstype = lhstype = TREE_TYPE (lhs);
!     
      default:
        break;
      }
  
    if (modifycode == INIT_EXPR)
      {
        if (TREE_CODE (rhs) == CONSTRUCTOR)
  	{
! 	  my_friendly_assert (same_type_p (TREE_TYPE (rhs), lhstype),
! 			      20011220);
  	  result = build (INIT_EXPR, lhstype, lhs, rhs);
  	  TREE_SIDE_EFFECTS (result) = 1;
  	  return result;
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5622,5656 ****
  	  return result;
  	}
      }
!   else if (modifycode == NOP_EXPR)
      {
!       /* `operator=' is not an inheritable operator.  */
!       if (! IS_AGGR_TYPE (lhstype))
! 	/* Do the default thing */;
!       else
  	{
! 	  result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
! 				   lhs, rhs, make_node (NOP_EXPR));
! 	  if (result == NULL_TREE)
! 	    return error_mark_node;
! 	  return result;
  	}
!       lhstype = olhstype;
!     }
!   else if (PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE))
!     {
!       my_friendly_abort (978652);
!     }
!   else
!     {
!       lhs = stabilize_reference (lhs);
!       newrhs = cp_build_binary_op (modifycode, lhs, rhs);
!       if (newrhs == error_mark_node)
  	{
! 	  error ("  in evaluation of `%Q(%#T, %#T)'", modifycode,
! 		    TREE_TYPE (lhs), TREE_TYPE (rhs));
! 	  return error_mark_node;
  	}
      }
  
    /* Handle a cast used as an "lvalue".
--- 5590,5644 ----
  	  return result;
  	}
      }
!   else
      {
!       if (TREE_CODE (lhstype) == REFERENCE_TYPE)
  	{
! 	  lhs = convert_from_reference (lhs);
! 	  olhstype = lhstype = TREE_TYPE (lhs);
  	}
!       lhs = require_complete_type (lhs);
!       if (lhs == error_mark_node)
! 	return error_mark_node;
! 
!       if (modifycode == NOP_EXPR)
  	{
! 	  /* `operator=' is not an inheritable operator.  */
! 	  if (! IS_AGGR_TYPE (lhstype))
! 	    /* Do the default thing */;
! 	  else
! 	    {
! 	      result = build_opfncall (MODIFY_EXPR, LOOKUP_NORMAL,
! 				       lhs, rhs, make_node (NOP_EXPR));
! 	      if (result == NULL_TREE)
! 		return error_mark_node;
! 	      return result;
! 	    }
! 	  lhstype = olhstype;
! 	}
!       else
! 	{
! 	  /* A binary op has been requested.  Combine the old LHS
!      	     value with the RHS producing the value we should actually
!      	     store into the LHS.  */
! 
! 	  my_friendly_assert (!PROMOTES_TO_AGGR_TYPE (lhstype, REFERENCE_TYPE),
! 			      978652);
! 	  lhs = stabilize_reference (lhs);
! 	  newrhs = cp_build_binary_op (modifycode, lhs, rhs);
! 	  if (newrhs == error_mark_node)
! 	    {
! 	      error ("  in evaluation of `%Q(%#T, %#T)'", modifycode,
! 		     TREE_TYPE (lhs), TREE_TYPE (rhs));
! 	      return error_mark_node;
! 	    }
! 	  
! 	  /* Now it looks like a plain assignment.  */
! 	  modifycode = NOP_EXPR;
  	}
+       my_friendly_assert (TREE_CODE (lhstype) != REFERENCE_TYPE, 20011220);
+       my_friendly_assert (TREE_CODE (TREE_TYPE (newrhs)) != REFERENCE_TYPE,
+ 			  20011220);
      }
  
    /* Handle a cast used as an "lvalue".
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5669,5683 ****
      case FIX_FLOOR_EXPR:
      case FIX_ROUND_EXPR:
      case FIX_CEIL_EXPR:
-       if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
- 	  || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
- 	  || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
- 	  || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
- 	newrhs = default_conversion (newrhs);
        {
  	tree inner_lhs = TREE_OPERAND (lhs, 0);
  	tree result;
  
  	/* ISO C++ 5.4/1: The result is an lvalue if T is a reference
  	   type, otherwise the result is an rvalue.  */
  	if (! lvalue_p (lhs))
--- 5657,5672 ----
      case FIX_FLOOR_EXPR:
      case FIX_ROUND_EXPR:
      case FIX_CEIL_EXPR:
        {
  	tree inner_lhs = TREE_OPERAND (lhs, 0);
  	tree result;
  
+ 	if (TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
+ 	    || TREE_CODE (TREE_TYPE (newrhs)) == FUNCTION_TYPE
+ 	    || TREE_CODE (TREE_TYPE (newrhs)) == METHOD_TYPE
+ 	    || TREE_CODE (TREE_TYPE (newrhs)) == OFFSET_TYPE)
+ 	  newrhs = default_conversion (newrhs);
+ 	
  	/* ISO C++ 5.4/1: The result is an lvalue if T is a reference
  	   type, otherwise the result is an rvalue.  */
  	if (! lvalue_p (lhs))
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5703,5725 ****
  
    GNU_xref_assign (lhs);
  
!   /* Warn about storing in something that is `const'.  */
!   /* For C++, don't warn if this is initialization.  */
    if (modifycode != INIT_EXPR
        && (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
  	  /* Functions are not modifiable, even though they are
  	     lvalues.  */
  	  || TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
  	  || (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
! 	      && C_TYPE_FIELDS_READONLY (lhstype))
! 	  || (TREE_CODE (lhstype) == REFERENCE_TYPE
! 	      && CP_TYPE_CONST_P (TREE_TYPE (lhstype)))))
      readonly_error (lhs, "assignment", 0);
  
!   /* If storing into a structure or union member,
!      it has probably been given type `int'.
!      Compute the type that would go with
!      the actual amount of storage the member occupies.  */
  
    if (TREE_CODE (lhs) == COMPONENT_REF
        && (TREE_CODE (lhstype) == INTEGER_TYPE
--- 5692,5714 ----
  
    GNU_xref_assign (lhs);
  
!   /* Warn about modifying something that is `const'.  Don't warn if
!      this is initialization.  */
    if (modifycode != INIT_EXPR
        && (TREE_READONLY (lhs) || CP_TYPE_CONST_P (lhstype)
  	  /* Functions are not modifiable, even though they are
  	     lvalues.  */
  	  || TREE_CODE (TREE_TYPE (lhs)) == FUNCTION_TYPE
+ 	  || TREE_CODE (TREE_TYPE (lhs)) == METHOD_TYPE
+ 	  /* If it's an aggregate and any field is const, then it is
+ 	     effectively const.  */
  	  || (IS_AGGR_TYPE_CODE (TREE_CODE (lhstype))
! 	      && C_TYPE_FIELDS_READONLY (lhstype))))
      readonly_error (lhs, "assignment", 0);
  
!   /* If storing into a structure or union member, it has probably been
!      given type `int'.  Compute the type that would go with the actual
!      amount of storage the member occupies.  */
  
    if (TREE_CODE (lhs) == COMPONENT_REF
        && (TREE_CODE (lhstype) == INTEGER_TYPE
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5738,5777 ****
  	}
      }
  
!   if (modifycode != INIT_EXPR)
      {
!       /* Make modifycode now either a NOP_EXPR or an INIT_EXPR.  */
!       modifycode = NOP_EXPR;
!       /* Reference-bashing */
!       if (TREE_CODE (lhstype) == REFERENCE_TYPE)
! 	{
! 	  tree tmp = convert_from_reference (lhs);
! 	  lhstype = TREE_TYPE (tmp);
! 	  if (!COMPLETE_TYPE_P (lhstype))
! 	    {
! 	      incomplete_type_error (lhs, lhstype);
! 	      return error_mark_node;
! 	    }
! 	  lhs = tmp;
! 	  olhstype = lhstype;
! 	}
!       if (TREE_CODE (TREE_TYPE (newrhs)) == REFERENCE_TYPE)
! 	{
! 	  tree tmp = convert_from_reference (newrhs);
! 	  if (!COMPLETE_TYPE_P (TREE_TYPE (tmp)))
! 	    {
! 	      incomplete_type_error (newrhs, TREE_TYPE (tmp));
! 	      return error_mark_node;
! 	    }
! 	  newrhs = tmp;
! 	}
      }
  
-   if (TREE_SIDE_EFFECTS (lhs))
-     lhs = stabilize_reference (lhs);
-   if (TREE_SIDE_EFFECTS (newrhs))
-     newrhs = stabilize_reference (newrhs);
- 
    /* Convert new value to destination type.  */
  
    if (TREE_CODE (lhstype) == ARRAY_TYPE)
--- 5727,5740 ----
  	}
      }
  
!   if (TREE_CODE (lhstype) != REFERENCE_TYPE)
      {
!       if (TREE_SIDE_EFFECTS (lhs))
! 	lhs = stabilize_reference (lhs);
!       if (TREE_SIDE_EFFECTS (newrhs))
! 	newrhs = stabilize_reference (newrhs);
      }
  
    /* Convert new value to destination type.  */
  
    if (TREE_CODE (lhstype) == ARRAY_TYPE)
*************** build_modify_expr (lhs, modifycode, rhs)
*** 5795,5811 ****
      }
  
    if (modifycode == INIT_EXPR)
!     {
!       newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
! 					   "initialization", NULL_TREE, 0);
!       if (current_function_decl && 
! 	  lhs == DECL_RESULT (current_function_decl))
! 	{
! 	  if (DECL_INITIAL (lhs))
! 	    warning ("return value from function receives multiple initializations");
! 	  DECL_INITIAL (lhs) = newrhs;
! 	}
!     }
    else
      {
        /* Avoid warnings on enum bit fields.  */
--- 5758,5765 ----
      }
  
    if (modifycode == INIT_EXPR)
!     newrhs = convert_for_initialization (lhs, lhstype, newrhs, LOOKUP_NORMAL,
! 					 "initialization", NULL_TREE, 0);
    else
      {
        /* Avoid warnings on enum bit fields.  */
// { dg-do run }

// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 20 Dec 2001 <nathan@nathan@codesourcery.com>

// PR 160. Wrong code emitted for some reference initializers.

void Foo ()
{
}

int fail;

class C
{
  public:
  int m;
  int &r;
  
  C () ;
};

C::C ()
  : m (1), r ((Foo (), m))
{
  m = 10;
  
  if (r != m)
    fail = 1;
  else if (&m != &r)
    fail = 2;
}
int main ()
{
  int m (1);
  int &r ((Foo (),m));

  m = 10;
  if (r != m)
    fail = 3;
  else if (&r != &m)
    fail = 4;

  if (!fail)
    {
      C c;
    }
  return fail;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]