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++, tree-ssa] PATCH to preevaluate new-initializer args


This patch implements the FIXME in build_new_1: we now preevaluate all of
the arguments to the constructor for a new'd object, so that we can
do the actual memory allocation last and thereby minimize the extent of the
EH region for freeing the memory if the constructor throws an exception.
Previously the region covered the whole statement and we needed to control
whether or not we actually run the cleanup using a boolean temporary
variable; this is much simpler and should be easier for the optimizers to
deal with.

This patch changes the observable behavior on
g++.old-deja/g++.martin/new1.C; we used to allocate the memory before
evaluating any of the constructor args, now we do the opposite.  This order
is unspecified in the standard, so both are conformant.

While I was there, I removed the 'pedantic' check for the pedwarn about
specifying an initializer in array new.  This might be worth applying to
the trunk as well.  The whole patch would be suitable for the trunk, except
that we're now in stage 3.

Tested athlon-pc-linux-gnu, applied to tree-ssa branch.

2003-11-17  Jason Merrill  <jason@redhat.com>

	* init.c (build_new_1): Preevaluate initializer.  Simplify EH code.
	(build_init): Call a constructor rather than call build_aggr_init
	for classes.
	* except.c (stabilize_throw_expr): Remove.
	(build_throw): Use stabilize_init instead of stabilize_throw_expr.
	* tree.c (stabilize_call, stabilize_init): New fns.
	* call.c (build_over_call): A constructor no longer returns the
	address of the object.

	* init.c (build_new_1): Preevaluate placement args.
	* call.c (build_op_delete_call): Don't expose placement args to
	overload resolution.

Index: gcc/cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.320.2.36
diff -c -p -r1.320.2.36 call.c
*** gcc/cp/call.c	13 Nov 2003 02:38:50 -0000	1.320.2.36
--- gcc/cp/call.c	18 Nov 2003 05:35:23 -0000
*************** build_op_delete_call (enum tree_code cod
*** 3824,3833 ****
  
        /* Find the allocation function that is being called.  */
        call_expr = placement;
-       /* Sometimes we have a COMPOUND_EXPR, rather than a simple
- 	 CALL_EXPR.  */
-       while (TREE_CODE (call_expr) == COMPOUND_EXPR)
- 	call_expr = TREE_OPERAND (call_expr, 1);
        /* Extract the function.  */
        alloc_fn = get_callee_fndecl (call_expr);
        my_friendly_assert (alloc_fn != NULL_TREE, 20020327);
--- 3824,3829 ----
*************** build_op_delete_call (enum tree_code cod
*** 3910,3916 ****
  	args = tree_cons (NULL_TREE, addr, 
  			  build_tree_list (NULL_TREE, size));
  
!       return build_function_call (fn, args);
      }
  
    /* If we are doing placement delete we do nothing if we don't find a
--- 3906,3920 ----
  	args = tree_cons (NULL_TREE, addr, 
  			  build_tree_list (NULL_TREE, size));
  
!       if (placement)
! 	{
! 	  /* The placement args might not be suitable for overload
! 	     resolution at this point, so build the call directly.  */
! 	  mark_used (fn);
! 	  return build_cxx_call (fn, args, args);
! 	}
!       else
! 	return build_function_call (fn, args);
      }
  
    /* If we are doing placement delete we do nothing if we don't find a
*************** build_over_call (struct z_candidate *can
*** 4577,4592 ****
        else if (TREE_CODE (arg) == TARGET_EXPR
  	       || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
  	{
- 	  tree address;
  	  tree to = stabilize_reference
  	    (build_indirect_ref (TREE_VALUE (args), 0));
  
  	  val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
! 	  address = build_unary_op (ADDR_EXPR, val, 0);
! 	  /* Avoid a warning about this expression, if the address is
! 	     never used.  */
! 	  TREE_USED (address) = 1;
! 	  return address;
  	}
      }
    else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
