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 to avoid reevaluation of new placement args


While looking at PR 11266, I noticed that any side-effects in a new
placement argument are evaluated again if we call placement delete.  The
standard is not entirely clear on this point, but I think this is wrong,
and the EDG compiler agrees with me.

Tested x86_64-pc-linux-gnu, applied to trunk.  Test in
g++.dg/init/placement2.C.

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

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

*** call.c.~1~	2003-11-17 11:51:48.000000000 -0500
--- call.c	2003-11-17 13:22:09.000000000 -0500
*************** 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
*** init.c.~1~	2003-11-03 16:39:12.000000000 -0500
--- init.c	2003-11-17 13:24:07.000000000 -0500
*************** 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
--- 2060,2081 ----
    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 ****
--- 2092,2118 ----
      = (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 = NULL_TREE;
+       t = TREE_CHAIN (TREE_OPERAND (alloc_call, 1));
+       for (; 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;
+ 	  }
+       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;
--- 2126,2131 ----

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