This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH]: Fix 11295 - Make statement exprs work properly in C++


Hi,
This patch makes statement expressions function properly with C++.
Statement expressions did not behave correctly for non-pod types. This
patch makes them work in a similar manner to a function returning
a struct by value - a TARGET_EXPR is build whose initializer is the
statement-expression.

The awkardness with tf_stmt_expr and tf_stmt_exprs occurs because
a STMT_EXPR simply contains a COMPOUND_STMT, rather than a list
of statements and a separate 'result statement'. The STMT_EXPR
machinery can know it is supposed to wrap things in a scope etc.

Looking at stmts_are_full_exprs_p, I find it is (ab)used within tree-inline,
because there a STMT_EXPR is used to hold the both the inlined function and
its arg inits. Those temps in those arg inits must be destroyed in the
containing environment - not the environment of the STMT_EXPR.

IMHO, STMT_EXPRs would be cleaner (and we could probably do away
with stmts_are_full_exprs and the want_value & maybe_last
parameters from expand_expr) by
1) doing the same target_expr stuff in the C front end.
2) letting STMT_EXPRs have three slots
  *) an intializtion statement list. These are the things where temps are
     destroyed in the containing scope, and will be the only place where
     stmts_are_full_exprs_p is effectively false.
  *) an evaluation statement list -- all the statements

Expanding this would consist of
	begin_compound_stmt, begin_scope
        expand init statements in no-target-cleanup-mode
	expand eval statements
	end_scope, end_compound_stmt

Thoughts?

booted & tested on i686-pc-linux-gnu, ok?

nathan
--
Nathan Sidwell    ::   http://www.codesourcery.com   ::     CodeSourcery LLC
         The voices in my head said this was stupid too
nathan@codesourcery.com    ::     http://www.planetfall.pwp.blueyonder.co.uk

