From: Nathan Sidwell Date: Fri, 1 Aug 2003 09:34:09 +0000 (+0000) Subject: re PR c++/11295 (ICE when using a non-trivial object in a compound statement expression) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a5bcc58230c173c6923908cd7622dca7240f18de;p=gcc.git 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) : Pass tf_stmt_expr. (tsubst_expr): Process tf_stmt_expr and tf_stmt_exprs flags. (tsubst_expr) : 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index cd4c1acbac0..56fe21a8a30 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2003-08-01 Nathan Sidwell + + PR c++/11295 + * doc/extend.texi (Statement Expressions): Document C++ semantics. + 2003-07-31 SUGIOKA Toshinobu * 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 d999173926d..07fffc2f975 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,30 @@ 2003-08-01 Nathan Sidwell + 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) : Pass tf_stmt_expr. + (tsubst_expr): Process tf_stmt_expr and tf_stmt_exprs flags. + (tsubst_expr) : 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 a7bdc578e7d..f62255b2f39 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 c4b40b20d04..51f4eda4a6a 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 9661ea3414f..9cfefb2ed0c 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 de5b190ee02..80a3d60136d 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 36a5a944b8c..f636d33215d 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 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 eb64af8c6c8..28e6e20eb0b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2003-08-01 Nathan Sidwell + 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 00000000000..afdf6440317 --- /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 + +// 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 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"); +} +