On 9/21/26 8:55 AM, Jakub Jelinek wrote:
On Mon, Sep 21, 2026 at 07:53:14AM -0400, Jason Merrill wrote:
The second testcase according to the paper's Implementation divergence
section should be rejected, but we accept it instead.
That isn't about selection of the single placement deallocation function
if any, but that we have later on
        /* Core issue 901: It's ok to new a type with deleted delete.  */
        if (DECL_DELETED_FN (fn) && alloc_fn)
          return NULL_TREE;
https://wg21.link/cwg901 seems to be unresolved for years, shall we keep
it like that, or limit it to !placement, something else?

Let's leave it alone for now (and not test it), the wording doesn't seem to
touch on this question.

Ok, second testcase removed.

         t = FUNCTION_ARG_CHAIN (alloc_fn);
         t = tree_cons (NULL_TREE, ptr_type_node, t);
         t = build_function_type (void_type_node, t);

Since we're no longer calling instantiate_type, it seems unnecessary to
build up this FUNCTION_TYPE...

Removed both build_function_type and tree_cons.

+                 tree arg_types = TYPE_ARG_TYPES (t), arg;
+                 unsigned ia;
+                 nargs = list_length (arg_types);
+                 args = XALLOCAVEC (tree, nargs);
+                 for (arg = arg_types, ia = 0; arg != NULL_TREE;
+                      arg = TREE_CHAIN (arg), ++ia)
+                   args[ia] = TREE_VALUE (arg);

Had to adjust this hunk because we want args[0] to be ptr_type_node
here and nargs to be list_length (t) + 1.

+         tree fntype = static_fn_type (elt);
+         if (!compparms (TYPE_ARG_TYPES (t), TYPE_ARG_TYPES (fntype)))

...that we're only going to pull the TYPE_ARG_TYPES back out of.  And we can
also use FUNCTION_ARG_CHAIN (elt) here instead of prepending ptr_type_node
above.  static_fn_type seems unnecessary since operator delete is always
static.

Changed too.

So far lightly tested, ok for trunk if it passes full bootstrap/regtest?

2026-09-21  Jakub Jelinek  <[email protected]>

        P3769R1
        PR c++/125848
        * call.cc (build_op_delete_call_1): Implement C++26
        P3769R1 - Clarification of placement new deallocation.  Instead of
        calling instantiate_type to select placement deallocation function
        iterate over OVERLOAD if any, perform argument deduction for
        templates, ignore candidates with different parameter type lists
        or unsatisfied constraints and if only one candidate remains,
        use it, otherwise don't destruct on throw.

        * g++.dg/cpp26/placement-new1.C: New test.

--- a/gcc/cp/call.cc    2026-09-16 22:17:02.640462648 +0200
+++ b/gcc/cp/call.cc    2026-09-21 14:47:20.784522801 +0200
@@ -8127,28 +8127,69 @@ build_op_delete_call_1 (enum tree_code c
if (placement)
      {
-      /* "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."
+      /* For a placement allocation function, the matching deallocation
+        function is selected as follows:
- So we build up the function type we want and ask instantiate_type
-        to get it for us.  */
+        - Each candidate that is a function template is replaced by the
+          function template specializations (if any) generated using template
+          argument deduction with arguments as specified below.
+        - Each candidate whose parameter-type-list is not identical to that
+          of the allocation function, ignoring their respective first
+          parameters, is removed from the set of candidates.
+        - Each candidate whose associated constraints (if any) are not
+          satisfied is removed from the set of candidates.
+        - If exactly one function remains, that function is selected.
+        - Otherwise, no deallocation function is selected.  */
        t = FUNCTION_ARG_CHAIN (alloc_fn);
-      t = tree_cons (NULL_TREE, ptr_type_node, t);
-      t = build_function_type (void_type_node, t);
+      fn = NULL_TREE;
+      tree *args = NULL;
+      unsigned nargs = 0;
+      for (tree elt : lkp_range (MAYBE_BASELINK_FUNCTIONS (fns)))
+       {
+         if (TREE_CODE (elt) == TEMPLATE_DECL)
+           {
+             tree targs = make_tree_vec (DECL_NTPARMS (elt));
+             if (args == NULL)
+               {
+                 tree arg;
+                 unsigned ia;
+                 nargs = list_length (t) + 1;
+                 args = XALLOCAVEC (tree, nargs);
+                 args[0] = ptr_type_node;
+                 for (arg = t, ia = 1; arg != NULL_TREE;
+                      arg = TREE_CHAIN (arg), ++ia)
+                   args[ia] = TREE_VALUE (arg);

"as specified below" refers to https://eel.is/c++draft/expr.new#32
so instead of filling args with the parameter types from alloc_fn, we should use the same actual arguments that are used for the call later in the function.

Jason

Reply via email to