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
This commit is contained in:
parent
d340e53fc3
commit
a5bcc58230
9 changed files with 322 additions and 99 deletions
|
@ -1,3 +1,8 @@
|
|||
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>
|
||||
|
||||
* config.gcc (sh-*-linux*): Do not override sh/t-linux with sh/t-le.
|
||||
|
|
|
@ -1,5 +1,30 @@
|
|||
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
|
||||
compound expr inside the target's initializer.
|
||||
|
||||
|
|
|
@ -3056,8 +3056,13 @@ typedef enum tsubst_flags_t {
|
|||
(make_typename_type use) */
|
||||
tf_ptrmem_ok = 1 << 4, /* pointers to member ok (internal
|
||||
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) */
|
||||
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;
|
||||
|
||||
/* The kind of checking we can do looking in a class hierarchy. */
|
||||
|
@ -4134,6 +4139,7 @@ extern void finish_subobject (tree);
|
|||
extern tree finish_parenthesized_expr (tree);
|
||||
extern tree finish_non_static_data_member (tree, tree, tree);
|
||||
extern tree begin_stmt_expr (void);
|
||||
extern tree finish_stmt_expr_expr (tree);
|
||||
extern tree finish_stmt_expr (tree);
|
||||
extern tree perform_koenig_lookup (tree, tree);
|
||||
extern tree finish_call_expr (tree, tree, bool);
|
||||
|
|
|
@ -1367,15 +1367,15 @@ static tree cp_parser_constant_expression
|
|||
/* Statements [gram.stmt.stmt] */
|
||||
|
||||
static void cp_parser_statement
|
||||
(cp_parser *);
|
||||
(cp_parser *, bool);
|
||||
static tree cp_parser_labeled_statement
|
||||
(cp_parser *);
|
||||
(cp_parser *, bool);
|
||||
static tree cp_parser_expression_statement
|
||||
(cp_parser *);
|
||||
(cp_parser *, bool);
|
||||
static tree cp_parser_compound_statement
|
||||
(cp_parser *);
|
||||
(cp_parser *, bool);
|
||||
static void cp_parser_statement_seq_opt
|
||||
(cp_parser *);
|
||||
(cp_parser *, bool);
|
||||
static tree cp_parser_selection_statement
|
||||
(cp_parser *);
|
||||
static tree cp_parser_condition
|
||||
|
@ -2244,7 +2244,7 @@ cp_parser_primary_expression (cp_parser *parser,
|
|||
/* Start the statement-expression. */
|
||||
expr = begin_stmt_expr ();
|
||||
/* Parse the compound-statement. */
|
||||
cp_parser_compound_statement (parser);
|
||||
cp_parser_compound_statement (parser, true);
|
||||
/* Finish up. */
|
||||
expr = finish_stmt_expr (expr);
|
||||
}
|
||||
|
@ -5075,7 +5075,7 @@ cp_parser_constant_expression (cp_parser* parser,
|
|||
try-block */
|
||||
|
||||
static void
|
||||
cp_parser_statement (cp_parser* parser)
|
||||
cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
{
|
||||
tree statement;
|
||||
cp_token *token;
|
||||
|
@ -5097,7 +5097,8 @@ cp_parser_statement (cp_parser* parser)
|
|||
{
|
||||
case RID_CASE:
|
||||
case RID_DEFAULT:
|
||||
statement = cp_parser_labeled_statement (parser);
|
||||
statement = cp_parser_labeled_statement (parser,
|
||||
in_statement_expr_p);
|
||||
break;
|
||||
|
||||
case RID_IF:
|
||||
|
@ -5134,11 +5135,11 @@ cp_parser_statement (cp_parser* parser)
|
|||
labeled-statement. */
|
||||
token = cp_lexer_peek_nth_token (parser->lexer, 2);
|
||||
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. */
|
||||
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
|
||||
expression-statement. Try for the declaration-statement
|
||||
|
@ -5156,7 +5157,7 @@ cp_parser_statement (cp_parser* parser)
|
|||
return;
|
||||
}
|
||||
/* 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. */
|
||||
|
@ -5175,7 +5176,7 @@ cp_parser_statement (cp_parser* parser)
|
|||
an ordinary label, returns a LABEL_STMT. */
|
||||
|
||||
static tree
|
||||
cp_parser_labeled_statement (cp_parser* parser)
|
||||
cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
|
||||
{
|
||||
cp_token *token;
|
||||
tree statement = NULL_TREE;
|
||||
|
@ -5222,7 +5223,7 @@ cp_parser_labeled_statement (cp_parser* parser)
|
|||
/* Require the `:' token. */
|
||||
cp_parser_require (parser, CPP_COLON, "`:'");
|
||||
/* 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 statement;
|
||||
|
@ -5234,25 +5235,35 @@ cp_parser_labeled_statement (cp_parser* parser)
|
|||
expression [opt] ;
|
||||
|
||||
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
|
||||
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))
|
||||
statement = finish_expr_stmt (cp_parser_expression (parser));
|
||||
/* Otherwise, we do not even bother to build an EXPR_STMT. */
|
||||
else
|
||||
{
|
||||
finish_stmt ();
|
||||
statement = NULL_TREE;
|
||||
}
|
||||
statement = cp_parser_expression (parser);
|
||||
|
||||
/* Consume the final `;'. */
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -5264,7 +5275,7 @@ cp_parser_expression_statement (cp_parser* parser)
|
|||
Returns a COMPOUND_STMT representing the statement. */
|
||||
|
||||
static tree
|
||||
cp_parser_compound_statement (cp_parser *parser)
|
||||
cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
|
||||
{
|
||||
tree compound_stmt;
|
||||
|
||||
|
@ -5274,7 +5285,7 @@ cp_parser_compound_statement (cp_parser *parser)
|
|||
/* Begin the compound-statement. */
|
||||
compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
/* 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_compound_stmt (compound_stmt);
|
||||
/* Consume the `}'. */
|
||||
|
@ -5290,7 +5301,7 @@ cp_parser_compound_statement (cp_parser *parser)
|
|||
statement-seq [opt] statement */
|
||||
|
||||
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. */
|
||||
while (true)
|
||||
|
@ -5301,7 +5312,7 @@ cp_parser_statement_seq_opt (cp_parser* parser)
|
|||
break;
|
||||
|
||||
/* 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)
|
|||
return;
|
||||
}
|
||||
|
||||
cp_parser_expression_statement (parser);
|
||||
cp_parser_expression_statement (parser, false);
|
||||
}
|
||||
|
||||
/* Parse a jump-statement.
|
||||
|
@ -5756,13 +5767,13 @@ cp_parser_implicitly_scoped_statement (cp_parser* parser)
|
|||
/* Create a compound-statement. */
|
||||
statement = begin_compound_stmt (/*has_no_scope=*/false);
|
||||
/* Parse the dependent-statement. */
|
||||
cp_parser_statement (parser);
|
||||
cp_parser_statement (parser, false);
|
||||
/* Finish the dummy compound-statement. */
|
||||
finish_compound_stmt (statement);
|
||||
}
|
||||
/* Otherwise, we simply parse the statement directly. */
|
||||
else
|
||||
statement = cp_parser_compound_statement (parser);
|
||||
statement = cp_parser_compound_statement (parser, false);
|
||||
|
||||
/* Return the statement. */
|
||||
return statement;
|
||||
|
@ -5784,13 +5795,13 @@ cp_parser_already_scoped_statement (cp_parser* parser)
|
|||
/* Create a compound-statement. */
|
||||
statement = begin_compound_stmt (/*has_no_scope=*/true);
|
||||
/* Parse the dependent-statement. */
|
||||
cp_parser_statement (parser);
|
||||
cp_parser_statement (parser, false);
|
||||
/* Finish the dummy compound-statement. */
|
||||
finish_compound_stmt (statement);
|
||||
}
|
||||
/* Otherwise, we simply parse the statement directly. */
|
||||
else
|
||||
cp_parser_statement (parser);
|
||||
cp_parser_statement (parser, false);
|
||||
}
|
||||
|
||||
/* Declarations [gram.dcl.dcl] */
|
||||
|
@ -10693,7 +10704,7 @@ cp_parser_function_definition (cp_parser* parser, bool* friend_p)
|
|||
static void
|
||||
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
|
||||
|
@ -12244,7 +12255,7 @@ cp_parser_try_block (cp_parser* parser)
|
|||
|
||||
cp_parser_require_keyword (parser, RID_TRY, "`try'");
|
||||
try_block = begin_try_block ();
|
||||
cp_parser_compound_statement (parser);
|
||||
cp_parser_compound_statement (parser, false);
|
||||
finish_try_block (try_block);
|
||||
cp_parser_handler_seq (parser);
|
||||
finish_handler_sequence (try_block);
|
||||
|
@ -12320,7 +12331,7 @@ cp_parser_handler (cp_parser* parser)
|
|||
declaration = cp_parser_exception_declaration (parser);
|
||||
finish_handler_parms (declaration, handler);
|
||||
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
|
||||
cp_parser_compound_statement (parser);
|
||||
cp_parser_compound_statement (parser, false);
|
||||
finish_handler (handler);
|
||||
}
|
||||
|
||||
|
|
29
gcc/cp/pt.c
29
gcc/cp/pt.c
|
@ -7403,7 +7403,9 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
if (!processing_template_decl)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -7530,7 +7532,10 @@ static tree
|
|||
tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
||||
{
|
||||
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)
|
||||
return t;
|
||||
|
||||
|
@ -7556,10 +7561,18 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
break;
|
||||
|
||||
case EXPR_STMT:
|
||||
prep_stmt (t);
|
||||
finish_expr_stmt (tsubst_expr (EXPR_STMT_EXPR (t),
|
||||
args, complain, in_decl));
|
||||
break;
|
||||
{
|
||||
tree r;
|
||||
|
||||
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:
|
||||
prep_stmt (t);
|
||||
|
@ -7711,7 +7724,9 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
else
|
||||
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))
|
||||
finish_function_body (stmt);
|
||||
|
@ -7849,7 +7864,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
|
|||
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
|
||||
|
|
|
@ -416,21 +416,10 @@ tree
|
|||
finish_expr_stmt (tree expr)
|
||||
{
|
||||
tree r = NULL_TREE;
|
||||
tree expr_type = NULL_TREE;;
|
||||
|
||||
if (expr != NULL_TREE)
|
||||
{
|
||||
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 ())
|
||||
if (!processing_template_decl)
|
||||
expr = convert_to_void (expr, "statement");
|
||||
|
||||
r = add_stmt (build_stmt (EXPR_STMT, expr));
|
||||
|
@ -438,10 +427,6 @@ finish_expr_stmt (tree expr)
|
|||
|
||||
finish_stmt ();
|
||||
|
||||
/* This was an expression-statement, so we save the type of the
|
||||
expression. */
|
||||
last_expr_type = expr_type;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -1415,14 +1400,73 @@ begin_stmt_expr (void)
|
|||
if (! cfun && !last_tree)
|
||||
begin_stmt_tree (&scope_chain->x_saved_tree);
|
||||
|
||||
last_expr_type = NULL_TREE;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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
|
||||
returned by the previous begin_stmt_expr; EXPR is the
|
||||
statement-expression. Returns an expression representing the
|
||||
|
@ -1432,18 +1476,27 @@ tree
|
|||
finish_stmt_expr (tree rtl_expr)
|
||||
{
|
||||
tree result;
|
||||
|
||||
/* If the last thing in the statement-expression was not an
|
||||
expression-statement, then it has type `void'. In a template, we
|
||||
cannot distinguish the case where the last expression-statement
|
||||
had a dependent type from the case where the last statement was
|
||||
not an expression-statement. Therefore, we (incorrectly) treat
|
||||
the STMT_EXPR as dependent in that case. */
|
||||
if (!last_expr_type && !processing_template_decl)
|
||||
last_expr_type = void_type_node;
|
||||
result = build_min (STMT_EXPR, last_expr_type, last_tree);
|
||||
tree result_stmt = last_expr_type;
|
||||
tree type;
|
||||
|
||||
if (!last_expr_type)
|
||||
type = void_type_node;
|
||||
else
|
||||
{
|
||||
if (result_stmt == void_type_node)
|
||||
{
|
||||
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;
|
||||
|
||||
last_expr_type = NULL_TREE;
|
||||
|
||||
/* Remove the compound statement from the tree structure; it is
|
||||
now saved in the STMT_EXPR. */
|
||||
last_tree = rtl_expr;
|
||||
|
@ -1455,6 +1508,22 @@ finish_stmt_expr (tree rtl_expr)
|
|||
&& TREE_CHAIN (scope_chain->x_saved_tree) == NULL_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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
must use @code{typeof} (@pxref{Typeof}).
|
||||
|
||||
Statement expressions are not supported fully in G++, and their fate
|
||||
there is unclear. (It is possible that they will become fully supported
|
||||
at some point, or that they will be deprecated, or that the bugs that
|
||||
are present will continue to exist indefinitely.) Presently, statement
|
||||
expressions do not work well as default arguments.
|
||||
In G++, the result value of a statement expression undergoes array and
|
||||
function pointer decay, and is returned by value to the enclosing
|
||||
expression. For instance, if @code{A} is a class, then
|
||||
|
||||
In addition, there are semantic issues with statement-expressions in
|
||||
C++. If you try to use statement-expressions instead of inline
|
||||
functions in C++, you may be surprised at the way object destruction is
|
||||
handled. For example:
|
||||
@smallexample
|
||||
A a;
|
||||
|
||||
@example
|
||||
#define foo(a) (@{int b = (a); b + 3; @})
|
||||
@end example
|
||||
(@{a;@}).Foo ()
|
||||
@end smallexample
|
||||
|
||||
@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}.
|
||||
|
||||
@example
|
||||
inline int foo(int a) @{ int b = a; return b + 3; @}
|
||||
@end example
|
||||
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,
|
||||
|
||||
@smallexample
|
||||
#define macro(a) (@{__typeof__(a) b = (a); b + 3; @})
|
||||
template<typename T> T function(T a) @{ T b = a; return b + 3; @}
|
||||
|
||||
void foo ()
|
||||
@{
|
||||
macro (X ());
|
||||
function (X ());
|
||||
@}
|
||||
@end smallexample
|
||||
|
||||
@noindent
|
||||
In particular, if the expression passed into @code{foo} involves the
|
||||
creation of temporaries, the destructors for those temporaries will be
|
||||
run earlier in the case of the macro than in the case of the function.
|
||||
will have different places where temporaries are destroyed. For the
|
||||
@code{macro} case, the temporary @code{X} will be destroyed just after
|
||||
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
|
||||
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
|
|||
alignment. See your linker documentation for further information.
|
||||
|
||||
@item packed
|
||||
This attribute, attached to an @code{enum}, @code{struct}, or
|
||||
@code{union} type definition, specifies that the minimum required memory
|
||||
be used to represent the type.
|
||||
This attribute, attached to @code{struct} or @code{union} type
|
||||
definition, specifies that each member of the structure or union is
|
||||
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
|
||||
Specifying this attribute for @code{struct} and @code{union} types is
|
||||
|
@ -3487,9 +3502,29 @@ structure or union members. Specifying the @option{-fshort-enums}
|
|||
flag on the line is equivalent to specifying the @code{packed}
|
||||
attribute on all @code{enum} definitions.
|
||||
|
||||
You may only specify this attribute after a closing curly brace on an
|
||||
@code{enum} definition, not in a @code{typedef} declaration, unless that
|
||||
declaration also contains the definition of the @code{enum}.
|
||||
In the following example @code{struct my_packed_struct}'s members are
|
||||
packed closely together, but the internal layout of its @code{s} member
|
||||
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
|
||||
This attribute, attached to a @code{union} type definition, indicates
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
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.
|
||||
|
||||
PR c++/11525
|
||||
|
|
54
gcc/testsuite/g++.dg/ext/stmtexpr1.C
Normal file
54
gcc/testsuite/g++.dg/ext/stmtexpr1.C
Normal file
|
@ -0,0 +1,54 @@
|
|||
// { 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");
|
||||
}
|
||||
|
Loading…
Add table
Reference in a new issue