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:
Nathan Sidwell 2003-08-01 09:34:09 +00:00 committed by Nathan Sidwell
parent d340e53fc3
commit a5bcc58230
9 changed files with 322 additions and 99 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View 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");
}