This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for 16015: fix g++.dg/ext/stmtexpr1.C
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Thu, 17 Jun 2004 18:34:10 -0400
- Subject: C++ PATCH for 16015: fix g++.dg/ext/stmtexpr1.C
rth's recent change to make the C/C++ front ends use STATEMENT_LISTs
internally broke stmtexpr1.C; the problem turned out to be that we were
losing the CLEANUP_POINT_EXPR that was previously added in
gimplify_stmt_expr.
However, the fix wasn't as easy as just adding it to finish_stmt_expr,
because that led to the gimplifier trying to generate another temporary.
To avoid this, I have declared that the initializer operand to TARGET_EXPR
can be void, and made AGGR_INIT_EXPRs void to match. This simplifies
things enormously; there are hacks throughout the compiler to deal with
this case that can now go away.
Tested x86_64-pc-linux-gnu, applied to trunk.
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.
* 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.
Index: gcc/expr.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/expr.c,v
retrieving revision 1.652
diff -c -p -r1.652 expr.c
*** gcc/expr.c 16 Jun 2004 07:25:52 -0000 1.652
--- gcc/expr.c 17 Jun 2004 22:07:25 -0000
*************** expand_expr_real_1 (tree exp, rtx target
*** 8862,8868 ****
/* Mark it as expanded. */
TREE_OPERAND (exp, 1) = NULL_TREE;
! store_expr (exp1, target, modifier == EXPAND_STACK_PARM ? 2 : 0);
expand_decl_cleanup_eh (NULL_TREE, cleanups, CLEANUP_EH_ONLY (exp));
--- 8862,8873 ----
/* Mark it as expanded. */
TREE_OPERAND (exp, 1) = NULL_TREE;
! 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: gcc/gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.16
diff -c -p -r2.16 gimplify.c
*** gcc/gimplify.c 16 Jun 2004 01:21:25 -0000 2.16
--- gcc/gimplify.c 17 Jun 2004 22:07:25 -0000
*************** gimplify_target_expr (tree *expr_p, tree
*** 3018,3024 ****
gimplify_bind_expr (&init, temp, pre_p);
if (init != temp)
{
! 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;
--- 3018,3025 ----
gimplify_bind_expr (&init, temp, pre_p);
if (init != temp)
{
! 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: gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.78
diff -c -p -r1.78 tree.def
*** gcc/tree.def 15 Jun 2004 18:37:34 -0000 1.78
--- gcc/tree.def 17 Jun 2004 22:07:25 -0000
*************** DEFTREECODE (MODIFY_EXPR, "modify_expr",
*** 435,444 ****
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. */
DEFTREECODE (TARGET_EXPR, "target_expr", 'e', 4)
/* Conditional expression ( ... ? ... : ... in C).
--- 435,445 ----
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, 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).
Index: gcc/cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.401
diff -c -p -r1.401 semantics.c
*** gcc/cp/semantics.c 17 Jun 2004 01:24:06 -0000 1.401
--- gcc/cp/semantics.c 17 Jun 2004 22:07:26 -0000
*************** tree
*** 1374,1387 ****
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)))
{
if (TREE_CODE (type) == ARRAY_TYPE
|| TREE_CODE (type) == FUNCTION_TYPE)
expr = decay_conversion (expr);
--- 1374,1386 ----
finish_stmt_expr_expr (tree expr, tree stmt_expr)
{
tree result = NULL_TREE;
if (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);
*************** finish_stmt_expr_expr (tree expr, tree s
*** 1389,1394 ****
--- 1388,1395 ----
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
*************** finish_stmt_expr (tree stmt_expr, bool h
*** 1489,1513 ****
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)
{
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)))
;
else
abort ();
}
else if (TREE_CODE (result) == STATEMENT_LIST)
! result = build (BIND_EXPR, TREE_TYPE (last_expr), NULL, result, NULL);
! TREE_OPERAND (last_expr, 1) = result;
! result = last_expr;
}
return result;
--- 1490,1529 ----
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 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) = type;
! else if (same_type_p (TREE_TYPE (result), type))
;
else
abort ();
}
else if (TREE_CODE (result) == STATEMENT_LIST)
! /* 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 (target_expr, 1) = result;
! result = target_expr;
}
return result;
*************** simplify_aggr_init_expr (tree *tp)
*** 2722,2728 ****
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 call_expr;
enum style_t { ctor, arg, pcc } style;
--- 2738,2744 ----
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 (slot);
tree call_expr;
enum style_t { ctor, arg, pcc } style;
*************** simplify_aggr_init_expr (tree *tp)
*** 2750,2756 ****
args = TREE_CHAIN (args);
cxx_mark_addressable (slot);
! addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot);
if (style == arg)
{
/* The return type might have different cv-quals from the slot. */
--- 2766,2772 ----
args = TREE_CHAIN (args);
cxx_mark_addressable (slot);
! addr = build1 (ADDR_EXPR, build_pointer_type (type), slot);
if (style == arg)
{
/* The return type might have different cv-quals from the slot. */
*************** simplify_aggr_init_expr (tree *tp)
*** 2785,2794 ****
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;
}
--- 2801,2806 ----
Index: gcc/cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.378
diff -c -p -r1.378 tree.c
*** gcc/cp/tree.c 16 Jun 2004 20:51:46 -0000 1.378
--- gcc/cp/tree.c 17 Jun 2004 22:07:26 -0000
*************** build_cplus_new (tree type, tree init)
*** 302,308 ****
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);
TREE_SIDE_EFFECTS (rval) = 1;
AGGR_INIT_VIA_CTOR_P (rval) = is_ctor;
}
--- 302,309 ----
type, don't mess with AGGR_INIT_EXPR. */
if (is_ctor || TREE_ADDRESSABLE (type))
{
! 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: gcc/doc/c-tree.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/c-tree.texi,v
retrieving revision 1.57
diff -c -p -r1.57 c-tree.texi
*** gcc/doc/c-tree.texi 17 Jun 2004 01:24:06 -0000 1.57
--- gcc/doc/c-tree.texi 17 Jun 2004 22:07:26 -0000
*************** depth-first preorder traversal of the ex
*** 2302,2309 ****
@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.
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
--- 2302,2310 ----
@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,
! 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
*************** cleanups.
*** 2329,2349 ****
@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.
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.
@item VTABLE_REF
A @code{VTABLE_REF} indicates that the interior expression computes
--- 2330,2349 ----
@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 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 either case, the expression is void.
@item VTABLE_REF
A @code{VTABLE_REF} indicates that the interior expression computes
Index: gcc/testsuite/g++.dg/ext/stmtexpr1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/ext/stmtexpr1.C,v
retrieving revision 1.2
diff -c -p -r1.2 stmtexpr1.C
*** gcc/testsuite/g++.dg/ext/stmtexpr1.C 16 Jun 2004 01:21:38 -0000 1.2
--- gcc/testsuite/g++.dg/ext/stmtexpr1.C 17 Jun 2004 22:07:27 -0000
***************
*** 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
extern "C" int printf (char const *, ...);
extern "C" void abort ();
--- 1,10 ----
// Copyright (C) 2003 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 30 Jul 2003 <nathan@codesourcery.com>
! // make sure statement expressions work properly
!
! // { dg-do run }
! // { dg-options "" }
extern "C" int printf (char const *, ...);
extern "C" void abort ();
*************** int main ()
*** 51,54 ****
({A<14> a; a; });
Check (0, 0, 0, "end");
}
-
--- 51,53 ----