]> gcc.gnu.org Git - gcc.git/commitdiff
re PR c++/34158 (Template delete doesn't call if exception thrown in constructor)
authorJason Merrill <jason@redhat.com>
Tue, 10 Nov 2009 18:18:51 +0000 (13:18 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Tue, 10 Nov 2009 18:18:51 +0000 (13:18 -0500)
PR c++/34158
PR c++/36406
* call.c (non_placement_deallocation_fn_p): Split out...
(build_op_delete_call): ...from here.  Use instantiate_type
for placement delete.  Simplify logic.
* pt.c (primary_template_instantiation_p): Non-static.
* cp-tree.h: Declare it.

From-SVN: r154072

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/pt.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/init/placement4.C [new file with mode: 0644]

index 24da7cf5f3cbe7fde72582639c93f558d3b5f9a1..6087ed7f90c69ea2536a08bd73b4dbba1d6970e7 100644 (file)
@@ -1,5 +1,13 @@
 2009-11-09  Jason Merrill  <jason@redhat.com>
 
+       PR c++/34158
+       PR c++/36406
+       * call.c (non_placement_deallocation_fn_p): Split out...
+       (build_op_delete_call): ...from here.  Use instantiate_type
+       for placement delete.  Simplify logic.
+       * pt.c (primary_template_instantiation_p): Non-static.
+       * cp-tree.h: Declare it.
+
        PR c++/41972
        * parser.c (cp_parser_template_argument): Accept SCOPE_REF around
        VAR_DECL.
index 1aebaac8cd53d8a2d400c8b5782a53bfcdb4c09c..1cd3fc2e0e69a778c43219fcf8e47017096d30de 100644 (file)
@@ -4503,6 +4503,33 @@ build_new_op (enum tree_code code, int flags, tree arg1, tree arg2, tree arg3,
   return NULL_TREE;
 }
 
+/* Returns true iff T, an element of an OVERLOAD chain, is a usual
+   deallocation function (3.7.4.2 [basic.stc.dynamic.deallocation]).  */
+
+static bool
+non_placement_deallocation_fn_p (tree t)
+{
+  /* A template instance is never a usual deallocation function,
+     regardless of its signature.  */
+  if (TREE_CODE (t) == TEMPLATE_DECL
+      || primary_template_instantiation_p (t))
+    return false;
+
+  /* If a class T has a member deallocation function named operator delete
+     with exactly one parameter, then that function is a usual
+     (non-placement) deallocation function. If class T does not declare
+     such an operator delete but does declare a member deallocation
+     function named operator delete with exactly two parameters, the second
+     of which has type std::size_t (18.2), then this function is a usual
+     deallocation function.  */
+  t = FUNCTION_ARG_CHAIN (t);
+  if (t == void_list_node
+      || (t && same_type_p (TREE_VALUE (t), size_type_node)
+         && TREE_CHAIN (t) == void_list_node))
+    return true;
+  return false;
+}
+
 /* Build a call to operator delete.  This has to be handled very specially,
    because the restrictions on what signatures match are different from all
    other call instances.  For a normal delete, only a delete taking (void *)
@@ -4528,8 +4555,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
                      tree alloc_fn)
 {
   tree fn = NULL_TREE;
-  tree fns, fnname, argtypes, type;
-  int pass;
+  tree fns, fnname, type, t;
 
   if (addr == error_mark_node)
     return error_mark_node;
@@ -4564,78 +4590,68 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
 
   if (placement)
     {
-      /* Get the parameter types for the allocation function that is
-        being called.  */
-      gcc_assert (alloc_fn != NULL_TREE);
-      argtypes = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn)));
-    }
-  else
-    {
-      /* First try it without the size argument.  */
-      argtypes = void_list_node;
-    }
+      /* "A declaration of a placement deallocation function matches the
+        declaration of a placement allocation function if it has the same
+        number of parameters and, after parameter transformations (8.3.5),
+        all parameter types except the first are identical."
 
-  /* We make two tries at finding a matching `operator delete'.  On
-     the first pass, we look for a one-operator (or placement)
-     operator delete.  If we're not doing placement delete, then on
-     the second pass we look for a two-argument delete.  */
-  for (pass = 0; pass < (placement ? 1 : 2); ++pass)
-    {
-      /* Go through the `operator delete' functions looking for one
-        with a matching type.  */
-      for (fn = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns;
-          fn;
-          fn = OVL_NEXT (fn))
-       {
-         tree t;
+        So we build up the function type we want and ask instantiate_type
+        to get it for us.  */
+      t = FUNCTION_ARG_CHAIN (alloc_fn);
+      t = tree_cons (NULL_TREE, ptr_type_node, t);
+      t = build_function_type (void_type_node, t);
 
-         /* The first argument must be "void *".  */
-         t = TYPE_ARG_TYPES (TREE_TYPE (OVL_CURRENT (fn)));
-         if (!same_type_p (TREE_VALUE (t), ptr_type_node))
-           continue;
-         t = TREE_CHAIN (t);
-         /* On the first pass, check the rest of the arguments.  */
-         if (pass == 0)
-           {
-             tree a = argtypes;
-             while (a && t)
-               {
-                 if (!same_type_p (TREE_VALUE (a), TREE_VALUE (t)))
-                   break;
-                 a = TREE_CHAIN (a);
-                 t = TREE_CHAIN (t);
-               }
-             if (!a && !t)
-               break;
-           }
-         /* On the second pass, look for a function with exactly two
-            arguments: "void *" and "size_t".  */
-         else if (pass == 1
-                  /* For "operator delete(void *, ...)" there will be
-                     no second argument, but we will not get an exact
-                     match above.  */
-                  && t
-                  && same_type_p (TREE_VALUE (t), size_type_node)
-                  && TREE_CHAIN (t) == void_list_node)
-           break;
-       }
+      fn = instantiate_type (t, fns, tf_none);
+      if (fn == error_mark_node)
+       return NULL_TREE;
 
-      /* If we found a match, we're done.  */
-      if (fn)
-       break;
+      if (BASELINK_P (fn))
+       fn = BASELINK_FUNCTIONS (fn);
+
+      /* "If the lookup finds the two-parameter form of a usual deallocation
+        function (3.7.4.2) and that function, considered as a placement
+        deallocation function, would have been selected as a match for the
+        allocation function, the program is ill-formed."  */
+      if (non_placement_deallocation_fn_p (fn))
+       error ("non-placement deallocation function %qD selected for "
+              "placement delete", fn);
     }
