OSDN Git Service

* call.c (build_op_delete_call): Ignore exception-specifications
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 May 2001 00:31:36 +0000 (00:31 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 May 2001 00:31:36 +0000 (00:31 +0000)
when looking for matching delete operators.
* init.c (build_new_1): Compute whether or not the allocation
function used is a placement allocation function or not, and
communicate this information to build_op_delete_call.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@42413 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/init.c
gcc/testsuite/g++.old-deja/g++.other/new7.C [new file with mode: 0644]

index eda85ec..5d6ca8f 100644 (file)
@@ -1,3 +1,11 @@
+2001-05-21  Mark Mitchell  <mark@codesourcery.com>
+
+       * call.c (build_op_delete_call): Ignore exception-specifications
+       when looking for matching delete operators.
+       * init.c (build_new_1): Compute whether or not the allocation
+       function used is a placement allocation function or not, and
+       communicate this information to build_op_delete_call.
+
 2001-05-21  Jason Merrill  <jason_merrill@redhat.com>
 
        * class.c (build_vtable_entry_ref): Lose vtbl parm.  Fix for new abi.
index 6694f56..5367cc5 100644 (file)
@@ -3545,7 +3545,7 @@ builtin:
      used to determine what the corresponding new looked like.
    SIZE is the size of the memory block to be deleted.
    FLAGS are the usual overloading flags.
-   PLACEMENT is the corresponding placement new call, or 0.  */
+   PLACEMENT is the corresponding placement new call, or NULL_TREE.  */
 
 tree
 build_op_delete_call (code, addr, size, flags, placement)
@@ -3620,23 +3620,50 @@ build_op_delete_call (code, addr, size, flags, placement)
        argtypes = tree_cons (NULL_TREE, ptr_type_node,
                              tree_cons (NULL_TREE, sizetype, 
                                         void_list_node));
-
       fntype = build_function_type (void_type_node, argtypes);
-      fn = instantiate_type (fntype, fns, itf_no_attributes);
 
-      if (fn != error_mark_node)
+      /* Go through the `operator delete' functions looking for one
+        with a matching type.  */
+      for (fn = BASELINK_P (fns) ? TREE_VALUE (fns) : fns; 
+          fn; 
+          fn = OVL_NEXT (fn))
        {
-         /* Member functions.  */
-         if (BASELINK_P (fns))
-           enforce_access (type, fn);
-
-         if (pass == 0)
-           args = tree_cons (NULL_TREE, addr, args);
-         else
-           args = tree_cons (NULL_TREE, addr, 
-                             build_tree_list (NULL_TREE, size));
-         return build_function_call (fn, args);
+         tree t;
+
+         /* Exception specifications on the `delete' operator do not
+            matter.  */
+         t = build_exception_variant (TREE_TYPE (OVL_CURRENT (fn)),
+                                      NULL_TREE);
+         /* We also don't compare attributes.  We're really just
+            trying to check the types of the first two parameters.  */
+         if (comptypes (t, fntype, COMPARE_NO_ATTRIBUTES))
+           break;
        }
+
+      /* If we found a match, we're done.  */
+      if (fn)
+       break;
+    }
+
+  /* If we have a matching function, call it.  */
+  if (fn)
+    {
+      /* Make sure we have the actual function, and not an
+        OVERLOAD.  */
+      fn = OVL_CURRENT (fn);
+
+      /* If the FN is a member function, make sure that it is
+        accessible.  */
+      if (DECL_CLASS_SCOPE_P (fn))
+       enforce_access (type, fn);
+
+      if (pass == 0)
+       args = tree_cons (NULL_TREE, addr, args);
+      else
+       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
index 1ac6f73..6bce193 100644 (file)
@@ -2293,6 +2293,9 @@ build_new_1 (exp)
      beginning of the storage allocated for an array-new expression in
      order to store the number of elements.  */
   tree cookie_size = NULL_TREE;
+  /* True if the function we are calling is a placement allocation
+     function.  */
+  bool placement_allocation_fn_p;
 
   placement = TREE_OPERAND (exp, 0);
   type = TREE_OPERAND (exp, 1);
@@ -2418,8 +2421,25 @@ build_new_1 (exp)
   if (alloc_call == error_mark_node)
     return error_mark_node;
 
-  if (alloc_call == NULL_TREE)
-    abort ();
+  /* The ALLOC_CALL should be a CALL_EXPR, and the first operand
+     should be the address of a known FUNCTION_DECL.  */
+  my_friendly_assert (TREE_CODE (alloc_call) == CALL_EXPR, 20000521);
+  t = TREE_OPERAND (alloc_call, 0);
+  my_friendly_assert (TREE_CODE (t) == ADDR_EXPR, 20000521);
+  t = TREE_OPERAND (t, 0);
+  my_friendly_assert (TREE_CODE (t) == FUNCTION_DECL, 20000521);
+  /* Now, check to see if this function is actually a placement
+     allocation function.  This can happen even when PLACEMENT is NULL
+     because we might have something like:
+
+       struct S { void* operator new (size_t, int i = 0); };
+
+     A call to `new S' will get this allocation function, even though
+     there is no explicit placement argument.  If there is more than
+     one argument, or there are variable arguments, then this is a
+     placement allocation function.  */
+  placement_allocation_fn_p 
+    = (type_num_arguments (TREE_TYPE (t)) > 1 || varargs_function_p (t));
 
   /*        unless an allocation function is declared with an empty  excep-
      tion-specification  (_except.spec_),  throw(), it indicates failure to
@@ -2536,7 +2556,8 @@ build_new_1 (exp)
          flags |= LOOKUP_SPECULATIVELY;
 
          cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
-                                         alloc_call);
+                                         (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
diff --git a/gcc/testsuite/g++.old-deja/g++.other/new7.C b/gcc/testsuite/g++.old-deja/g++.other/new7.C
new file mode 100644 (file)
index 0000000..35ec0bb
--- /dev/null
@@ -0,0 +1,39 @@
+// Origin: philip_martin@ntlworld.com
+
+#include <new>
+
+extern "C" void abort();
+
+bool new_flag = false;
+bool delete_flag = false;
+
+struct X {
+  X()
+  {
+    throw 1;
+  }
+  void* operator new ( std::size_t n ) throw ( std::bad_alloc )
+  {
+    new_flag = true;
+    return ::operator new( n );
+  }
+  void operator delete( void* p, std::size_t n ) throw()
+  {
+    delete_flag = true;
+    ::operator delete( p );
+  }
+};
+
+int
+main()
+{
+  try
+    {
+      X* x = new X; // gcc 3.0 fails to call operator delete when X::X throws
+    }
+  catch ( ... )
+    {
+    }
+  if ( ! new_flag || ! delete_flag )
+    ::abort();
+}