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 for 16015: fix g++.dg/ext/stmtexpr1.C


rth's recent change to make the C/C++ front ends use STATEMENT_LISTs
internally broke stmtexpr1.C; the problem turned out to be that we were
losing the CLEANUP_POINT_EXPR that was previously added in
gimplify_stmt_expr.

However, the fix wasn't as easy as just adding it to finish_stmt_expr,
because that led to the gimplifier trying to generate another temporary.
To avoid this, I have declared that the initializer operand to TARGET_EXPR
can be void, and made AGGR_INIT_EXPRs void to match.  This simplifies
things enormously; there are hacks throughout the compiler to deal with
this case that can now go away.

Tested x86_64-pc-linux-gnu, applied to trunk.

2004-06-17  Jason Merrill  <jason@redhat.com>

	PR c++/16015
	* gimplify.c (gimplify_target_expr): Handle void initializer.
	* expr.c (expand_expr_real_1) [TARGET_EXPR]: Likewise.
	* doc/c-tree.texi (Expression trees): Update TARGET_EXPR
	and AGGR_INIT_EXPR.
	* cp/semantics.c (simplify_aggr_init_expr): Don't return the slot.
	(finish_stmt_expr_expr): Update type after conversions.
	(finish_stmt_expr): Wrap initializer in CLEANUP_POINT_EXPR.
	Handle void initializer.
	* cp/tree.c (build_cplus_new): Make AGGR_INIT_EXPRs void.

Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.652
diff -c -p -r1.652 expr.c
*** gcc/expr.c	16 Jun 2004 07:25:52 -0000	1.652
--- gcc/expr.c	17 Jun 2004 22:07:25 -0000
*************** expand_expr_real_1 (tree exp, rtx target
*** 8862,8868 ****
  	/* Mark it as expanded.  */
  	TREE_OPERAND (exp, 1) = NULL_TREE;
  
! 	store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
  
  	expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
  
--- 8862,8873 ----
  	/* Mark it as expanded.  */
  	TREE_OPERAND (exp, 1) = NULL_TREE;
  
! 	if (VOID_TYPE_P (TREE_TYPE (exp1)))
! 	  /* If the initializer is void, just expand it; it will initialize
! 	     the object directly.  */
! 	  expand_expr (exp1, const0_rtx, VOIDmode, 0);
! 	else
! 	  store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
  
  	expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
  
Index: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.16
diff -c -p -r2.16 gimplify.c
*** gcc/gimplify.c	16 Jun 2004 01:21:25 -0000	2.16
--- gcc/gimplify.c	17 Jun 2004 22:07:25 -0000
*************** gimplify_target_expr (tree *expr_p, tree
*** 3018,3024 ****
  	gimplify_bind_expr (&init, temp, pre_p);
        if (init != temp)
  	{
! 	  init = build (MODIFY_EXPR, void_type_node, temp, init);
  	  ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
  	  if (ret == GS_ERROR)
  	    return GS_ERROR;
--- 3018,3025 ----
  	gimplify_bind_expr (&init, temp, pre_p);
        if (init != temp)
  	{
! 	  if (! VOID_TYPE_P (TREE_TYPE (init)))
! 	    init = build (MODIFY_EXPR, void_type_node, temp, init);
  	  ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt, fb_none);
  	  if (ret == GS_ERROR)
  	    return GS_ERROR;
Index: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.78
diff -c -p -r1.78 tree.def
*** gcc/tree.def	15 Jun 2004 18:37:34 -0000	1.78
--- gcc/tree.def	17 Jun 2004 22:07:25 -0000
*************** DEFTREECODE (MODIFY_EXPR, "modify_expr",
*** 435,444 ****
  DEFTREECODE (INIT_EXPR, "init_expr", 'e', 2)
  
  /* For TARGET_EXPR, operand 0 is the target of an initialization,
!    operand 1 is the initializer for the target,
!    and operand 2 is the cleanup for this node, if any.
!    and operand 3 is the saved initializer after this node has been
!    expanded once, this is so we can re-expand the tree later.  */
  DEFTREECODE (TARGET_EXPR, "target_expr", 'e', 4)
  
  /* Conditional expression ( ... ? ... : ...  in C).
--- 435,445 ----
  DEFTREECODE (INIT_EXPR, "init_expr", 'e', 2)
  
  /* For TARGET_EXPR, operand 0 is the target of an initialization,
!    operand 1 is the initializer for the target, which may be void
!      if simplify expanding it initializes the target.
!    operand 2 is the cleanup for this node, if any.
!    operand 3 is the saved initializer after this node has been
!    expanded once; this is so we can re-expand the tree later.  */
  DEFTREECODE (TARGET_EXPR, "target_expr", 'e', 4)
  
  /* Conditional expression ( ... ? ... : ...  in C).
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.401
diff -c -p -r1.401 semantics.c
*** gcc/cp/semantics.c	17 Jun 2004 01:24:06 -0000	1.401
--- gcc/cp/semantics.c	17 Jun 2004 22:07:26 -0000
*************** tree
*** 1374,1387 ****
  finish_stmt_expr_expr (tree expr, tree stmt_expr)
  {
    tree result = NULL_TREE;
-   tree type = void_type_node;
  
    if (expr)
      {
-       type = TREE_TYPE (expr);
-       
        if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr)))
  	{
  	  if (TREE_CODE (type) == ARRAY_TYPE
  	      || TREE_CODE (type) == FUNCTION_TYPE)
  	    expr = decay_conversion (expr);
--- 1374,1386 ----
  finish_stmt_expr_expr (tree expr, tree stmt_expr)
  {
    tree result = NULL_TREE;
  
    if (expr)
      {
        if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr)))
  	{
+ 	  tree type = TREE_TYPE (expr);
+ 
  	  if (TREE_CODE (type) == ARRAY_TYPE
  	      || TREE_CODE (type) == FUNCTION_TYPE)
  	    expr = decay_conversion (expr);
*************** finish_stmt_expr_expr (tree expr, tree s
*** 1389,1394 ****
--- 1388,1395 ----
  	  expr = convert_from_reference (expr);
  	  expr = require_complete_type (expr);
  
+ 	  type = TREE_TYPE (expr);
+ 
  	  /* Build a TARGET_EXPR for this aggregate.  finish_stmt_expr
  	     will then pull it apart so the lifetime of the target is
  	     within the scope of the expression containing this statement
*************** finish_stmt_expr (tree stmt_expr, bool h
*** 1489,1513 ****
  	 the target's init_expr as the final expression and then put
  	 the statement expression itself as the target's init
  	 expr. Finally, return the target expression.  */
!       tree last_expr = EXPR_STMT_EXPR (result_stmt);
!       
!       my_friendly_assert (TREE_CODE (last_expr) == TARGET_EXPR, 20030729);
!       *result_stmt_p = TREE_OPERAND (last_expr, 1);
  
!       if (TREE_CODE (result) == BIND_EXPR)
  	{
  	  if (VOID_TYPE_P (TREE_TYPE (result)))
! 	    TREE_TYPE (result) = TREE_TYPE (last_expr);
! 	  else if (same_type_p (TREE_TYPE (result), TREE_TYPE (last_expr)))
  	    ;
  	  else
  	    abort ();
  	}
        else if (TREE_CODE (result) == STATEMENT_LIST)
! 	result = build (BIND_EXPR, TREE_TYPE (last_expr), NULL, result, NULL);
  
!       TREE_OPERAND (last_expr, 1) = result;
!       result = last_expr;
      }
  
    return result;
--- 1490,1529 ----
  	 the target's init_expr as the final expression and then put
  	 the statement expression itself as the target's init
  	 expr. Finally, return the target expression.  */
!       tree init, target_expr = EXPR_STMT_EXPR (result_stmt);
!       my_friendly_assert (TREE_CODE (target_expr) == TARGET_EXPR, 20030729);
  
!       /* The initializer will be void if the initialization is done by
! 	 AGGR_INIT_EXPR; propagate that out to the statement-expression as
! 	 a whole.  */
!       init = TREE_OPERAND (target_expr, 1);
!       type = TREE_TYPE (init);
! 
!       if (stmts_are_full_exprs_p ())
! 	init = fold (build1 (CLEANUP_POINT_EXPR, type, init));
!       *result_stmt_p = init;
! 
!       if (VOID_TYPE_P (type))
! 	/* No frobbing needed.  */;
!       else if (TREE_CODE (result) == BIND_EXPR)
  	{
+ 	  /* The BIND_EXPR created in finish_compound_stmt is void; if we're
+ 	     returning a value directly, give it the appropriate type.  */
  	  if (VOID_TYPE_P (TREE_TYPE (result)))
! 	    TREE_TYPE (result) = type;
! 	  else if (same_type_p (TREE_TYPE (result), type))
  	    ;
  	  else
  	    abort ();
  	}
        else if (TREE_CODE (result) == STATEMENT_LIST)
! 	/* We need to wrap a STATEMENT_LIST in a BIND_EXPR so it can have a
! 	   type other than void.  FIXME why can't we just return a value
! 	   from STATEMENT_LIST?  */
! 	result = build3 (BIND_EXPR, type, NULL, result, NULL);
  
!       TREE_OPERAND (target_expr, 1) = result;
!       result = target_expr;
      }
  
    return result;
*************** simplify_aggr_init_expr (tree *tp)
*** 2722,2728 ****
    tree fn = TREE_OPERAND (aggr_init_expr, 0);
    tree args = TREE_OPERAND (aggr_init_expr, 1);
    tree slot = TREE_OPERAND (aggr_init_expr, 2);
!   tree type = TREE_TYPE (aggr_init_expr);
  
    tree call_expr;
    enum style_t { ctor, arg, pcc } style;
--- 2738,2744 ----
    tree fn = TREE_OPERAND (aggr_init_expr, 0);
    tree args = TREE_OPERAND (aggr_init_expr, 1);
    tree slot = TREE_OPERAND (aggr_init_expr, 2);
!   tree type = TREE_TYPE (slot);
  
    tree call_expr;
    enum style_t { ctor, arg, pcc } style;
*************** simplify_aggr_init_expr (tree *tp)
*** 2750,2756 ****
  	args = TREE_CHAIN (args);
  
        cxx_mark_addressable (slot);
!       addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot);
        if (style == arg)
  	{
  	  /* The return type might have different cv-quals from the slot.  */
--- 2766,2772 ----
  	args = TREE_CHAIN (args);
  
        cxx_mark_addressable (slot);
!       addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
        if (style == arg)
  	{
  	  /* The return type might have different cv-quals from the slot.  */
*************** simplify_aggr_init_expr (tree *tp)
*** 2785,2794 ****
        pop_deferring_access_checks ();
      }
  
-   /* We want to use the value of the initialized location as the
-      result.  */
-   call_expr = build (COMPOUND_EXPR, type, call_expr, slot);
- 
    *tp = call_expr;
  }
  
--- 2801,2806 ----
Index: gcc/cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.378
diff -c -p -r1.378 tree.c
*** gcc/cp/tree.c	16 Jun 2004 20:51:46 -0000	1.378
--- gcc/cp/tree.c	17 Jun 2004 22:07:26 -0000
*************** build_cplus_new (tree type, tree init)
*** 302,308 ****
       type, don't mess with AGGR_INIT_EXPR.  */
    if (is_ctor || TREE_ADDRESSABLE (type))
      {
!       rval = build (AGGR_INIT_EXPR, type, fn, TREE_OPERAND (init, 1), slot);
        TREE_SIDE_EFFECTS (rval) = 1;
        AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
      }
--- 302,309 ----
       type, don't mess with AGGR_INIT_EXPR.  */
    if (is_ctor || TREE_ADDRESSABLE (type))
      {
!       rval = build (AGGR_INIT_EXPR, void_type_node, fn,
! 		    TREE_OPERAND (init, 1), slot);
        TREE_SIDE_EFFECTS (rval) = 1;
        AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
      }
Index: gcc/doc/c-tree.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/c-tree.texi,v
retrieving revision 1.57
diff -c -p -r1.57 c-tree.texi
*** gcc/doc/c-tree.texi	17 Jun 2004 01:24:06 -0000	1.57
--- gcc/doc/c-tree.texi	17 Jun 2004 22:07:26 -0000
*************** depth-first preorder traversal of the ex
*** 2302,2309 ****
  @item TARGET_EXPR
  A @code{TARGET_EXPR} represents a temporary object.  The first operand
  is a @code{VAR_DECL} for the temporary variable.  The second operand is
! the initializer for the temporary.  The initializer is evaluated, and
! copied (bitwise) into the temporary.
  
  Often, a @code{TARGET_EXPR} occurs on the right-hand side of an
  assignment, or as the second operand to a comma-expression which is
--- 2302,2310 ----
  @item TARGET_EXPR
  A @code{TARGET_EXPR} represents a temporary object.  The first operand
  is a @code{VAR_DECL} for the temporary variable.  The second operand is
! the initializer for the temporary.  The initializer is evaluated and,
! if non-void, copied (bitwise) into the temporary.  If the initializer
! is void, that means that it will perform the initialization itself.
  
  Often, a @code{TARGET_EXPR} occurs on the right-hand side of an
  assignment, or as the second operand to a comma-expression which is
*************** cleanups.
*** 2329,2349 ****
  @item AGGR_INIT_EXPR
  An @code{AGGR_INIT_EXPR} represents the initialization as the return
  value of a function call, or as the result of a constructor.  An
! @code{AGGR_INIT_EXPR} will only appear as the second operand of a
! @code{TARGET_EXPR}.  The first operand to the @code{AGGR_INIT_EXPR} is
! the address of a function to call, just as in a @code{CALL_EXPR}.  The
! second operand are the arguments to pass that function, as a
! @code{TREE_LIST}, again in a manner similar to that of a
! @code{CALL_EXPR}.  The value of the expression is that returned by the
! function.
  
  If @code{AGGR_INIT_VIA_CTOR_P} holds of the @code{AGGR_INIT_EXPR}, then
  the initialization is via a constructor call.  The address of the third
  operand of the @code{AGGR_INIT_EXPR}, which is always a @code{VAR_DECL},
  is taken, and this value replaces the first argument in the argument
! list.  In this case, the value of the expression is the @code{VAR_DECL}
! given by the third operand to the @code{AGGR_INIT_EXPR}; constructors do
! not return a value.
  
  @item VTABLE_REF
  A @code{VTABLE_REF} indicates that the interior expression computes
--- 2330,2349 ----
  @item AGGR_INIT_EXPR
  An @code{AGGR_INIT_EXPR} represents the initialization as the return
  value of a function call, or as the result of a constructor.  An
! @code{AGGR_INIT_EXPR} will only appear as a full-expression, or as the
! second operand of a @code{TARGET_EXPR}.  The first operand to the
! @code{AGGR_INIT_EXPR} is the address of a function to call, just as in
! a @code{CALL_EXPR}.  The second operand are the arguments to pass that
! function, as a @code{TREE_LIST}, again in a manner similar to that of
! a @code{CALL_EXPR}.
  
  If @code{AGGR_INIT_VIA_CTOR_P} holds of the @code{AGGR_INIT_EXPR}, then
  the initialization is via a constructor call.  The address of the third
  operand of the @code{AGGR_INIT_EXPR}, which is always a @code{VAR_DECL},
  is taken, and this value replaces the first argument in the argument
! list.
! 
! In either case, the expression is void.
  
  @item VTABLE_REF
  A @code{VTABLE_REF} indicates that the interior expression computes
Index: gcc/testsuite/g++.dg/ext/stmtexpr1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/ext/stmtexpr1.C,v
retrieving revision 1.2
diff -c -p -r1.2 stmtexpr1.C
*** gcc/testsuite/g++.dg/ext/stmtexpr1.C	16 Jun 2004 01:21:38 -0000	1.2
--- gcc/testsuite/g++.dg/ext/stmtexpr1.C	17 Jun 2004 22:07:27 -0000
***************
*** 1,10 ****
- // { dg-do run { xfail *-*-* } }
- // { dg-options "" }
- 
  // Copyright (C) 2003 Free Software Foundation, Inc.
  // Contributed by Nathan Sidwell 30 Jul 2003 <nathan@codesourcery.com>
  
! // make statement expressions work properly
  
  extern "C" int printf (char const *, ...);
  extern "C" void abort ();
--- 1,10 ----
  // Copyright (C) 2003 Free Software Foundation, Inc.
  // Contributed by Nathan Sidwell 30 Jul 2003 <nathan@codesourcery.com>
  
! // make sure statement expressions work properly
! 
! // { dg-do run }
! // { dg-options "" }
  
  extern "C" int printf (char const *, ...);
  extern "C" void abort ();
*************** int main ()
*** 51,54 ****
    ({A<14> a; a; });
    Check (0, 0, 0, "end");
  }
- 
--- 51,53 ----

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