From bbdcc797eafc57ef68c5dff12bff63f780cffcd1 Mon Sep 17 00:00:00 2001
From: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Thu, 17 Jun 2004 22:35:55 +0000
Subject: [PATCH]         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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@83320 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/ChangeLog                        |  8 +++++
 gcc/cp/ChangeLog                     |  9 +++++
 gcc/cp/semantics.c                   | 52 +++++++++++++++++-----------
 gcc/cp/tree.c                        |  3 +-
 gcc/doc/c-tree.texi                  | 24 ++++++-------
 gcc/expr.c                           |  7 +++-
 gcc/gimplify.c                       |  3 +-
 gcc/testsuite/g++.dg/ext/stmtexpr1.C |  9 +++--
 gcc/tree.def                         |  9 ++---
 9 files changed, 80 insertions(+), 44 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 946ef76dfbe1..aadf8534b363 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+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.
+
 2004-06-17  Roger Sayle  <roger@eyesopen.com>
 
 	* fold-const.c (fold_relational_const): Use constant_boolean_node.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 1c1f0d660cda..b8f955c790d1 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,12 @@
+2004-06-17  Jason Merrill  <jason@redhat.com>
+
+	PR c++/16015
+	* 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.
+	* tree.c (build_cplus_new): Make AGGR_INIT_EXPRs void.
+
 2004-06-17  Geoffrey Keating  <geoffk@apple.com>
 
 	* class.c (build_clone): Don't call defer_fn, let mark_used do it.
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 271092a6c241..ec5ef7a3c414 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -1374,14 +1374,13 @@ tree
 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)))
 	{
+	  tree type = TREE_TYPE (expr);
+
 	  if (TREE_CODE (type) == ARRAY_TYPE
 	      || TREE_CODE (type) == FUNCTION_TYPE)
 	    expr = decay_conversion (expr);
@@ -1389,6 +1388,8 @@ finish_stmt_expr_expr (tree expr, tree stmt_expr)
 	  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
@@ -1489,25 +1490,40 @@ finish_stmt_expr (tree stmt_expr, bool has_no_scope)
 	 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)
+      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) = TREE_TYPE (last_expr);
-	  else if (same_type_p (TREE_TYPE (result), TREE_TYPE (last_expr)))
+	    TREE_TYPE (result) = type;
+	  else if (same_type_p (TREE_TYPE (result), type))
 	    ;
 	  else
 	    abort ();
 	}
       else if (TREE_CODE (result) == STATEMENT_LIST)
-	result = build (BIND_EXPR, TREE_TYPE (last_expr), NULL, result, NULL);
+	/* 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 (last_expr, 1) = result;
-      result = last_expr;
+      TREE_OPERAND (target_expr, 1) = result;
+      result = target_expr;
     }
 
   return result;
@@ -2722,7 +2738,7 @@ simplify_aggr_init_expr (tree *tp)
   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 type = TREE_TYPE (slot);
 
   tree call_expr;
   enum style_t { ctor, arg, pcc } style;
@@ -2750,7 +2766,7 @@ simplify_aggr_init_expr (tree *tp)
 	args = TREE_CHAIN (args);
 
       cxx_mark_addressable (slot);
-      addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot);
+      addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
       if (style == arg)
 	{
 	  /* The return type might have different cv-quals from the slot.  */
@@ -2785,10 +2801,6 @@ simplify_aggr_init_expr (tree *tp)
       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;
 }
 
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index c06810e0a3e9..61f751aa3f69 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -302,7 +302,8 @@ build_cplus_new (tree type, tree init)
      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);
+      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;
     }
diff --git a/gcc/doc/c-tree.texi b/gcc/doc/c-tree.texi
index 3a7fd58b2414..dae858a42924 100644
--- a/gcc/doc/c-tree.texi
+++ b/gcc/doc/c-tree.texi
@@ -2302,8 +2302,9 @@ depth-first preorder traversal of the expression tree.
 @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.
+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
@@ -2329,21 +2330,20 @@ cleanups.
 @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.
+@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 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.
+list.
+
+In either case, the expression is void.
 
 @item VTABLE_REF
 A @code{VTABLE_REF} indicates that the interior expression computes
diff --git a/gcc/expr.c b/gcc/expr.c
index a3f89a1d2edc..651d6cd01423 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -8862,7 +8862,12 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
 	/* Mark it as expanded.  */
 	TREE_OPERAND (exp, 1) = NULL_TREE;
 
-	store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
+	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));
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index b0a2aa67c124..45d5e6ec1a9c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -3018,7 +3018,8 @@ gimplify_target_expr (tree *expr_p, tree *pre_p, tree *post_p)
 	gimplify_bind_expr (&init, temp, pre_p);
       if (init != temp)
 	{
-	  init = build (MODIFY_EXPR, void_type_node, temp, init);
+	  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;
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr1.C b/gcc/testsuite/g++.dg/ext/stmtexpr1.C
index ad14a238b834..fe9f3c3aa89c 100644
--- a/gcc/testsuite/g++.dg/ext/stmtexpr1.C
+++ b/gcc/testsuite/g++.dg/ext/stmtexpr1.C
@@ -1,10 +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
+// make sure statement expressions work properly
+
+// { dg-do run }
+// { dg-options "" }
 
 extern "C" int printf (char const *, ...);
 extern "C" void abort ();
@@ -51,4 +51,3 @@ int main ()
   ({A<14> a; a; });
   Check (0, 0, 0, "end");
 }
-
diff --git a/gcc/tree.def b/gcc/tree.def
index 5c40c8a163fa..3e911113ee4a 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -435,10 +435,11 @@ DEFTREECODE (MODIFY_EXPR, "modify_expr", 'e', 2)
 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.  */
+   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).
-- 
GitLab