2003-07-30  Nathan Sidwell  <nathan@codesourcery.com>

	* cp-tree.h (tubst_flags_t): Add tf_stmt_expr, tf_stmt_exprs.
	(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.

	* doc/extend.texi (Statement Expressions): Document C++ semantics.
_
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.891
diff -c -3 -p -r1.891 cp-tree.h
*** cp/cp-tree.h	26 Jul 2003 19:10:26 -0000	1.891
--- cp/cp-tree.h	30 Jul 2003 13:40:27 -0000
*************** typedef enum tsubst_flags_t {
*** 3056,3063 ****
  				   (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
  				   (lookup_template_class use) */
  } tsubst_flags_t;
  
  /* The kind of checking we can do looking in a class hierarchy.  */
--- 3056,3067 ----
  				   (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
  				   (lookup_template_class use) */
+   tf_stmt_expr = 1 << 6,      /* tsubsting the statement of a statement
+ 			       	 expr.  */
+   tf_stmt_exprs = 1 << 7      /* tsubsting the statements of a statement
+ 			       	 expr.  */
  } tsubst_flags_t;
  
  /* The kind of checking we can do looking in a class hierarchy.  */
*************** extern void finish_subobject            
*** 4135,4140 ****
--- 4139,4145 ----
  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: cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.89
diff -c -3 -p -r1.89 parser.c
*** cp/parser.c	27 Jul 2003 16:51:14 -0000	1.89
--- cp/parser.c	30 Jul 2003 13:41:12 -0000
*************** static tree cp_parser_constant_expressio
*** 1367,1381 ****
  /* Statements [gram.stmt.stmt]  */
  
  static void cp_parser_statement
!   (cp_parser *);
  static tree cp_parser_labeled_statement
!   (cp_parser *);
  static tree cp_parser_expression_statement
!   (cp_parser *);
  static tree cp_parser_compound_statement
!   (cp_parser *);
  static void cp_parser_statement_seq_opt
!   (cp_parser *);
  static tree cp_parser_selection_statement
    (cp_parser *);
  static tree cp_parser_condition
--- 1367,1381 ----
  /* Statements [gram.stmt.stmt]  */
  
  static void cp_parser_statement
!   (cp_parser *, bool);
  static tree cp_parser_labeled_statement
!   (cp_parser *, bool);
  static tree cp_parser_expression_statement
!   (cp_parser *, bool);
  static tree cp_parser_compound_statement
!   (cp_parser *, bool);
  static void cp_parser_statement_seq_opt
!   (cp_parser *, bool);
  static tree cp_parser_selection_statement
    (cp_parser *);
  static tree cp_parser_condition
*************** cp_parser_primary_expression (cp_parser 
*** 2244,2250 ****
  	    /* Start the statement-expression.  */
  	    expr = begin_stmt_expr ();
  	    /* Parse the compound-statement.  */
! 	    cp_parser_compound_statement (parser);
  	    /* Finish up.  */
  	    expr = finish_stmt_expr (expr);
  	  }
--- 2244,2250 ----
  	    /* Start the statement-expression.  */
  	    expr = begin_stmt_expr ();
  	    /* Parse the compound-statement.  */
! 	    cp_parser_compound_statement (parser, true);
  	    /* Finish up.  */
  	    expr = finish_stmt_expr (expr);
  	  }
*************** cp_parser_constant_expression (cp_parser
*** 5083,5089 ****
       try-block  */
  
  static void
! cp_parser_statement (cp_parser* parser)
  {
    tree statement;
    cp_token *token;
--- 5083,5089 ----
       try-block  */
  
  static void
! cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
  {
    tree statement;
    cp_token *token;
*************** cp_parser_statement (cp_parser* parser)
*** 5105,5111 ****
  	{
  	case RID_CASE:
  	case RID_DEFAULT:
! 	  statement = cp_parser_labeled_statement (parser);
  	  break;
  
  	case RID_IF:
--- 5105,5112 ----
  	{
  	case RID_CASE:
  	case RID_DEFAULT:
! 	  statement = cp_parser_labeled_statement (parser,
! 						   in_statement_expr_p);
  	  break;
  
  	case RID_IF:
*************** cp_parser_statement (cp_parser* parser)
*** 5142,5152 ****
  	 labeled-statement.  */
        token = cp_lexer_peek_nth_token (parser->lexer, 2);
        if (token->type == CPP_COLON)
! 	statement = cp_parser_labeled_statement (parser);
      }
    /* Anything that starts with a `{' must be a compound-statement.  */
    else if (token->type == CPP_OPEN_BRACE)
!     statement = cp_parser_compound_statement (parser);
  
    /* Everything else must be a declaration-statement or an
       expression-statement.  Try for the declaration-statement 
--- 5143,5153 ----
  	 labeled-statement.  */
        token = cp_lexer_peek_nth_token (parser->lexer, 2);
        if (token->type == CPP_COLON)
! 	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, false);
  
    /* Everything else must be a declaration-statement or an
       expression-statement.  Try for the declaration-statement 
*************** cp_parser_statement (cp_parser* parser)
*** 5164,5170 ****
  	    return;
  	}
        /* Look for an expression-statement instead.  */
!       statement = cp_parser_expression_statement (parser);
      }
  
    /* Set the line number for the statement.  */
--- 5165,5171 ----
  	    return;
  	}
        /* Look for an expression-statement instead.  */
!       statement = cp_parser_expression_statement (parser, in_statement_expr_p);
      }
  
    /* Set the line number for the statement.  */
*************** cp_parser_statement (cp_parser* parser)
*** 5183,5189 ****
     an ordinary label, returns a LABEL_STMT.  */
  
  static tree
! cp_parser_labeled_statement (cp_parser* parser)
  {
    cp_token *token;
    tree statement = NULL_TREE;
--- 5184,5190 ----
     an ordinary label, returns a LABEL_STMT.  */
  
  static tree
! cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
  {
    cp_token *token;
    tree statement = NULL_TREE;
*************** cp_parser_labeled_statement (cp_parser* 
*** 5230,5236 ****
    /* Require the `:' token.  */
    cp_parser_require (parser, CPP_COLON, "`:'");
    /* Parse the labeled statement.  */
!   cp_parser_statement (parser);
  
    /* Return the label, in the case of a `case' or `default' label.  */
    return statement;
--- 5231,5237 ----
    /* Require the `:' token.  */
    cp_parser_require (parser, CPP_COLON, "`:'");
    /* Parse the labeled statement.  */
!   cp_parser_statement (parser, in_statement_expr_p);
  
    /* Return the label, in the case of a `case' or `default' label.  */
    return statement;
*************** cp_parser_labeled_statement (cp_parser* 
*** 5242,5266 ****
       expression [opt] ;
  
     Returns the new EXPR_STMT -- or NULL_TREE if the expression
!    statement consists of nothing more than an `;'.  */
  
  static tree
! cp_parser_expression_statement (cp_parser* parser)
  {
!   tree statement;
  
!   /* If the next token is not a `;', then there is an expression to parse.  */
    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;
!     }
    /* Consume the final `;'.  */
    cp_parser_consume_semicolon_at_end_of_statement (parser);
  
    return statement;
  }
  
--- 5243,5277 ----
       expression [opt] ;
  
     Returns the new EXPR_STMT -- or NULL_TREE if the expression
!    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, bool in_statement_expr_p)
  {
!   tree statement = NULL_TREE;
  
!   /* If the next token is a ';', then there is no expression
!      statement. */
    if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
!     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;
  }
  
*************** cp_parser_expression_statement (cp_parse
*** 5272,5278 ****
     Returns a COMPOUND_STMT representing the statement.  */
  
  static tree
! cp_parser_compound_statement (cp_parser *parser)
  {
    tree compound_stmt;
  
--- 5283,5289 ----
     Returns a COMPOUND_STMT representing the statement.  */
  
  static tree
! cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
  {
    tree compound_stmt;
  
*************** cp_parser_compound_statement (cp_parser 
*** 5282,5288 ****
    /* Begin the compound-statement.  */
    compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
    /* Parse an (optional) statement-seq.  */
!   cp_parser_statement_seq_opt (parser);
    /* Finish the compound-statement.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
    /* Consume the `}'.  */
--- 5293,5299 ----
    /* Begin the compound-statement.  */
    compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
    /* Parse an (optional) statement-seq.  */
!   cp_parser_statement_seq_opt (parser, in_statement_expr_p);
    /* Finish the compound-statement.  */
    finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
    /* Consume the `}'.  */
*************** cp_parser_compound_statement (cp_parser 
*** 5298,5304 ****
       statement-seq [opt] statement  */
  
  static void
! cp_parser_statement_seq_opt (cp_parser* parser)
  {
    /* Scan statements until there aren't any more.  */
    while (true)
--- 5309,5315 ----
       statement-seq [opt] statement  */
  
  static void
! cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p)
  {
    /* Scan statements until there aren't any more.  */
    while (true)
*************** cp_parser_statement_seq_opt (cp_parser* 
*** 5309,5315 ****
  	break;
  
        /* Parse the statement.  */
!       cp_parser_statement (parser);
      }
  }
  
--- 5320,5326 ----
  	break;
  
        /* Parse the statement.  */
!       cp_parser_statement (parser, in_statement_expr_p);
      }
  }
  
*************** cp_parser_for_init_statement (cp_parser*
*** 5639,5645 ****
  	return;
      }
  
!   cp_parser_expression_statement (parser);
  }
  
  /* Parse a jump-statement.
--- 5650,5656 ----
  	return;
      }
  
!   cp_parser_expression_statement (parser, false);
  }
  
  /* Parse a jump-statement.
*************** cp_parser_implicitly_scoped_statement (c
*** 5764,5776 ****
        /* Create a compound-statement.  */
        statement = begin_compound_stmt (/*has_no_scope=*/0);
        /* Parse the dependent-statement.  */
!       cp_parser_statement (parser);
        /* Finish the dummy compound-statement.  */
        finish_compound_stmt (/*has_no_scope=*/0, statement);
      }
    /* Otherwise, we simply parse the statement directly.  */
    else
!     statement = cp_parser_compound_statement (parser);
  
    /* Return the statement.  */
    return statement;
--- 5775,5787 ----
        /* Create a compound-statement.  */
        statement = begin_compound_stmt (/*has_no_scope=*/0);
        /* Parse the dependent-statement.  */
!       cp_parser_statement (parser, false);
        /* Finish the dummy compound-statement.  */
        finish_compound_stmt (/*has_no_scope=*/0, statement);
      }
    /* Otherwise, we simply parse the statement directly.  */
    else
!     statement = cp_parser_compound_statement (parser, false);
  
    /* Return the statement.  */
    return statement;
*************** cp_parser_already_scoped_statement (cp_p
*** 5792,5804 ****
        /* Create a compound-statement.  */
        statement = begin_compound_stmt (/*has_no_scope=*/1);
        /* Parse the dependent-statement.  */
!       cp_parser_statement (parser);
        /* Finish the dummy compound-statement.  */
        finish_compound_stmt (/*has_no_scope=*/1, statement);
      }
    /* Otherwise, we simply parse the statement directly.  */
    else
!     cp_parser_statement (parser);
  }
  
  /* Declarations [gram.dcl.dcl] */
--- 5803,5815 ----
        /* Create a compound-statement.  */
        statement = begin_compound_stmt (/*has_no_scope=*/1);
        /* Parse the dependent-statement.  */
!       cp_parser_statement (parser, false);
        /* Finish the dummy compound-statement.  */
        finish_compound_stmt (/*has_no_scope=*/1, statement);
      }
    /* Otherwise, we simply parse the statement directly.  */
    else
!     cp_parser_statement (parser, false);
  }
  
  /* Declarations [gram.dcl.dcl] */
*************** cp_parser_function_definition (cp_parser
*** 10701,10707 ****
  static void
  cp_parser_function_body (cp_parser *parser)
  {
!   cp_parser_compound_statement (parser);
  }
  
  /* Parse a ctor-initializer-opt followed by a function-body.  Return
--- 10712,10718 ----
  static void
  cp_parser_function_body (cp_parser *parser)
  {
!   cp_parser_compound_statement (parser, false);
  }
  
  /* Parse a ctor-initializer-opt followed by a function-body.  Return
*************** cp_parser_try_block (cp_parser* parser)
*** 12252,12258 ****
  
    cp_parser_require_keyword (parser, RID_TRY, "`try'");
    try_block = begin_try_block ();
!   cp_parser_compound_statement (parser);
    finish_try_block (try_block);
    cp_parser_handler_seq (parser);
    finish_handler_sequence (try_block);
--- 12263,12269 ----
  
    cp_parser_require_keyword (parser, RID_TRY, "`try'");
    try_block = begin_try_block ();
!   cp_parser_compound_statement (parser, false);
    finish_try_block (try_block);
    cp_parser_handler_seq (parser);
    finish_handler_sequence (try_block);
*************** cp_parser_handler (cp_parser* parser)
*** 12328,12334 ****
    declaration = cp_parser_exception_declaration (parser);
    finish_handler_parms (declaration, handler);
    cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
!   cp_parser_compound_statement (parser);
    finish_handler (handler);
  }
  
--- 12339,12345 ----
    declaration = cp_parser_exception_declaration (parser);
    finish_handler_parms (declaration, handler);
    cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
!   cp_parser_compound_statement (parser, false);
    finish_handler (handler);
  }
  
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.738
diff -c -3 -p -r1.738 pt.c
*** cp/pt.c	25 Jul 2003 16:45:34 -0000	1.738
--- cp/pt.c	30 Jul 2003 13:41:37 -0000
*************** tsubst_copy (tree t, tree args, tsubst_f
*** 7417,7423 ****
        if (!processing_template_decl)
  	{
  	  tree stmt_expr = begin_stmt_expr ();
! 	  tsubst_expr (STMT_EXPR_STMT (t), args, complain, in_decl);
  	  return finish_stmt_expr (stmt_expr);
  	}
        
--- 7408,7416 ----
        if (!processing_template_decl)
  	{
  	  tree stmt_expr = begin_stmt_expr ();
! 	  
! 	  tsubst_expr (STMT_EXPR_STMT (t), args,
! 		       complain | tf_stmt_expr, in_decl);
  	  return finish_stmt_expr (stmt_expr);
  	}
        
*************** static tree
*** 7544,7550 ****
--- 7537,7545 ----
  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 | tf_stmt_exprs);
  
+   complain ^= stmt_expr;
    if (t == NULL_TREE || t == error_mark_node)
      return t;
  
*************** tsubst_expr (tree t, tree args, tsubst_f
*** 7570,7579 ****
        break;
  
      case EXPR_STMT:
!       prep_stmt (t);
!       finish_expr_stmt (tsubst_expr (EXPR_STMT_EXPR (t),
! 				     args, complain, in_decl));
!       break;
  
      case USING_STMT:
        prep_stmt (t);
--- 7565,7582 ----
        break;
  
      case EXPR_STMT:
!       {
! 	tree r;
! 	
! 	prep_stmt (t);
! 
! 	r = tsubst_expr (EXPR_STMT_EXPR (t), args, complain, in_decl);
! 	if (stmt_expr & tf_stmt_exprs && !TREE_CHAIN (t))
! 	  finish_stmt_expr_expr (r);
! 	else
! 	  finish_expr_stmt (r);
! 	break;
!       }
  
      case USING_STMT:
        prep_stmt (t);
*************** tsubst_expr (tree t, tree args, tsubst_f
*** 7725,7731 ****
  	else
  	  stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
  
! 	tsubst_expr (COMPOUND_BODY (t), args, complain, in_decl);
  
  	if (COMPOUND_STMT_BODY_BLOCK (t))
  	  finish_function_body (stmt);
--- 7728,7735 ----
  	else
  	  stmt = begin_compound_stmt (COMPOUND_STMT_NO_SCOPE (t));
  
! 	tsubst_expr (COMPOUND_BODY (t), args,
! 		     complain | ((stmt_expr & tf_stmt_expr) << 1), in_decl);
  
  	if (COMPOUND_STMT_BODY_BLOCK (t))
  	  finish_function_body (stmt);
*************** tsubst_expr (tree t, tree args, tsubst_f
*** 7863,7869 ****
        abort ();
      }
  
!   return tsubst_expr (TREE_CHAIN (t), args, complain, in_decl);
  }
  
  /* T is a postfix-expression that is not being used in a function
--- 7867,7873 ----
        abort ();
      }
  
!   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: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.336
diff -c -3 -p -r1.336 semantics.c
*** cp/semantics.c	26 Jul 2003 19:10:26 -0000	1.336
--- cp/semantics.c	30 Jul 2003 13:41:44 -0000
*************** tree
*** 416,447 ****
  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 (stmts_are_full_exprs_p ())
! 	expr = convert_to_void (expr, "statement");
        
        r = add_stmt (build_stmt (EXPR_STMT, expr));
      }
  
    finish_stmt ();
  
-   /* This was an expression-statement, so we save the type of the
-      expression.  */
-   last_expr_type = expr_type;
- 
    return r;
  }
  
