init.c (build_new_1): Preevaluate placement args.
authorJason Merrill <jason@redhat.com>
Mon, 17 Nov 2003 19:39:46 +0000 (14:39 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 17 Nov 2003 19:39:46 +0000 (14:39 -0500)
        * init.c (build_new_1): Preevaluate placement args.
        * call.c (build_op_delete_call): Don't expose placement args to
        overload resolution.

From-SVN: r73677

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/init.c
gcc/testsuite/g++.dg/init/placement2.C [new file with mode: 0644]

index 5a5dc78b9286aff38a16b274ee3f4705c98059ca..e143dea0ec936a3b7101b434b098143957b7d151 100644 (file)
@@ -1,3 +1,9 @@
+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.
+
 2003-11-16  Jason Merrill  <jason@redhat.com>
 
        * Make-lang.in (c++.tags): Create TAGS.sub files in each directory
index 07622ab37cd7f350c967c75281ed133c3514f502..354eb8bb71a51c58120932dacce06088c28db4fa 100644 (file)
@@ -3824,10 +3824,6 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
 
       /* 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);
@@ -3910,7 +3906,15 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
        args = tree_cons (NULL_TREE, addr, 
                          build_tree_list (NULL_TREE, size));
 
-      return build_function_call (fn, args);
+      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
index 735215377a3b6f02d59f6361e065b1ea4f42ff58..332c518c76c20872e3656dd6a8c312fabf3a9ac1 100644 (file)
@@ -2060,13 +2060,22 @@ build_new_1 (tree exp)
   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);
+  /* 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
@@ -2083,6 +2092,27 @@ build_new_1 (tree exp)
     = (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_,
@@ -2096,18 +2126,6 @@ build_new_1 (tree exp)
   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;
diff --git a/gcc/testsuite/g++.dg/init/placement2.C b/gcc/testsuite/g++.dg/init/placement2.C
new file mode 100644 (file)
index 0000000..bca7415
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do run }
+
+void* operator new    (unsigned int sz, void*) { return operator new (sz); }
+void  operator delete (void* p, void*)         { operator delete (p); }
+
+struct A { A() { throw 1; } };
+
+int c;
+void *f() { ++c; return 0; }
+
+int main()
+{
+  try
+    {
+      new (f()) A;
+    }
+  catch (...) {}
+  return c != 1;
+}