--- 4581,4591 ----
        else if (TREE_CODE (arg) == TARGET_EXPR
  	       || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn)))
  	{
  	  tree to = stabilize_reference
  	    (build_indirect_ref (TREE_VALUE (args), 0));
  
  	  val = build (INIT_EXPR, DECL_CONTEXT (fn), to, arg);
! 	  return val;
  	}
      }
    else if (DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR
Index: gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.719.2.42
diff -c -p -r1.719.2.42 cp-tree.h
*** gcc/cp/cp-tree.h	17 Nov 2003 00:31:02 -0000	1.719.2.42
--- gcc/cp/cp-tree.h	18 Nov 2003 05:35:24 -0000
*************** extern void finalize_nrv			(tree *, tree
*** 4090,4095 ****
--- 4090,4097 ----
  extern void lang_check_failed			(const char *, int,
  							 const char *);
  extern tree stabilize_expr			(tree, tree *);
+ extern void stabilize_call			(tree, tree *);
+ extern void stabilize_init			(tree, tree *);
  extern tree cxx_unsave_expr_now			(tree);
  extern tree cxx_maybe_build_cleanup		(tree);
  extern void init_tree			        (void);
Index: gcc/cp/except.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/except.c,v
retrieving revision 1.142.2.14
diff -c -p -r1.142.2.14 except.c
*** gcc/cp/except.c	6 Oct 2003 17:38:04 -0000	1.142.2.14
--- gcc/cp/except.c	18 Nov 2003 05:35:24 -0000
*************** static tree do_end_catch (tree);
*** 47,53 ****
  static bool decl_is_java_type (tree decl, int err);
  static void initialize_handler_parm (tree, tree);
  static tree do_allocate_exception (tree);
- static tree stabilize_throw_expr (tree, tree *);
  static tree wrap_cleanups_r (tree *, int *, void *);
  static int complete_ptr_ref_or_void_ptr_p (tree, tree);
  static bool is_admissible_throw_operand (tree);
--- 47,52 ----
*************** wrap_cleanups_r (tree *tp, int *walk_sub
*** 558,615 ****
    return NULL_TREE;
  }
  
- /* Like stabilize_expr, but specifically for a thrown expression.  When
-    throwing a temporary class object, we want to construct it directly into
-    the thrown exception, so we look past the TARGET_EXPR and stabilize the
-    arguments of the call instead.
- 
-    The case where EXP is a call to a function returning a class is a bit of
-    a grey area in the standard; it's unclear whether or not it should be
-    allowed to throw.  I'm going to say no, as that allows us to optimize
-    this case without worrying about deallocating the exception object if it
-    does.  The alternatives would be either not optimizing this case, or
-    wrapping the initialization in a TRY_CATCH_EXPR to call do_free_exception
-    rather than in a MUST_NOT_THROW_EXPR, for this case only.  */
- 
- static tree
- stabilize_throw_expr (tree exp, tree *initp)
- {
-   tree init_expr;
- 
-   if (TREE_CODE (exp) == TARGET_EXPR
-       && TREE_CODE (TARGET_EXPR_INITIAL (exp)) == AGGR_INIT_EXPR
-       && flag_elide_constructors)
-     {
-       tree aggr_init = AGGR_INIT_EXPR_CHECK (TARGET_EXPR_INITIAL (exp));
-       tree args = TREE_OPERAND (aggr_init, 1);
-       tree newargs = NULL_TREE;
-       tree *p = &newargs;
- 
-       init_expr = void_zero_node;
-       for (; args; args = TREE_CHAIN (args))
- 	{
- 	  tree arg = TREE_VALUE (args);
- 	  tree arg_init_expr;
- 
- 	  arg = stabilize_expr (arg, &arg_init_expr);
- 
- 	  if (TREE_SIDE_EFFECTS (arg_init_expr))
- 	    init_expr = build (COMPOUND_EXPR, void_type_node, init_expr,
- 			       arg_init_expr);
- 	  *p = tree_cons (NULL_TREE, arg, NULL_TREE);
- 	  p = &TREE_CHAIN (*p);
- 	}
-       TREE_OPERAND (aggr_init, 1) = newargs;
-     }
-   else
-     {
-       exp = stabilize_expr (exp, &init_expr);
-     }
- 
-   *initp = init_expr;
-   return exp;
- }
- 
  /* Build a throw expression.  */
  
  tree
--- 557,562 ----
*************** build_throw (tree exp)
*** 695,705 ****
  	 the call to __cxa_allocate_exception first (which doesn't
  	 matter, since it can't throw).  */
  
-       /* Pre-evaluate the thrown expression first, since if we allocated
- 	 the space first we would have to deal with cleaning it up if
- 	 evaluating this expression throws.  */
-       exp = stabilize_throw_expr (exp, &temp_expr);
- 
        /* Allocate the space for the exception.  */
        allocate_expr = do_allocate_exception (TREE_TYPE (exp));
        allocate_expr = get_target_expr (allocate_expr);
--- 642,647 ----
*************** build_throw (tree exp)
*** 715,724 ****
  	  return error_mark_node;
  	}
  
        exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp);
        /* Prepend the allocation.  */
        exp = build (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp);
!       if (temp_expr != void_zero_node)
  	{
  	  /* Prepend the calculation of the throw expression.  Also, force
  	     any cleanups from the expression to be evaluated here so that
--- 657,680 ----
  	  return error_mark_node;
  	}
  
+       /* Pre-evaluate the thrown expression first, since if we allocated
+ 	 the space first we would have to deal with cleaning it up if
+ 	 evaluating this expression throws.
+ 
+ 	 The case where EXP the initializer is a call to a function
+ 	 returning a class is a bit of a grey area in the standard; it's
+ 	 unclear whether or not it should be allowed to throw.  I'm going
+ 	 to say no, as that allows us to optimize this case without
+ 	 worrying about deallocating the exception object if it does.  The
+ 	 alternatives would be either not optimizing this case, or wrapping
+ 	 the initialization in a TRY_CATCH_EXPR to call do_free_exception
+ 	 rather than in a MUST_NOT_THROW_EXPR, for this case only.  */
+       stabilize_init (exp, &temp_expr);
+ 
        exp = build1 (MUST_NOT_THROW_EXPR, void_type_node, exp);
        /* Prepend the allocation.  */
        exp = build (COMPOUND_EXPR, TREE_TYPE (exp), allocate_expr, exp);
!       if (temp_expr)
  	{
  	  /* Prepend the calculation of the throw expression.  Also, force
  	     any cleanups from the expression to be evaluated here so that
Index: gcc/cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.281.2.30
diff -c -p -r1.281.2.30 init.c
*** gcc/cp/init.c	28 Oct 2003 14:58:03 -0000	1.281.2.30
--- gcc/cp/init.c	18 Nov 2003 05:35:24 -0000
*************** build_init (tree decl, tree init, int fl
*** 1146,1154 ****
  {
    tree expr;
  
!   if (IS_AGGR_TYPE (TREE_TYPE (decl))
!       || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
      expr = build_aggr_init (decl, init, flags);
    else
      expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
  
--- 1146,1158 ----
  {
    tree expr;
  
!   if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
      expr = build_aggr_init (decl, init, flags);
+   else if (CLASS_TYPE_P (TREE_TYPE (decl)))
+     expr = build_special_member_call (decl, complete_ctor_identifier,
+ 				      build_tree_list (NULL_TREE, init),
+ 				      TYPE_BINFO (TREE_TYPE (decl)),
+ 				      LOOKUP_NORMAL|flags);
    else
      expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
  
*************** static tree
*** 1902,1908 ****
  build_new_1 (tree exp)
  {
    tree placement, init;
!   tree true_type, size, rval, t;
    /* The type of the new-expression.  (This type is always a pointer
       type.)  */
    tree pointer_type;
--- 1906,1912 ----
  build_new_1 (tree exp)
  {
    tree placement, init;
!   tree true_type, size, rval;
    /* The type of the new-expression.  (This type is always a pointer
       type.)  */
    tree pointer_type;
*************** build_new_1 (tree exp)
*** 1943,1948 ****
--- 1947,1953 ----
       address of the first array element.  This node is a VAR_DECL, and
       is therefore reusable.  */
    tree data_addr;
+   tree init_preeval_expr = NULL_TREE;
  
    placement = TREE_OPERAND (exp, 0);
    type = TREE_OPERAND (exp, 1);
*************** build_new_1 (tree exp)
*** 2060,2072 ****
    if (alloc_call == error_mark_node)
      return error_mark_node;
  
!   /* The ALLOC_CALL should be a CALL_EXPR -- or a COMPOUND_EXPR whose
!      right-hand-side is ultimately a CALL_EXPR -- and the first
!      operand should be the address of a known FUNCTION_DECL.  */
!   t = alloc_call;
!   while (TREE_CODE (t) == COMPOUND_EXPR) 
!     t = TREE_OPERAND (t, 1);
!   alloc_fn = get_callee_fndecl (t);
    my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
  
    /* Now, check to see if this function is actually a placement
--- 2065,2086 ----
    if (alloc_call == error_mark_node)
      return error_mark_node;
  
!   /* In the simple case, we can stop now.  */
!   pointer_type = build_pointer_type (type);
!   if (!cookie_size && !is_initialized)
!     return build_nop (pointer_type, alloc_call);
! 
!   /* While we're working, use a pointer to the type we've actually
!      allocated. Store the result of the call in a variable so that we
!      can use it more than once.  */
!   full_pointer_type = build_pointer_type (full_type);
!   alloc_expr = get_target_expr (build_nop (full_pointer_type, alloc_call));
!   alloc_node = TARGET_EXPR_SLOT (alloc_expr);
! 
!   /* Strip any COMPOUND_EXPRs from ALLOC_CALL.  */
!   while (TREE_CODE (alloc_call) == COMPOUND_EXPR) 
!     alloc_call = TREE_OPERAND (alloc_call, 1);
!   alloc_fn = get_callee_fndecl (alloc_call);
    my_friendly_assert (alloc_fn != NULL_TREE, 20020325);
  
    /* Now, check to see if this function is actually a placement
*************** build_new_1 (tree exp)
*** 2083,2088 ****
--- 2097,2113 ----
      = (type_num_arguments (TREE_TYPE (alloc_fn)) > 1 
         || varargs_function_p (alloc_fn));
  
+   /* Preevaluate the placement args so that we don't reevaluate them for a
+      placement delete.  */
+   if (placement_allocation_fn_p)
+     {
+       tree inits;
+       stabilize_call (alloc_call, &inits);
+       if (inits)
+ 	alloc_expr = build (COMPOUND_EXPR, TREE_TYPE (alloc_expr), inits,
+ 			    alloc_expr);
+     }
+ 
    /*        unless an allocation function is declared with an empty  excep-
       tion-specification  (_except.spec_),  throw(), it indicates failure to
       allocate storage by throwing a bad_alloc exception  (clause  _except_,
*************** build_new_1 (tree exp)
*** 2096,2113 ****
    nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
    check_new = (flag_check_new || nothrow) && ! use_java_new;
  
-   /* In the simple case, we can stop now.  */
-   pointer_type = build_pointer_type (type);
-   if (!cookie_size && !is_initialized)
-     return build_nop (pointer_type, alloc_call);
- 
-   /* While we're working, use a pointer to the type we've actually
-      allocated. Store the result of the call in a variable so that we
-      can use it more than once.  */
-   full_pointer_type = build_pointer_type (full_type);
-   alloc_expr = get_target_expr (build_nop (full_pointer_type, alloc_call));
-   alloc_node = TARGET_EXPR_SLOT (alloc_expr);
- 
    if (cookie_size)
      {
        tree cookie;
--- 2121,2126 ----
*************** build_new_1 (tree exp)
*** 2132,2145 ****
        data_addr = alloc_node;
      }
  
!   /* Now initialize the allocated object.  */
    if (is_initialized)
      {
        init_expr = build_indirect_ref (data_addr, NULL);
  
        if (init == void_zero_node)
  	init = build_default_init (full_type, nelts);
!       else if (init && pedantic && has_array)
  	pedwarn ("ISO C++ forbids initialization in array new");
  
        if (has_array)
--- 2145,2162 ----
        data_addr = alloc_node;
      }
  
!   /* Now initialize the allocated object.  Note that we preevaluate the
!      initialization expression, apart from the actual constructor call or
!      assignment--we do this because we want to delay the allocation as long
!      as possible in order to minimize the size of the exception region for
!      placement delete.  */
    if (is_initialized)
      {
        init_expr = build_indirect_ref (data_addr, NULL);
  
        if (init == void_zero_node)
  	init = build_default_init (full_type, nelts);
!       else if (init && has_array)
  	pedwarn ("ISO C++ forbids initialization in array new");
  
        if (has_array)
*************** build_new_1 (tree exp)
*** 2149,2158 ****
  						integer_one_node),
  			    init, /*from_array=*/0);
        else if (TYPE_NEEDS_CONSTRUCTING (type))
! 	init_expr = build_special_member_call (init_expr, 
! 					       complete_ctor_identifier,
! 					       init, TYPE_BINFO (true_type),
! 					       LOOKUP_NORMAL);
        else
  	{
  	  /* We are processing something like `new int (10)', which
--- 2166,2178 ----
  						integer_one_node),
  			    init, /*from_array=*/0);
        else if (TYPE_NEEDS_CONSTRUCTING (type))
! 	{
! 	  init_expr = build_special_member_call (init_expr, 
! 						 complete_ctor_identifier,
! 						 init, TYPE_BINFO (true_type),
! 						 LOOKUP_NORMAL);
! 	  stabilize_init (init_expr, &init_preeval_expr);
! 	}
        else
  	{
  	  /* We are processing something like `new int (10)', which
*************** build_new_1 (tree exp)
*** 2160,2174 ****
  
  	  if (TREE_CODE (init) == TREE_LIST)
  	    init = build_x_compound_expr_from_list (init, "new initializer");
! 	  
  	  else if (TREE_CODE (init) == CONSTRUCTOR
  		   && TREE_TYPE (init) == NULL_TREE)
! 	    {
! 	      pedwarn ("ISO C++ forbids aggregate initializer to new");
! 	      init = digest_init (type, init, 0);
! 	    }
  
  	  init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
  	}
  
        if (init_expr == error_mark_node)
--- 2180,2192 ----
  
  	  if (TREE_CODE (init) == TREE_LIST)
  	    init = build_x_compound_expr_from_list (init, "new initializer");
! 
  	  else if (TREE_CODE (init) == CONSTRUCTOR
  		   && TREE_TYPE (init) == NULL_TREE)
! 	    abort ();
  
  	  init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
+ 	  stabilize_init (init_expr, &init_preeval_expr);
  	}
  
        if (init_expr == error_mark_node)
*************** build_new_1 (tree exp)
*** 2198,2248 ****
  					  (placement_allocation_fn_p 
  					   ? alloc_call : NULL_TREE));
  
! 	  /* Ack!  First we allocate the memory.  Then we set our sentry
! 	     variable to true, and expand a cleanup that deletes the memory
! 	     if sentry is true.  Then we run the constructor, and finally
! 	     clear the sentry.
! 
! 	     It would be nice to be able to handle this without the sentry
! 	     variable, perhaps with a TRY_CATCH_EXPR, but this doesn't
! 	     work.  We allocate the space first, so if there are any
! 	     temporaries with cleanups in the constructor args we need this
! 	     EH region to extend until end of full-expression to preserve
! 	     nesting.
! 
! 	     If the backend had some mechanism so that we could force the
! 	     allocation to be expanded after all the other args to the
! 	     constructor, that would fix the nesting problem and we could
! 	     do away with this complexity.  But that would complicate other
! 	     things; in particular, it would make it difficult to bail out
! 	     if the allocation function returns null.  Er, no, it wouldn't;
! 	     we just don't run the constructor.  The standard says it's
! 	     unspecified whether or not the args are evaluated.
! 
! 	     FIXME FIXME FIXME inline invisible refs as refs.  That way we
! 	     can preevaluate value parameters.  */
! 
  	  if (cleanup)
! 	    {
! 	      tree end, sentry, begin;
! 
! 	      begin = get_target_expr (boolean_true_node);
! 	      CLEANUP_EH_ONLY (begin) = 1;
! 
! 	      sentry = TARGET_EXPR_SLOT (begin);
! 
! 	      TARGET_EXPR_CLEANUP (begin)
! 		= build (COND_EXPR, void_type_node, sentry,
! 			 cleanup, void_zero_node);
! 
! 	      end = build (MODIFY_EXPR, TREE_TYPE (sentry),
! 			   sentry, boolean_false_node);
! 
! 	      init_expr
! 		= build (COMPOUND_EXPR, void_type_node, begin,
! 			 build (COMPOUND_EXPR, void_type_node, init_expr,
! 				end));
! 	    }
  	}
      }
    else
--- 2216,2226 ----
  					  (placement_allocation_fn_p 
  					   ? alloc_call : NULL_TREE));
  
! 	  /* This is much simpler now that we've preevaluated all of the
! 	     arguments to the constructor call.  */
  	  if (cleanup)
! 	    init_expr = build (TRY_CATCH_EXPR, void_type_node,
! 			       init_expr, cleanup);
  	}
      }
    else
