re PR c++/11295 (ICE when using a non-trivial object in a compound statement expression)
authorNathan Sidwell <nathan@codesourcery.com>
Fri, 1 Aug 2003 09:34:09 +0000 (09:34 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Fri, 1 Aug 2003 09:34:09 +0000 (09:34 +0000)
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

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/cp/pt.c
gcc/cp/semantics.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/ext/stmtexpr1.C [new file with mode: 0644]

index cd4c1acbac08ee37510be33128aed15162755190..56fe21a8a30c85c4b41284b5489a494734748f90 100644 (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.
index d999173926d8af23ff09a5364fc6d841130a4bb4..07fffc2f97554cc880fe03b528a56fd55844733a 100644 (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.
        
index a7bdc578e7dace6accc3a34cf786e480420c8001..f62255b2f39c6ee6c4a3771509b309885d7c4fff 100644 (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);
index c4b40b20d0403d363b8a036068b5608151f08ea0..51f4eda4a6afd264ac9176a8f626352b9cad6e96 100644 (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);
 }
 
index 9661ea3414fcc75736d2dc9f46845f768281e53a..9cfefb2ed0c37a7338e629460074be134740e2eb 100644 (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
index de5b190ee0246eac5e014ea02fb4bb6782d17392..80a3d60136db4ee27780a8127ea82db70b81f0ef 100644 (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;
 }
 
index 36a5a944b8cd4d7f4105e6c6527102927cf9c2ee..f636d33215da9f80ac71068f406e9c7ef71b8220 100644 (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}.
+
+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
index eb64af8c6c805e633c4d4d0e1f4cb5fd88afe4de..28e6e20eb0b0289d161ac7cc6d60af39c234f292 100644 (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
diff --git a/gcc/testsuite/g++.dg/ext/stmtexpr1.C b/gcc/testsuite/g++.dg/ext/stmtexpr1.C
new file mode 100644 (file)
index 0000000..afdf644
--- /dev/null
@@ -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");
+}
+