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
This commit is contained in:
Jason Merrill 2004-06-17 18:35:55 -04:00 committed by Jason Merrill
parent 6ffbdf03e5
commit 2692eb7d0e
9 changed files with 79 additions and 43 deletions

View 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.

View 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.

View 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);
tree init, target_expr = EXPR_STMT_EXPR (result_stmt);
my_friendly_assert (TREE_CODE (target_expr) == TARGET_EXPR, 20030729);
if (TREE_CODE (result) == BIND_EXPR)
/* 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;
}

View 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;
}

View 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

View 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));

View 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;

View 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");
}

View 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).