--- 416,431 ----
  finish_expr_stmt (tree expr)
  {
    tree r = NULL_TREE;
  
    if (expr != NULL_TREE)
      {
!       expr = convert_to_void (expr, "statement");
        
        r = add_stmt (build_stmt (EXPR_STMT, expr));
      }
  
    finish_stmt ();
  
    return r;
  }
  
*************** begin_stmt_expr (void)
*** 1417,1430 ****
    if (! cfun && !last_tree)
      begin_stmt_tree (&scope_chain->x_saved_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; 
  }
  
  /* 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
--- 1401,1473 ----
    if (! cfun && !last_tree)
      begin_stmt_tree (&scope_chain->x_saved_tree);
  
+   last_expr_type = NULL_TREE;
+   
    keep_next_level (1);
!   
    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
*************** tree 
*** 1434,1451 ****
  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_SIDE_EFFECTS (result) = 1;
    
    /* Remove the compound statement from the tree structure; it is
       now saved in the STMT_EXPR.  */
    last_tree = rtl_expr;
--- 1477,1503 ----
  finish_stmt_expr (tree rtl_expr)
  {
    tree result;
!   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;
*************** finish_stmt_expr (tree rtl_expr)
*** 1457,1462 ****
--- 1509,1530 ----
        && 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: doc/extend.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/extend.texi,v
retrieving revision 1.152
diff -c -3 -p -r1.152 extend.texi
*** doc/extend.texi	27 Jul 2003 16:57:18 -0000	1.152
--- doc/extend.texi	30 Jul 2003 16:04:15 -0000
*************** the initial value of a static variable.
*** 539,570 ****
  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 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:
  
! @example
! #define foo(a)  (@{int b = (a); b + 3; @})
! @end example
  
  @noindent
! does not work the same way as:
  
! @example
! inline int foo(int a) @{ int b = a; return b + 3; @}
! @end example
  
  @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.
  
  These considerations mean that it is probably a bad idea to use
  statement-expressions of this form in header files that are designed to
--- 539,584 ----
  If you don't know the type of the operand, you can still do this, but you
  must use @code{typeof} (@pxref{Typeof}).
  
! 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
  
! @smallexample
!         A a;
  
!         (@{a;@}).Foo ()
! @end smallexample
  
  @noindent
! 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,
! 
! @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
! 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
*************** in an @code{__attribute__} will still on
*** 3476,3484 ****
  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.
  
  @opindex fshort-enums
  Specifying this attribute for @code{struct} and @code{union} types is
--- 3490,3499 ----
  alignment.  See your linker documentation for further information.
  
  @item packed
! 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
*************** structure or union members.  Specifying 
*** 3487,3495 ****
  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}.
  
  @item transparent_union
  This attribute, attached to a @code{union} type definition, indicates
--- 3502,3530 ----
  flag on the line is equivalent to specifying the @code{packed}
  attribute on all @code{enum} definitions.
  
! 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
// { 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");
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]