+  else
+    /* "Any non-placement deallocation function matches a non-placement
+       allocation function. If the lookup finds a single matching
+       deallocation function, that function will be called; otherwise, no
+       deallocation function will be called."  */
+    for (t = BASELINK_P (fns) ? BASELINK_FUNCTIONS (fns) : fns;
+        t; t = OVL_NEXT (t))
+      {
+       tree elt = OVL_CURRENT (t);
+       if (non_placement_deallocation_fn_p (elt))
+         {
+           fn = elt;
+           /* "If a class T has a member deallocation function named
+              operator delete with exactly one parameter, then that
+              function is a usual (non-placement) deallocation
+              function. If class T does not declare such an operator
+              delete but does declare a member deallocation function named
+              operator delete with exactly two parameters, the second of
+              which has type std::size_t (18.2), then this function is a
+              usual deallocation function."
+
+              So (void*) beats (void*, size_t).  */
+           if (FUNCTION_ARG_CHAIN (fn) == void_list_node)
+             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);
+      gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
 
       /* If the FN is a member function, make sure that it is
         accessible.  */
-      if (DECL_CLASS_SCOPE_P (fn))
-       perform_or_defer_access_check (TYPE_BINFO (type), fn, fn);
+      if (BASELINK_P (fns))
+       perform_or_defer_access_check (BASELINK_BINFO (fns), fn, fn);
 
       /* Core issue 901: It's ok to new a type with deleted delete.  */
       if (DECL_DELETED_FN (fn) && alloc_fn)
@@ -4659,7 +4675,7 @@ build_op_delete_call (enum tree_code code, tree addr, tree size,
          tree ret;
          VEC(tree,gc) *args = VEC_alloc (tree, gc, 2);
          VEC_quick_push (tree, args, addr);
-         if (pass != 0)
+         if (FUNCTION_ARG_CHAIN (fn) != void_list_node)
            VEC_quick_push (tree, args, size);
          ret = cp_build_function_call_vec (fn, &args, tf_warning_or_error);
          VEC_free (tree, gc, args);
index 68be934547199727e8e2eae1e3cdaf8962beb460..ca52bdf7597cc9e3d3892853873fa67defc95f33 100644 (file)
@@ -4853,6 +4853,7 @@ extern struct tinst_level *outermost_tinst_level(void);
 extern bool parameter_of_template_p            (tree, tree);
 extern void init_template_processing           (void);
 bool template_template_parameter_p             (const_tree);
+extern bool primary_template_instantiation_p    (const_tree);
 extern tree get_primary_template_innermost_parameters  (const_tree);
 extern tree get_template_innermost_arguments   (const_tree);
 extern tree get_template_argument_pack_elems   (const_tree);
index 3efeda80fe61524e228e9ec490cfa00774bb9592..0e688bf406a632b36b7d5c188784d561cd7d1015 100644 (file)
@@ -191,7 +191,6 @@ static tree tsubst_decl (tree, tree, tsubst_flags_t);
 static void perform_typedefs_access_check (tree tmpl, tree targs);
 static void append_type_to_template_for_access_check_1 (tree, tree, tree);
 static hashval_t iterative_hash_template_arg (tree arg, hashval_t val);
-static bool primary_template_instantiation_p (const_tree);
 static tree listify (tree);
 static tree listify_autos (tree, tree);
 
@@ -2739,7 +2738,7 @@ make_ith_pack_parameter_name (tree name, int i)
 /* Return true if T is a primary function
    or class template instantiation.  */
 
-static bool
+bool
 primary_template_instantiation_p (const_tree t)
 {
   if (!t)
index 2635b758409ed0a7f0735bcd2a5647033e1ab31e..ae1202fcbe8d2daf92d4b35311b451ff2c021a8f 100644 (file)
@@ -1,3 +1,8 @@
+2009-11-09  Jason Merrill  <jason@redhat.com>
+
+       PR c++/34158
+       * g++.dg/init/placement4.C: New.
+
 2009-11-10  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc.dg/vect/vect-multitypes-5.c: XFAIL on SPARC 32-bit.
diff --git a/gcc/testsuite/g++.dg/init/placement4.C b/gcc/testsuite/g++.dg/init/placement4.C
new file mode 100644 (file)
index 0000000..9c61eca
--- /dev/null
@@ -0,0 +1,32 @@
+// PR c++/34158
+
+typedef __SIZE_TYPE__ size_t;
+extern "C" void* malloc (size_t);
+extern "C" void free (void *);
+
+template <class T> class undef;
+
+struct A {
+  A() { throw 1; }
+};
+
+template<typename T> class Pool { };
+
+void *operator new(size_t size,Pool<int>& pool)
+{
+  return malloc(size);
+}
+
+template<typename T>
+void operator delete(void *p,Pool<T>& pool)
+{
+  undef<T> t;                  // { dg-error "incomplete" }
+  free(p);
+}
+
+int main ()
+{
+  Pool<int> pool;
+  new (pool) A();              // { dg-message "instantiated" }
+  return 0;
+}
This page took 0.082919 seconds and 5 git commands to generate.