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:
parent
6ffbdf03e5
commit
2692eb7d0e
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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).
|
||||
|
Loading…
Reference in New Issue
Block a user