re PR c++/16015 (xfailed g++.dg/ext/stmtexpr1.C)
authorJason Merrill <jason@redhat.com>
Thu, 17 Jun 2004 22:35:55 +0000 (18:35 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Thu, 17 Jun 2004 22:35:55 +0000 (18:35 -0400)
        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.

From-SVN: r83320

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/cp/tree.c
gcc/doc/c-tree.texi
gcc/expr.c
gcc/gimplify.c
gcc/testsuite/g++.dg/ext/stmtexpr1.C
gcc/tree.def

index 946ef76dfbe1c433a3307b027e1022638107a1d3..aadf8534b3631b4f8b622380309ff1452eaa31e4 100644 (file)
@@ -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.
index 1c1f0d660cda0185dd6c11378797109e1890814e..b8f955c790d13f35228538b3c3a872109c9116ea 100644 (file)
@@ -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.
index 271092a6c2414460a8a5b1820ca4b8bcd6dd8a79..ec5ef7a3c4147aba4faf8d6fb86173348d26255d 100644 (file)
@@ -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;
 }
 
index c06810e0a3e97a7e3fb977fe98213581b2ad69c2..61f751aa3f69b116495e4eb30a24f1476fe49506 100644 (file)
@@ -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;
     }
index 3a7fd58b241458231c3088aec1e8da29be16f35c..dae858a42924e9b97aa3ee4d123d36301b229844 100644 (file)
@@ -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
index a3f89a1d2edc9335067383d74e5c6635bf278b4f..651d6cd01423080e46e098162cedf4c0c2c6aa73 100644 (file)
@@ -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));
 
index b0a2aa67c12416b810694d9d6328646b8111f5c5..45d5e6ec1a9c962df896482881bef5d3d99981dd 100644 (file)
@@ -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;
index ad14a238b83497360e7de2fda1249d279bcc7462..fe9f3c3aa89cacfc92c6583f2d78aab099718139 100644 (file)
@@ -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");
 }
-
index 5c40c8a163fa4cbd8e540f2ca6f08ab28d2a4cd2..3e911113ee4a4690b8fa1b1d9d338ba616d832f6 100644 (file)
@@ -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).