From 2692eb7d0ea1757cbf2508f001be9ee9f2f87ed3 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Thu, 17 Jun 2004 18:35:55 -0400 Subject: [PATCH] re PR c++/16015 (xfailed g++.dg/ext/stmtexpr1.C) 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 | 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 946ef76dfbe..aadf8534b36 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2004-06-17 Jason Merrill + + 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 * fold-const.c (fold_relational_const): Use constant_boolean_node. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1c1f0d660cd..b8f955c790d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,12 @@ +2004-06-17 Jason Merrill + + 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 * 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 271092a6c24..ec5ef7a3c41 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 c06810e0a3e..61f751aa3f6 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 3a7fd58b241..dae858a4292 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 a3f89a1d2ed..651d6cd0142 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 b0a2aa67c12..45d5e6ec1a9 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 ad14a238b83..fe9f3c3aa89 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 -// 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 5c40c8a163f..3e911113ee4 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). -- 2.30.2