aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2003-08-01 09:34:09 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2003-08-01 09:34:09 +0000
commita5bcc58230c173c6923908cd7622dca7240f18de (patch)
treebbb501c90255aea4dd7368daf077d8f0d4280c1c /gcc
parentd340e53fc39cdfc88b89ec4a420719dc31aadca8 (diff)
downloadgcc-a5bcc58230c173c6923908cd7622dca7240f18de.zip
gcc-a5bcc58230c173c6923908cd7622dca7240f18de.tar.gz
gcc-a5bcc58230c173c6923908cd7622dca7240f18de.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/cp-tree.h8
-rw-r--r--gcc/cp/parser.c83
-rw-r--r--gcc/cp/pt.c29
-rw-r--r--gcc/cp/semantics.c129
-rw-r--r--gcc/doc/extend.texi85
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/ext/stmtexpr1.C54
9 files changed, 322 insertions, 99 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cd4c1ac..56fe21a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d999173..07fffc2 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a7bdc57..f62255b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -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);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c4b40b2..51f4eda 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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);
}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9661ea3..9cfefb2 100644
--- a/gcc/cp/pt.c
+++ b/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
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index de5b190..80a3d60 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -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;
}
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 36a5a94..f636d33 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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}.
+
+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
-inline int foo(int a) @{ int b = a; return b + 3; @}
-@end example
+@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
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index eb64af8..28e6e20 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr1.C b/gcc/testsuite/g++.dg/ext/stmtexpr1.C
new file mode 100644
index 0000000..afdf644
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/stmtexpr1.C
@@ -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");
+}
+