*************** build_new_1 (tree exp)
*** 2274,2279 ****
--- 2252,2260 ----
  	 has been initialized before we start using it.  */
        rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
      }
+ 
+   if (init_preeval_expr)
+     rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_preeval_expr, rval);
  
    /* Convert to the final type.  */
    rval = build_nop (pointer_type, rval);
Index: gcc/cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.286.2.38
diff -c -p -r1.286.2.38 tree.c
*** gcc/cp/tree.c	17 Nov 2003 00:31:02 -0000	1.286.2.38
--- gcc/cp/tree.c	18 Nov 2003 05:35:25 -0000
*************** stabilize_expr (tree exp, tree* initp)
*** 2396,2402 ****
  
    if (!TREE_SIDE_EFFECTS (exp))
      {
!       init_expr = void_zero_node;
      }
    else if (!real_lvalue_p (exp)
  	   || !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp)))
--- 2396,2402 ----
  
    if (!TREE_SIDE_EFFECTS (exp))
      {
!       init_expr = NULL_TREE;
      }
    else if (!real_lvalue_p (exp)
  	   || !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (exp)))
*************** stabilize_expr (tree exp, tree* initp)
*** 2415,2420 ****
--- 2415,2485 ----
    *initp = init_expr;
    return exp;
  }
+ 
+ /* Like stabilize_expr, but for a call whose args we want to
+    pre-evaluate.  */
+ 
+ void
+ stabilize_call (tree call, tree *initp)
+ {
+   tree inits = NULL_TREE;
+   tree t;
+ 
+   if (call == error_mark_node)
+     return;
+ 
+   if (TREE_CODE (call) != CALL_EXPR
+       && TREE_CODE (call) != AGGR_INIT_EXPR)
+     abort ();
+ 
+   for (t = TREE_OPERAND (call, 1); t; t = TREE_CHAIN (t))
+     if (TREE_SIDE_EFFECTS (TREE_VALUE (t)))
+       {
+ 	tree init;
+ 	TREE_VALUE (t) = stabilize_expr (TREE_VALUE (t), &init);
+ 	if (inits)
+ 	  inits = build (COMPOUND_EXPR, void_type_node, inits, init);
+ 	else
+ 	  inits = init;
+       }
+ 
+   *initp = inits;
+ }
+ 
+ /* Like stabilize_expr, but for an initialization.  If we are initializing
+    an object of class type, we don't want to introduce an extra temporary,
+    so we look past the TARGET_EXPR and stabilize the arguments of the call
+    instead.  */
+ 
+ void
+ stabilize_init (tree init, tree *initp)
+ {
+   tree t = init;
+ 
+   if (t == error_mark_node)
+     return;
+ 
+   if (TREE_CODE (t) == INIT_EXPR
+       && TREE_CODE (TREE_OPERAND (t, 1)) != TARGET_EXPR)
+     TREE_OPERAND (t, 1) = stabilize_expr (TREE_OPERAND (t, 1), initp);
+   else
+     {
+       if (TREE_CODE (t) == INIT_EXPR)
+ 	t = TREE_OPERAND (t, 1);
+       if (TREE_CODE (t) == TARGET_EXPR)
+ 	t = TARGET_EXPR_INITIAL (t);
+       if (TREE_CODE (t) == CONSTRUCTOR
+ 	  && CONSTRUCTOR_ELTS (t) == NULL_TREE)
+ 	{
+ 	  /* Default-initialization.  */
+ 	  *initp = NULL_TREE;
+ 	  return;
+ 	}
+ 
+       stabilize_call (t, initp);
+     }
+ }
+ 
  
  #if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
  /* Complain that some language-specific thing hanging off a tree
Index: gcc/cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.408.2.34
diff -c -p -r1.408.2.34 typeck.c
*** gcc/cp/typeck.c	17 Nov 2003 07:55:56 -0000	1.408.2.34
--- gcc/cp/typeck.c	18 Nov 2003 05:35:26 -0000
*************** build_modify_expr (tree lhs, enum tree_c
*** 4958,4964 ****
  	  return cond;
  	/* Make sure the code to compute the rhs comes out
  	   before the split.  */
