Commit a5bcc582 by Nathan Sidwell Committed by Nathan Sidwell

re PR c++/11295 (ICE when using a non-trivial object in a compound statement expression)

	PR c++/11295
	* doc/extend.texi (Statement Expressions): Document C++ semantics.
cp:
	PR c++/11295
	* cp-tree.h (tubst_flags_t): Add tf_stmt_expr_cmpd,
	tf_stmt_expr_body.
	(finish_stmt_expr_expr): Declare.
	* parser.c (cp_parser_primary_expression): Tell
	cp_parser_compount_statement that it is a statement expression.
	(cp_parser_statement, cp_parser_labeled_statement,
	cp_parser_compound_statement, cp_parser_statement_seq_opt): Add
	in_statement_expr_p parameter.
	(cp_parser_expression_statement): Likewise. Call
	finish_stmt_expr_expr for final expression of a statement
	expression.
	(cp_parser_for_init_statement,
	cp_parser_implicitly_scoped_statement,
	cp_parser_already_scoped_statement, cp_parser_function_definition,
	cp_parser_try_block, cp_parser_handled): Adjust.
	* pt.c (tsubst_copy) <STMT_EXPR case>: Pass tf_stmt_expr.
	(tsubst_expr): Process tf_stmt_expr and tf_stmt_exprs flags.
	(tsubst_expr) <EXPR_STMT case>: Check tf_stmt_exprs flag.
	* semantics.c (finish_expr_stmt): Do not deal with statement
	expressions.
	(begin_stmt_expr): Clear last_expr_type.
	(finish_stmt_expr_expr): New.
	(finish_stmt_expr): Process the value expression.
testsuite:
	PR c++/11295
	* g++.dg/ext/stmtexpr1.C: New test.

