summaryrefslogtreecommitdiff
path: root/gcc/cp/semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/semantics.c')
-rw-r--r--gcc/cp/semantics.c52
1 files changed, 32 insertions, 20 deletions
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;
}