! 	return build (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond);
        }
        
      default:
--- 4958,4966 ----
  	  return cond;
  	/* Make sure the code to compute the rhs comes out
  	   before the split.  */
! 	if (preeval)
! 	  cond = build (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond);
! 	return cond;
        }
        
      default:
Index: gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C,v
retrieving revision 1.3.48.1
diff -c -p -r1.3.48.1 arrnew2.C
*** gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C	7 May 2003 13:33:30 -0000	1.3.48.1
--- gcc/testsuite/g++.old-deja/g++.ext/arrnew2.C	18 Nov 2003 05:35:28 -0000
***************
*** 1,4 ****
! // { dg-do assemble  }
! // { dg-options "" }
  
! int *foo = new int[1](0); // { dg-bogus "" } 
--- 1,8 ----
! // { dg-do run { xfail *-*-* } }
! // { dg-options "-w -fpermissive" }
  
! int *foo = new int[1](42); // { dg-bogus "" }
! int main ()
! {
!   return foo[0] != 42;
! }
Index: gcc/testsuite/g++.old-deja/g++.martin/new1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.martin/new1.C,v
retrieving revision 1.3.28.1
diff -c -p -r1.3.28.1 new1.C
*** gcc/testsuite/g++.old-deja/g++.martin/new1.C	7 May 2003 13:33:55 -0000	1.3.28.1
--- gcc/testsuite/g++.old-deja/g++.martin/new1.C	18 Nov 2003 05:35:28 -0000
*************** void test1()
*** 71,78 ****
      func(new B(A(10).addr()));
    }catch(int){
    }