From-SVN: r70043
parent d340e53f
2003-08-01 Nathan Sidwell <nathan@codesourcery.com>
PR c++/11295
* doc/extend.texi (Statement Expressions): Document C++ semantics.
2003-07-31 SUGIOKA Toshinobu <sugioka@itonet.co.jp> 2003-07-31 SUGIOKA Toshinobu <sugioka@itonet.co.jp>
* config.gcc (sh-*-linux*): Do not override sh/t-linux with sh/t-le. * config.gcc (sh-*-linux*): Do not override sh/t-linux with sh/t-le.
......
2003-08-01 Nathan Sidwell <nathan@codesourcery.com> 2003-08-01 Nathan Sidwell <nathan@codesourcery.com>
PR c++/11295
* cp-tree.h (tubst_flags_t): Add tf_stmt_expr_cmpd,
tf_stmt_expr_body.
(finish_stmt_expr_expr): Declare.
* parser.c (cp_parser_primary_expression): Tell
cp_parser_compount_statement that it is a statement expression.
(cp_parser_statement, cp_parser_labeled_statement,
cp_parser_compound_statement, cp_parser_statement_seq_opt): Add
in_statement_expr_p parameter.
(cp_parser_expression_statement): Likewise. Call
finish_stmt_expr_expr for final expression of a statement
expression.
(cp_parser_for_init_statement,
cp_parser_implicitly_scoped_statement,
cp_parser_already_scoped_statement, cp_parser_function_definition,
cp_parser_try_block, cp_parser_handled): Adjust.
* pt.c (tsubst_copy) <STMT_EXPR case>: Pass tf_stmt_expr.
(tsubst_expr): Process tf_stmt_expr and tf_stmt_exprs flags.
(tsubst_expr) <EXPR_STMT case>: Check tf_stmt_exprs flag.
* semantics.c (finish_expr_stmt): Do not deal with statement
expressions.
(begin_stmt_expr): Clear last_expr_type.
(finish_stmt_expr_expr): New.
(finish_stmt_expr): Process the value expression.
* typeck.c (build_compound_expr): If RHS is a TARGET_EXPR, put the * typeck.c (build_compound_expr): If RHS is a TARGET_EXPR, put the
compound expr inside the target's initializer. compound expr inside the target's initializer.
......
...@@ -3056,8 +3056,13 @@ typedef enum tsubst_flags_t { ...@@ -3056,8 +3056,13 @@ typedef enum tsubst_flags_t {
(make_typename_type use) */ (make_typename_type use) */
tf_ptrmem_ok = 1 << 4, /* pointers to member ok (internal tf_ptrmem_ok = 1 << 4, /* pointers to member ok (internal
instantiate_type use) */ instantiate_type use) */
tf_user = 1 << 5 /* Found template must be a user template tf_user = 1 << 5, /* found template must be a user template
(lookup_template_class use) */ (lookup_template_class use) */
tf_stmt_expr_cmpd = 1 << 6, /* tsubsting the compound statement of
a statement expr. */
tf_stmt_expr_body = 1 << 7 /* tsubsting the statements in the
body of the compound statement of a
statement expr. */
} tsubst_flags_t; } tsubst_flags_t;
/* The kind of checking we can do looking in a class hierarchy. */ /* The kind of checking we can do looking in a class hierarchy. */
...@@ -4134,6 +4139,7 @@ extern void finish_subobject (tree); ...@@ -4134,6 +4139,7 @@ extern void finish_subobject (tree);
extern tree finish_parenthesized_expr (tree); extern tree finish_parenthesized_expr (tree);
extern tree finish_non_static_data_member (tree, tree, tree); extern tree finish_non_static_data_member (tree, tree, tree);
extern tree begin_stmt_expr (void); extern tree begin_stmt_expr (void);
extern tree finish_stmt_expr_expr (tree);
extern tree finish_stmt_expr (tree); extern tree finish_stmt_expr (tree);
extern tree perform_koenig_lookup (tree, tree); extern tree perform_koenig_lookup (tree, tree);
extern tree finish_call_expr (tree, tree, bool); extern tree finish_call_expr (tree, tree, bool);
......
...@@ -1367,15 +1367,15 @@ static tree cp_parser_constant_expression ...@@ -1367,15 +1367,15 @@ static tree cp_parser_constant_expression
/* Statements [gram.stmt.stmt] */ /* Statements [gram.stmt.stmt] */
static void cp_parser_statement static void cp_parser_statement
(cp_parser *); (cp_parser *, bool);
static tree cp_parser_labeled_statement static tree cp_parser_labeled_statement
(cp_parser *); (cp_parser *, bool);
static tree cp_parser_expression_statement static tree cp_parser_expression_statement
(cp_parser *); (cp_parser *, bool);
static tree cp_parser_compound_statement static tree cp_parser_compound_statement
(cp_parser *); (cp_parser *, bool);
static void cp_parser_statement_seq_opt static void cp_parser_statement_seq_opt
(cp_parser *); (cp_parser *, bool);
static tree cp_parser_selection_statement static tree cp_parser_selection_statement
(cp_parser *); (cp_parser *);
static tree cp_parser_condition static tree cp_parser_condition
...@@ -2244,7 +2244,7 @@ cp_parser_primary_expression (cp_parser *parser, ...@@ -2244,7 +2244,7 @@ cp_parser_primary_expression (cp_parser *parser,
/* Start the statement-expression. */ /* Start the statement-expression. */
expr = begin_stmt_expr (); expr = begin_stmt_expr ();
/* Parse the compound-statement. */ /* Parse the compound-statement. */
cp_parser_compound_statement (parser); cp_parser_compound_statement (parser, true);
/* Finish up. */ /* Finish up. */
expr = finish_stmt_expr (expr); expr = finish_stmt_expr (expr);
} }
...@@ -5075,7 +5075,7 @@ cp_parser_constant_expression (cp_parser* parser, ...@@ -5075,7 +5075,7 @@ cp_parser_constant_expression (cp_parser* parser,
try-block */ try-block */
static void static void
cp_parser_statement (cp_parser* parser) cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
{ {
tree statement; tree statement;
cp_token *token; cp_token *token;
...@@ -5097,7 +5097,8 @@ cp_parser_statement (cp_parser* parser) ...@@ -5097,7 +5097,8 @@ cp_parser_statement (cp_parser* parser)
{ {
case RID_CASE: case RID_CASE:
case RID_DEFAULT: case RID_DEFAULT:
statement = cp_parser_labeled_statement (parser); statement = cp_parser_labeled_statement (parser,
in_statement_expr_p);
break; break;
case RID_IF: case RID_IF:
...@@ -5134,11 +5135,11 @@ cp_parser_statement (cp_parser* parser) ...@@ -5134,11 +5135,11 @@ cp_parser_statement (cp_parser* parser)
labeled-statement. */ labeled-statement. */
token = cp_lexer_peek_nth_token (parser->lexer, 2); token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_COLON) if (token->type == CPP_COLON)
statement = cp_parser_labeled_statement (parser); statement = cp_parser_labeled_statement (parser, in_statement_expr_p);
} }
/* Anything that starts with a `{' must be a compound-statement. */ /* Anything that starts with a `{' must be a compound-statement. */
else if (token->type == CPP_OPEN_BRACE) else if (token->type == CPP_OPEN_BRACE)
statement = cp_parser_compound_statement (parser); statement = cp_parser_compound_statement (parser, false);
/* Everything else must be a declaration-statement or an /* Everything else must be a declaration-statement or an
expression-statement. Try for the declaration-statement expression-statement. Try for the declaration-statement
...@@ -5156,7 +5157,7 @@ cp_parser_statement (cp_parser* parser) ...@@ -5156,7 +5157,7 @@ cp_parser_statement (cp_parser* parser)
return; return;
} }
/* Look for an expression-statement instead. */ /* Look for an expression-statement instead. */
statement = cp_parser_expression_statement (parser); statement = cp_parser_expression_statement (parser, in_statement_expr_p);
} }
/* Set the line number for the statement. */ /* Set the line number for the statement. */
...@@ -5175,7 +5176,7 @@ cp_parser_statement (cp_parser* parser) ...@@ -5175,7 +5176,7 @@ cp_parser_statement (cp_parser* parser)
an ordinary label, returns a LABEL_STMT. */ an ordinary label, returns a LABEL_STMT. */
static tree static tree
cp_parser_labeled_statement (cp_parser* parser) cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
{ {
cp_token *token; cp_token *token;
tree statement = NULL_TREE; tree statement = NULL_TREE;
...@@ -5222,7 +5223,7 @@ cp_parser_labeled_statement (cp_parser* parser) ...@@ -5222,7 +5223,7 @@ cp_parser_labeled_statement (cp_parser* parser)
/* Require the `:' token. */ /* Require the `:' token. */
cp_parser_require (parser, CPP_COLON, "`:'"); cp_parser_require (parser, CPP_COLON, "`:'");
/* Parse the labeled statement. */ /* Parse the labeled statement. */
cp_parser_statement (parser); cp_parser_statement (parser, in_statement_expr_p);
/* Return the label, in the case of a `case' or `default' label. */ /* Return the label, in the case of a `case' or `default' label. */
return statement; return statement;
...@@ -5234,25 +5235,35 @@ cp_parser_labeled_statement (cp_parser* parser) ...@@ -5234,25 +5235,35 @@ cp_parser_labeled_statement (cp_parser* parser)
expression [opt] ; expression [opt] ;
Returns the new EXPR_STMT -- or NULL_TREE if the expression Returns the new EXPR_STMT -- or NULL_TREE if the expression
statement consists of nothing more than an `;'. */ statement consists of nothing more than an `;'. IN_STATEMENT_EXPR_P
indicates whether this expression-statement is part of an
expression statement. */
static tree static tree
cp_parser_expression_statement (cp_parser* parser) cp_parser_expression_statement (cp_parser* parser, bool in_statement_expr_p)
{ {
tree statement; tree statement = NULL_TREE;
/* If the next token is not a `;', then there is an expression to parse. */ /* If the next token is a ';', then there is no expression
statement. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
statement = finish_expr_stmt (cp_parser_expression (parser)); statement = cp_parser_expression (parser);
/* Otherwise, we do not even bother to build an EXPR_STMT. */
else
{
finish_stmt ();
statement = NULL_TREE;
}
/* Consume the final `;'. */ /* Consume the final `;'. */
cp_parser_consume_semicolon_at_end_of_statement (parser); cp_parser_consume_semicolon_at_end_of_statement (parser);
if (in_statement_expr_p
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
{
/* This is the final expression statement of a statement
expression. */
statement = finish_stmt_expr_expr (statement);
}
else if (statement)
statement = finish_expr_stmt (statement);
else
finish_stmt ();
return statement; return statement;
} }
...@@ -5264,7 +5275,7 @@ cp_parser_expression_statement (cp_parser* parser) ...@@ -5264,7 +5275,7 @@ cp_parser_expression_statement (cp_parser* parser)
Returns a COMPOUND_STMT representing the statement. */ Returns a COMPOUND_STMT representing the statement. */
static tree static tree
cp_parser_compound_statement (cp_parser *parser) cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
{ {
tree compound_stmt; tree compound_stmt;
...@@ -5274,7 +5285,7 @@ cp_parser_compound_statement (cp_parser *parser) ...@@ -5274,7 +5285,7 @@ cp_parser_compound_statement (cp_parser *parser)
/* Begin the compound-statement. */ /* Begin the compound-statement. */
compound_stmt = begin_compound_stmt (/*has_no_scope=*/false); compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
/* Parse an (optional) statement-seq. */ /* Parse an (optional) statement-seq. */
cp_parser_statement_seq_opt (parser); cp_parser_statement_seq_opt (parser, in_statement_expr_p);
/* Finish the compound-statement. */ /* Finish the compound-statement. */
finish_compound_stmt (compound_stmt); finish_compound_stmt (compound_stmt);
/* Consume the `}'. */ /* Consume the `}'. */
...@@ -5290,7 +5301,7 @@ cp_parser_compound_statement (cp_parser *parser) ...@@ -5290,7 +5301,7 @@ cp_parser_compound_statement (cp_parser *parser)
statement-seq [opt] statement */ statement-seq [opt] statement */
static void static void
cp_parser_statement_seq_opt (cp_parser* parser) cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p)
{ {
/* Scan statements until there aren't any more. */ /* Scan statements until there aren't any more. */
while (true) while (true)
...@@ -5301,7 +5312,7 @@ cp_parser_statement_seq_opt (cp_parser* parser) ...@@ -5301,7 +5312,7 @@ cp_parser_statement_seq_opt (cp_parser* parser)
break; break;
/* Parse the statement. */ /* Parse the statement. */
cp_parser_statement (parser); cp_parser_statement (parser, in_statement_expr_p);
} }
} }
...@@ -5631,7 +5642,7 @@ cp_parser_for_init_statement (cp_parser* parser) ...@@ -5631,7 +5642,7 @@ cp_parser_for_init_statement (cp_parser* parser)
return; return;
} }
cp_parser_expression_statement (parser); cp_parser_expression_statement (parser, false);
} }
/* Parse a jump-statement. /* Parse a jump-statement.
...@@ -5756,13 +5767,13 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser) ...@@ -5756,13 +5767,13 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser)
/* Create a compound-statement. */ /* Create a compound-statement. */
statement = begin_compound_stmt (/*has_no_scope=*/false); statement = begin_compound_stmt (/*has_no_scope=*/false);
/* Parse the dependent-statement. */ /* Parse the dependent-statement. */
cp_parser_statement (parser); cp_parser_statement (parser, false);
/* Finish the dummy compound-statement. */ /* Finish the dummy compound-statement. */
finish_compound_stmt (statement); finish_compound_stmt (statement);
} }
/* Otherwise, we simply parse the statement directly. */ /* Otherwise, we simply parse the statement directly. */
else else
statement = cp_parser_compound_statement (parser); statement = cp_parser_compound_statement (parser, false);
/* Return the statement. */ /* Return the statement. */
return statement; return statement;
...@@ -5784,13 +5795,13 @@ cp_parser_already_scoped_statement (cp_parser* parser) ...@@ -5784,13 +5795,13 @@ cp_parser_already_scoped_statement (cp_parser* parser)
/* Create a compound-statement. */ /* Create a compound-statement. */
statement = begin_compound_stmt (/*has_no_scope=*/true); statement = begin_compound_stmt (/*has_no_scope=*/true);
/* Parse the dependent-statement. */ /* Parse the dependent-statement. */
cp_parser_statement (parser); cp_parser_statement (parser, false);
/* Finish the dummy compound-statement. */ /* Finish the dummy compound-statement. */
finish_compound_stmt (statement); finish_compound_stmt (statement);
} }
/* Otherwise, we simply parse the statement directly. */ /* Otherwise, we simply parse the statement directly. */
else else
cp_parser_statement (parser); cp_parser_statement (parser, false);
} }
/* Declarations [gram.dcl.dcl] */ /* Declarations [gram.dcl.dcl] */
...@@ -10693,7 +10704,7 @@ cp_parser_function_definition (cp_parser* parser, bool* friend_p) ...@@ -10693,7 +10704,7 @@ cp_parser_function_definition (cp_parser* parser, bool* friend_p)
static void static void
cp_parser_function_body (cp_parser *parser) cp_parser_function_body (cp_parser *parser)
{ {
cp_parser_compound_statement (parser); cp_parser_compound_statement (parser, false);
} }
/* Parse a ctor-initializer-opt followed by a function-body. Return /* Parse a ctor-initializer-opt followed by a function-body. Return
...@@ -12244,7 +12255,7 @@ cp_parser_try_block (cp_parser* parser) ...@@ -12244,7 +12255,7 @@ cp_parser_try_block (cp_parser* parser)
cp_parser_require_keyword (parser, RID_TRY, "`try'"); cp_parser_require_keyword (parser, RID_TRY, "`try'");
try_block = begin_try_block (); try_block = begin_try_block ();
cp_parser_compound_statement (parser); cp_parser_compound_statement (parser, false);
finish_try_block (try_block); finish_try_block (try_block);
cp_parser_handler_seq (parser); cp_parser_handler_seq (parser);
finish_handler_sequence (try_block); finish_handler_sequence (try_block);
...@@ -12320,7 +12331,7 @@ cp_parser_handler (cp_parser* parser) ...@@ -12320,7 +12331,7 @@ cp_parser_handler (cp_parser* parser)
declaration = cp_parser_exception_declaration (parser); declaration = cp_parser_exception_declaration (parser);
finish_handler_parms (declaration, handler); finish_handler_parms (declaration, handler);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"); cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
cp_parser_compound_statement (parser); cp_parser_compound_statement (parser, false);
finish_handler (handler); finish_handler (handler);
} }
......
...@@ -7403,7 +7403,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -7403,7 +7403,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (!processing_template_decl) if (!processing_template_decl)
{ {
tree stmt_expr = begin_stmt_expr (); tree stmt_expr = begin_stmt_expr ();
tsubst_expr (STMT_EXPR_STMT (t), args, complain, in_decl);
tsubst_expr (STMT_EXPR_STMT (t), args,
complain | tf_stmt_expr_cmpd, in_decl);
return finish_stmt_expr (stmt_expr); return finish_stmt_expr (stmt_expr);
} }
...@@ -7530,7 +7532,10 @@ static tree ...@@ -7530,7 +7532,10 @@ static tree
tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
{ {
tree stmt, tmp; tree stmt, tmp;
tsubst_flags_t stmt_expr
= complain & (tf_stmt_expr_cmpd | tf_stmt_expr_body);
complain ^= stmt_expr;
if (t == NULL_TREE || t == error_mark_node) if (t == NULL_TREE || t == error_mark_node)
return t; return t;
...@@ -7556,10 +7561,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -7556,10 +7561,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
break; break;
case EXPR_STMT: case EXPR_STMT:
prep_stmt (t); {
finish_expr_stmt (tsubst_expr (EXPR_STMT_EXPR (t), tree r;
args, complain, in_decl));
break; prep_stmt (t);
r = tsubst_expr (EXPR_STMT_EXPR (t), args, complain, in_decl);
if (stmt_expr & tf_stmt_expr_body && !TREE_CHAIN (t))
finish_stmt_expr_expr (r);
else
finish_expr_stmt (r);
break;
}
case USING_STMT: case USING_STMT:
prep_stmt (t); prep_stmt (t);
...@@ -7711,7 +7724,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -7711,7 +7724,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
else else
stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t)); stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl); tsubst_expr (COMPOUND_BODY (t), args,
complain | ((stmt_expr & tf_stmt_expr_cmpd) << 1),
in_decl);
if (COMPOUND_STMT_BODY_BLOCK (t)) if (COMPOUND_STMT_BODY_BLOCK (t))
finish_function_body (stmt); finish_function_body (stmt);
...@@ -7849,7 +7864,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) ...@@ -7849,7 +7864,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
abort (); abort ();
} }
return tsubst_expr (TREE_CHAIN (t), args, complain, in_decl); return tsubst_expr (TREE_CHAIN (t), args, complain | stmt_expr, in_decl);
} }
/* T is a postfix-expression that is not being used in a function /* T is a postfix-expression that is not being used in a function
......
...@@ -416,21 +416,10 @@ tree ...@@ -416,21 +416,10 @@ tree
finish_expr_stmt (tree expr) finish_expr_stmt (tree expr)
{ {
tree r = NULL_TREE; tree r = NULL_TREE;
tree expr_type = NULL_TREE;;
if (expr != NULL_TREE) if (expr != NULL_TREE)
{ {
if (!processing_template_decl if (!processing_template_decl)
&& !(stmts_are_full_exprs_p ())
&& ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
&& lvalue_p (expr))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE))
expr = decay_conversion (expr);
/* Remember the type of the expression. */
expr_type = TREE_TYPE (expr);
if (!processing_template_decl && stmts_are_full_exprs_p ())
expr = convert_to_void (expr, "statement"); expr = convert_to_void (expr, "statement");
r = add_stmt (build_stmt (EXPR_STMT, expr)); r = add_stmt (build_stmt (EXPR_STMT, expr));
...@@ -438,10 +427,6 @@ finish_expr_stmt (tree expr) ...@@ -438,10 +427,6 @@ finish_expr_stmt (tree expr)
finish_stmt (); finish_stmt ();
/* This was an expression-statement, so we save the type of the
expression. */
last_expr_type = expr_type;
return r; return r;
} }
...@@ -1415,14 +1400,73 @@ begin_stmt_expr (void) ...@@ -1415,14 +1400,73 @@ begin_stmt_expr (void)
if (! cfun && !last_tree) if (! cfun && !last_tree)
begin_stmt_tree (&scope_chain->x_saved_tree); begin_stmt_tree (&scope_chain->x_saved_tree);
last_expr_type = NULL_TREE;
keep_next_level (1); keep_next_level (1);
/* If we're building a statement tree, then the upcoming compound
statement will be chained onto the tree structure, starting at
last_tree. We return last_tree so that we can later unhook the
compound statement. */
return last_tree; return last_tree;
} }
/* Process the final expression of a statement expression. EXPR can be
NULL, if the final expression is empty. Build up a TARGET_EXPR so
that the result value can be safely returned to the enclosing
expression. */
tree
finish_stmt_expr_expr (tree 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);
expr = convert_from_reference (expr);
expr = require_complete_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 expresson containing this statement
expression. */
if (TREE_CODE (expr) == TARGET_EXPR)
;
else if (!IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_INIT_REF (type))
expr = build_target_expr_with_type (expr, type);
else
{
/* Copy construct. */
expr = build_special_member_call
(NULL_TREE, complete_ctor_identifier,
build_tree_list (NULL_TREE, expr),
TYPE_BINFO (type), LOOKUP_NORMAL);
expr = build_cplus_new (type, expr);
my_friendly_assert (TREE_CODE (expr) == TARGET_EXPR, 20030729);
}
}
if (expr != error_mark_node)
{
result = build_stmt (EXPR_STMT, expr);
add_stmt (result);
}
}
finish_stmt ();
/* Remember the last expression so that finish_stmt_expr can pull it
apart. */
last_expr_type = result ? result : void_type_node;
return result;
}
/* Finish a statement-expression. RTL_EXPR should be the value /* Finish a statement-expression. RTL_EXPR should be the value
returned by the previous begin_stmt_expr; EXPR is the returned by the previous begin_stmt_expr; EXPR is the
statement-expression. Returns an expression representing the statement-expression. Returns an expression representing the
...@@ -1432,18 +1476,27 @@ tree ...@@ -1432,18 +1476,27 @@ tree
finish_stmt_expr (tree rtl_expr) finish_stmt_expr (tree rtl_expr)
{ {
tree result; tree result;
tree result_stmt = last_expr_type;
/* If the last thing in the statement-expression was not an tree type;
expression-statement, then it has type `void'. In a template, we
cannot distinguish the case where the last expression-statement if (!last_expr_type)
had a dependent type from the case where the last statement was type = void_type_node;
not an expression-statement. Therefore, we (incorrectly) treat else
the STMT_EXPR as dependent in that case. */ {
if (!last_expr_type && !processing_template_decl) if (result_stmt == void_type_node)
last_expr_type = void_type_node; {
result = build_min (STMT_EXPR, last_expr_type, last_tree); type = void_type_node;
result_stmt = NULL_TREE;
}
else
type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt));
}
result = build_min (STMT_EXPR, type, last_tree);
TREE_SIDE_EFFECTS (result) = 1; TREE_SIDE_EFFECTS (result) = 1;
last_expr_type = NULL_TREE;
/* Remove the compound statement from the tree structure; it is /* Remove the compound statement from the tree structure; it is
now saved in the STMT_EXPR. */ now saved in the STMT_EXPR. */
last_tree = rtl_expr; last_tree = rtl_expr;
...@@ -1455,6 +1508,22 @@ finish_stmt_expr (tree rtl_expr) ...@@ -1455,6 +1508,22 @@ finish_stmt_expr (tree rtl_expr)
&& TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE) && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE)
finish_stmt_tree (&scope_chain->x_saved_tree); finish_stmt_tree (&scope_chain->x_saved_tree);
if (processing_template_decl)
return result;
if (!VOID_TYPE_P (type))
{
/* Pull out the TARGET_EXPR that is the final expression. Put
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);
EXPR_STMT_EXPR (result_stmt) = TREE_OPERAND (last_expr, 1);
TREE_OPERAND (last_expr, 1) = result;
result = last_expr;
}
return result; return result;
} }
......
...@@ -539,32 +539,46 @@ the initial value of a static variable. ...@@ -539,32 +539,46 @@ the initial value of a static variable.
If you don't know the type of the operand, you can still do this, but you If you don't know the type of the operand, you can still do this, but you
must use @code{typeof} (@pxref{Typeof}). must use @code{typeof} (@pxref{Typeof}).
Statement expressions are not supported fully in G++, and their fate In G++, the result value of a statement expression undergoes array and
there is unclear. (It is possible that they will become fully supported function pointer decay, and is returned by value to the enclosing
at some point, or that they will be deprecated, or that the bugs that expression. For instance, if @code{A} is a class, then
are present will continue to exist indefinitely.) Presently, statement
expressions do not work well as default arguments.
In addition, there are semantic issues with statement-expressions in @smallexample
C++. If you try to use statement-expressions instead of inline A a;
functions in C++, you may be surprised at the way object destruction is
handled. For example:
@example (@{a;@}).Foo ()
#define foo(a) (@{int b = (a); b + 3; @}) @end smallexample
@end example
@noindent @noindent
does not work the same way as: will construct a temporary @code{A} object to hold the result of the
statement expression, and that will be used to invoke @code{Foo}.
Therefore the @code{this} pointer observed by @code{Foo} will not be the
address of @code{a}.
Any temporaries created within a statement within a statement expression
will be destroyed at the statement's end. This makes statement
expressions inside macros slightly different from function calls. In
the latter case temporaries introduced during argument evaluation will
be destroyed at the end of the statement that includes the function
call. In the statement expression case they will be destroyed during
the statement expression. For instance,
@example @smallexample
inline int foo(int a) @{ int b = a; return b + 3; @} #define macro(a) (@{__typeof__(a) b = (a); b + 3; @})
@end example template<typename T> T function(T a) @{ T b = a; return b + 3; @}
void foo ()
@{
macro (X ());
function (X ());
@}
@end smallexample
@noindent @noindent
In particular, if the expression passed into @code{foo} involves the will have different places where temporaries are destroyed. For the
creation of temporaries, the destructors for those temporaries will be @code{macro} case, the temporary @code{X} will be destroyed just after
run earlier in the case of the macro than in the case of the function. the initialization of @code{b}. In the @code{function} case that
temporary will be destroyed when the function returns.
These considerations mean that it is probably a bad idea to use These considerations mean that it is probably a bad idea to use
statement-expressions of this form in header files that are designed to statement-expressions of this form in header files that are designed to
...@@ -3476,9 +3490,10 @@ in an @code{__attribute__} will still only provide you with 8 byte ...@@ -3476,9 +3490,10 @@ in an @code{__attribute__} will still only provide you with 8 byte
alignment. See your linker documentation for further information. alignment. See your linker documentation for further information.
@item packed @item packed
This attribute, attached to an @code{enum}, @code{struct}, or This attribute, attached to @code{struct} or @code{union} type
@code{union} type definition, specifies that the minimum required memory definition, specifies that each member of the structure or union is
be used to represent the type. placed to minimize the memory required. When attached to an @code{enum}
definition, it indicates that the smallest integral type should be used.
@opindex fshort-enums @opindex fshort-enums
Specifying this attribute for @code{struct} and @code{union} types is Specifying this attribute for @code{struct} and @code{union} types is
...@@ -3487,9 +3502,29 @@ structure or union members. Specifying the @option{-fshort-enums} ...@@ -3487,9 +3502,29 @@ structure or union members. Specifying the @option{-fshort-enums}
flag on the line is equivalent to specifying the @code{packed} flag on the line is equivalent to specifying the @code{packed}
attribute on all @code{enum} definitions. attribute on all @code{enum} definitions.
You may only specify this attribute after a closing curly brace on an In the following example @code{struct my_packed_struct}'s members are
@code{enum} definition, not in a @code{typedef} declaration, unless that packed closely together, but the internal layout of its @code{s} member
declaration also contains the definition of the @code{enum}. is not packed -- to do that, @code{struct my_unpacked_struct} would need to
be packed too.
@smallexample
struct my_unpacked_struct
@{
char c;
int i;
@};
struct my_packed_struct __attribute__ ((__packed__))
@{
char c;
int i;
struct my_unpacked_struct s;
@};
@end smallexample
You may only specify this attribute on the definition of a @code{enum},
@code{struct} or @code{union}, not on a @code{typedef} which does not
also define the enumerated type, structure or union.
@item transparent_union @item transparent_union
This attribute, attached to a @code{union} type definition, indicates This attribute, attached to a @code{union} type definition, indicates
......
2003-08-01 Nathan Sidwell <nathan@codesourcery.com> 2003-08-01 Nathan Sidwell <nathan@codesourcery.com>
PR c++/11295
* g++.dg/ext/stmtexpr1.C: New test.
* g++.dg/opt/tmp1.C: New test. * g++.dg/opt/tmp1.C: New test.
PR c++/11525 PR c++/11525
......
// { dg-do run }
// { 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 ();
static unsigned order[] =
{
1, 101, 2, 102,
3, 4, 104, 103,
5, 6, 105, 106,
7, 107, 8, 408, 9, 109, 108,
10, 11, 110, 411, 12, 112, 111,
13, 113,
14, 214, 114, 114,
0
};
static unsigned point;
static void Check (unsigned t, unsigned i, void const *ptr, char const *name)
{
printf ("%d %d %p %s\n", t, i, ptr, name);
if (order[point++] != i + t)
abort ();
}
template <int I> struct A
{
A () { Check (0, I, this, __PRETTY_FUNCTION__); }
~A () { Check (100, I, this, __PRETTY_FUNCTION__); }
A (A const &) { Check (200, I, this, __PRETTY_FUNCTION__); }
A &operator= (A const &) { Check (300, I, this, __PRETTY_FUNCTION__); }
void Foo () const { Check (400, I, this, __PRETTY_FUNCTION__); }
};
int main ()
{
({A<1> (); A<2> (); ;});
({A<3> (), A<4> (); ;});
({A<5> (), A<6> ();});
({A <7> (); A<8> (); }).Foo (), A<9> ();
({A <10> (), A<11> (); }).Foo (), A<12> ();
({A<13> a; a; ; });
({A<14> a; a; });
Check (0, 0, 0, "end");
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment