]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: non-standalone surrogate call template
authorPatrick Palka <ppalka@redhat.com>
Tue, 18 Jul 2023 13:22:49 +0000 (09:22 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 18 Jul 2023 13:22:49 +0000 (09:22 -0400)
I noticed we're accidentally prevented from considering a pointer- or
reference-to-function conversion function template if it's not the first
conversion function that's considered, which for the testcase below
results in us accepting the B call but not the A call despite the only
difference between A and B being their order of member declarations.
This patch fixes this so that the outcome of overload resolution doesn't
arbitrarily depend on declaration order here.

gcc/cp/ChangeLog:

* call.cc (add_template_conv_candidate): Don't check for
non-empty 'candidates' here.
(build_op_call): Check it here, before we've considered any
conversion functions.

gcc/testsuite/ChangeLog:

* g++.dg/overload/conv-op5.C: New test.

gcc/cp/call.cc
gcc/testsuite/g++.dg/overload/conv-op5.C [new file with mode: 0644]

index 24f93dd983ca08017eb39f8b6b845aa257629d7c..b55230d98aae42eede13eabda647bc8c5ce8629c 100644 (file)
@@ -3709,12 +3709,6 @@ add_template_conv_candidate (struct z_candidate **candidates, tree tmpl,
                             tree return_type, tree access_path,
                             tree conversion_path, tsubst_flags_t complain)
 {
-  /* Making this work broke PR 71117 and 85118, so until the committee resolves
-     core issue 2189, let's disable this candidate if there are any call
-     operators.  */
-  if (*candidates)
-    return NULL;
-
   return
     add_template_candidate_real (candidates, tmpl, NULL_TREE, NULL_TREE,
                                 NULL_TREE, arglist, return_type, access_path,
@@ -5290,6 +5284,8 @@ build_op_call (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
                      LOOKUP_NORMAL, &candidates, complain);
     }
 
+  bool any_call_ops = candidates != nullptr;
+
   convs = lookup_conversions (type);
 
   for (; convs; convs = TREE_CHAIN (convs))
@@ -5306,10 +5302,18 @@ build_op_call (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
              continue;
 
            if (TREE_CODE (fn) == TEMPLATE_DECL)
-             add_template_conv_candidate
-               (&candidates, fn, obj, *args, totype,
-                /*access_path=*/NULL_TREE,
-                /*conversion_path=*/NULL_TREE, complain);
+             {
+               /* Making this work broke PR 71117 and 85118, so until the
+                  committee resolves core issue 2189, let's disable this
+                  candidate if there are any call operators.  */
+               if (any_call_ops)
+                 continue;
+
+               add_template_conv_candidate
+                 (&candidates, fn, obj, *args, totype,
+                  /*access_path=*/NULL_TREE,
+                  /*conversion_path=*/NULL_TREE, complain);
+             }
            else
              add_conv_candidate (&candidates, fn, obj,
                                  *args, /*conversion_path=*/NULL_TREE,
diff --git a/gcc/testsuite/g++.dg/overload/conv-op5.C b/gcc/testsuite/g++.dg/overload/conv-op5.C
new file mode 100644 (file)
index 0000000..4f75092
--- /dev/null
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++11 } }
+
+template<class T> using F = int(*)(T);
+using G = int(*)(int*);
+
+struct A {
+  template<class T> operator F<T>(); // #1
+  operator G() = delete; // #2
+};
+
+struct B {
+  operator G() = delete; // #2
+  template<class T> operator F<T>(); // #1
+};
+
+int i = A{}(0); // OK, selects #1
+int j = B{}(0); // OK, selects #1