!   CHECK(new_done==1);
!   CHECK(ctor_done==2);
    CHECK(func_done==3);
    CHECK(dtor_done==4);
    CHECK(delete_done==0);
--- 71,78 ----
      func(new B(A(10).addr()));
    }catch(int){
    }
!   CHECK(ctor_done==1);
!   CHECK(new_done==2);
    CHECK(func_done==3);
    CHECK(dtor_done==4);
    CHECK(delete_done==0);
*************** void test2()
*** 86,95 ****
      func(new B(A(10).addr()));
    }catch(int){
    }
!   CHECK(new_done==1);
!   CHECK(ctor_done==0);
    CHECK(func_done==0);
!   CHECK(dtor_done==0);
    CHECK(delete_done==0);
  }
  
--- 86,95 ----
      func(new B(A(10).addr()));
    }catch(int){
    }
!   CHECK(ctor_done==1);
!   CHECK(new_done==2);
    CHECK(func_done==0);
!   CHECK(dtor_done==3);
    CHECK(delete_done==0);
  }
  
*************** void test3()
*** 101,111 ****
      func(new B(A(10).addr()));
    }catch(int){
    }
!   CHECK(new_done==1);
!   CHECK(ctor_done==2);
    CHECK(func_done==0);
    CHECK(dtor_done==0);
!   CHECK(delete_done==3);
  }
  
  int main()
--- 101,111 ----
      func(new B(A(10).addr()));
    }catch(int){
    }
!   CHECK(new_done==0);
!   CHECK(ctor_done==1);
    CHECK(func_done==0);
    CHECK(dtor_done==0);
!   CHECK(delete_done==0);
  }
  
  int main()
Index: gcc/testsuite/g++.old-deja/g++.robertl/eb58.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.robertl/eb58.C,v
retrieving revision 1.5.46.1
diff -c -p -r1.5.46.1 eb58.C
*** gcc/testsuite/g++.old-deja/g++.robertl/eb58.C	7 May 2003 13:35:24 -0000	1.5.46.1
--- gcc/testsuite/g++.old-deja/g++.robertl/eb58.C	18 Nov 2003 05:35:29 -0000
***************
*** 1,5 ****
  // { dg-do run  }
! // { dg-options "" }
  // Test for g++ array init extension 
  
  class A {
--- 1,5 ----
  // { dg-do run  }
! // { dg-options "-w -fpermissive" }
  // Test for g++ array init extension 
  
  class A {
Index: gcc/testsuite/g++.old-deja/g++.robertl/eb63.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.old-deja/g++.robertl/eb63.C,v
retrieving revision 1.5.22.1
diff -c -p -r1.5.22.1 eb63.C
*** gcc/testsuite/g++.old-deja/g++.robertl/eb63.C	7 May 2003 13:35:24 -0000	1.5.22.1
--- gcc/testsuite/g++.old-deja/g++.robertl/eb63.C	18 Nov 2003 05:35:29 -0000
***************
*** 1,5 ****
  // { dg-do run  }
! // { dg-options "" }
  //This uses GNU extensions, so disable -ansi
  #include <stdio.h>
  #include <stdlib.h>
--- 1,5 ----
  // { dg-do run  }
! // { dg-options "-w -fpermissive" }
  //This uses GNU extensions, so disable -ansi
  #include <stdio.h>
  #include <stdlib.h>

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