diff mbox series

[pushed] c++: address deduction and concepts [CWG2918]

Message ID 20241014192916.4119199-1-jason@redhat.com
State New
Headers show
Series [pushed] c++: address deduction and concepts [CWG2918] | expand

Commit Message

Jason Merrill Oct. 14, 2024, 7:28 p.m. UTC
Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

CWG2918 changes deduction from an overload set for the case where multiple
candidates succeed and have the same type; previously this made the overload
set a non-deduced context, now it succeeds since the result is consistent
between the candidates.

This is needed for cases of overloading based on requirements, where we want
to choose the most constrained overload.  I also needed to adjust
resolve_address_of_overloaded_function accordingly; we already handled the
comparison for template candidates in most_specialized_instantiation, but
need to also do the comparison for non-template candidates such as member
functions of a class template.

	CWG 2918 (proposed)

gcc/cp/ChangeLog:

	* cp-tree.h (most_constrained_function): Declare..
	* class.cc (resolve_address_of_overloaded_function): Call it.
	* pt.cc (get_template_for_ordering): Handle list from
	resolve_address_of_overloaded_function.
	(most_constrained_function): No longer static.
	(resolve_overloaded_unification): Always compare type rather
	than decl.

gcc/testsuite/ChangeLog:

	* g++.dg/DRs/dr2918.C: New test.
---
 gcc/cp/cp-tree.h                  |  1 +
 gcc/cp/class.cc                   | 13 ++++++++++---
 gcc/cp/pt.cc                      | 18 ++++++++++++++----
 gcc/testsuite/g++.dg/DRs/dr2918.C | 11 +++++++++++
 4 files changed, 36 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/DRs/dr2918.C


base-commit: fa04a1713b54bdc4c7b686c88117c9c46043ec73

Comments

Patrick Palka Oct. 14, 2024, 8:50 p.m. UTC | #1
On Mon, 14 Oct 2024, Jason Merrill wrote:

> Tested x86_64-pc-linux-gnu, applying to trunk.
> 
> -- 8< --
> 
> CWG2918 changes deduction from an overload set for the case where multiple
> candidates succeed and have the same type; previously this made the overload
> set a non-deduced context, now it succeeds since the result is consistent
> between the candidates.
> 
> This is needed for cases of overloading based on requirements, where we want
> to choose the most constrained overload.  I also needed to adjust
> resolve_address_of_overloaded_function accordingly; we already handled the
> comparison for template candidates in most_specialized_instantiation, but
> need to also do the comparison for non-template candidates such as member
> functions of a class template.
> 
> 	CWG 2918 (proposed)
> 
> gcc/cp/ChangeLog:
> 
> 	* cp-tree.h (most_constrained_function): Declare..
> 	* class.cc (resolve_address_of_overloaded_function): Call it.
> 	* pt.cc (get_template_for_ordering): Handle list from
> 	resolve_address_of_overloaded_function.
> 	(most_constrained_function): No longer static.
> 	(resolve_overloaded_unification): Always compare type rather
> 	than decl.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/DRs/dr2918.C: New test.
> ---
>  gcc/cp/cp-tree.h                  |  1 +
>  gcc/cp/class.cc                   | 13 ++++++++++---
>  gcc/cp/pt.cc                      | 18 ++++++++++++++----
>  gcc/testsuite/g++.dg/DRs/dr2918.C | 11 +++++++++++
>  4 files changed, 36 insertions(+), 7 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/DRs/dr2918.C
> 
> diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> index dc153a97dc4..94ee550bd9c 100644
> --- a/gcc/cp/cp-tree.h
> +++ b/gcc/cp/cp-tree.h
> @@ -7593,6 +7593,7 @@ extern int template_args_equal                  (tree, tree);
>  extern tree maybe_process_partial_specialization (tree);
>  extern tree most_specialized_instantiation	(tree);
>  extern tree most_specialized_partial_spec       (tree, tsubst_flags_t, bool = false);
> +extern tree most_constrained_function		(tree);
>  extern void print_candidates			(tree);
>  extern void instantiate_pending_templates	(int);
>  extern tree tsubst_default_argument		(tree, int, tree, tree,
> diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
> index 646072d4f20..8c39bb4a76b 100644
> --- a/gcc/cp/class.cc
> +++ b/gcc/cp/class.cc
> @@ -8896,11 +8896,18 @@ resolve_address_of_overloaded_function (tree target_type,
>  	  tree match = most_specialized_instantiation (matches);
>  
>  	  if (match != error_mark_node)
> -	    matches = tree_cons (TREE_PURPOSE (match),
> -				 NULL_TREE,
> -				 NULL_TREE);
> +	    {
> +	      matches = match;
> +	      TREE_CHAIN (match) = NULL_TREE;
> +	    }
>  	}
>      }
> +  else if (flag_concepts && TREE_CHAIN (matches))
> +    if (tree match = most_constrained_function (matches))
> +      {
> +	matches = match;
> +	TREE_CHAIN (match) = NULL_TREE;
> +      }
>  
>    /* Now we should have exactly one function in MATCHES.  */
>    if (matches == NULL_TREE)
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index 03a1144765b..c0a37a51cba 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -2071,6 +2071,10 @@ get_template_for_ordering (tree list)
>  {
>    gcc_assert (TREE_CODE (list) == TREE_LIST);
>    tree f = TREE_VALUE (list);
> +  if (f == NULL_TREE)
> +    /* Also handle a list from resolve_address_of_overloaded_function with the
> +       function in TREE_PURPOSE.  */
> +    f = TREE_PURPOSE (list);
>    if (tree ti = DECL_TEMPLATE_INFO (f))
>      return TI_TEMPLATE (ti);
>    return f;
> @@ -2084,7 +2088,7 @@ get_template_for_ordering (tree list)
>  
>     Note that we don't compare constraints on the functions
>     themselves, but rather those of their templates. */
> -static tree
> +tree
>  most_constrained_function (tree candidates)
>  {
>    // Try to find the best candidate in a first pass.
> @@ -23865,11 +23869,14 @@ resolve_overloaded_unification (tree tparms,
>  	tree fn = *iter;
>  	if (flag_noexcept_type)
>  	  maybe_instantiate_noexcept (fn, tf_none);
> -	if (try_one_overload (tparms, targs, tempargs, parm, TREE_TYPE (fn),
> +	if (TREE_CODE (fn) == FUNCTION_DECL && !constraints_satisfied_p (fn))
> +	  continue;

FWIW this seems to also fix PR80637 (in which we weren't discarding
functions with unsatisfied constraints when resolving &A<int>::f).

> +	tree elem = TREE_TYPE (fn);
> +	if (try_one_overload (tparms, targs, tempargs, parm, elem,
>  			      strict, sub_strict, addr_p, explain_p)
> -	    && (!goodfn || !decls_match (goodfn, fn)))
> +	    && (!goodfn || !same_type_p (goodfn, elem)))
>  	  {
> -	    goodfn = fn;
> +	    goodfn = elem;
>  	    ++good;
>  	  }
>        }
> @@ -23879,6 +23886,9 @@ resolve_overloaded_unification (tree tparms,
>       overloaded functions does not contain function templates and at most
>       one of a set of overloaded functions provides a unique match.
>  
> +     CWG2918 allows multiple functions to match if they all have the same type,
> +     so that we can choose the most constrained later.
> +
>       So if we found multiple possibilities, we return success but don't
>       deduce anything.  */
>  
> diff --git a/gcc/testsuite/g++.dg/DRs/dr2918.C b/gcc/testsuite/g++.dg/DRs/dr2918.C
> new file mode 100644
> index 00000000000..982ced71f1f
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/DRs/dr2918.C
> @@ -0,0 +1,11 @@
> +// CWG 2918 makes this OK
> +// { dg-do compile { target c++20 } }
> +
> +template<bool B> struct X {
> +  static void f(short) requires B; // #1
> +  static void f(short);		   // #2
> +};
> +void test() {
> +  auto x = &X<true>::f;		// OK, deduces void(*)(short), selects #1
> +  auto y = &X<false>::f;	// OK, deduces void(*)(short), selects #2
> +}
> 
> base-commit: fa04a1713b54bdc4c7b686c88117c9c46043ec73
> -- 
> 2.47.0
> 
>
diff mbox series

Patch

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index dc153a97dc4..94ee550bd9c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7593,6 +7593,7 @@  extern int template_args_equal                  (tree, tree);
 extern tree maybe_process_partial_specialization (tree);
 extern tree most_specialized_instantiation	(tree);
 extern tree most_specialized_partial_spec       (tree, tsubst_flags_t, bool = false);
+extern tree most_constrained_function		(tree);
 extern void print_candidates			(tree);
 extern void instantiate_pending_templates	(int);
 extern tree tsubst_default_argument		(tree, int, tree, tree,
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 646072d4f20..8c39bb4a76b 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -8896,11 +8896,18 @@  resolve_address_of_overloaded_function (tree target_type,
 	  tree match = most_specialized_instantiation (matches);
 
 	  if (match != error_mark_node)
-	    matches = tree_cons (TREE_PURPOSE (match),
-				 NULL_TREE,
-				 NULL_TREE);
+	    {
+	      matches = match;
+	      TREE_CHAIN (match) = NULL_TREE;
+	    }
 	}
     }
+  else if (flag_concepts && TREE_CHAIN (matches))
+    if (tree match = most_constrained_function (matches))
+      {
+	matches = match;
+	TREE_CHAIN (match) = NULL_TREE;
+      }
 
   /* Now we should have exactly one function in MATCHES.  */
   if (matches == NULL_TREE)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 03a1144765b..c0a37a51cba 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -2071,6 +2071,10 @@  get_template_for_ordering (tree list)
 {
   gcc_assert (TREE_CODE (list) == TREE_LIST);
   tree f = TREE_VALUE (list);
+  if (f == NULL_TREE)
+    /* Also handle a list from resolve_address_of_overloaded_function with the
+       function in TREE_PURPOSE.  */
+    f = TREE_PURPOSE (list);
   if (tree ti = DECL_TEMPLATE_INFO (f))
     return TI_TEMPLATE (ti);
   return f;
@@ -2084,7 +2088,7 @@  get_template_for_ordering (tree list)
 
    Note that we don't compare constraints on the functions
    themselves, but rather those of their templates. */
-static tree
+tree
 most_constrained_function (tree candidates)
 {
   // Try to find the best candidate in a first pass.
@@ -23865,11 +23869,14 @@  resolve_overloaded_unification (tree tparms,
 	tree fn = *iter;
 	if (flag_noexcept_type)
 	  maybe_instantiate_noexcept (fn, tf_none);
-	if (try_one_overload (tparms, targs, tempargs, parm, TREE_TYPE (fn),
+	if (TREE_CODE (fn) == FUNCTION_DECL && !constraints_satisfied_p (fn))
+	  continue;
+	tree elem = TREE_TYPE (fn);
+	if (try_one_overload (tparms, targs, tempargs, parm, elem,
 			      strict, sub_strict, addr_p, explain_p)
-	    && (!goodfn || !decls_match (goodfn, fn)))
+	    && (!goodfn || !same_type_p (goodfn, elem)))
 	  {
-	    goodfn = fn;
+	    goodfn = elem;
 	    ++good;
 	  }
       }
@@ -23879,6 +23886,9 @@  resolve_overloaded_unification (tree tparms,
      overloaded functions does not contain function templates and at most
      one of a set of overloaded functions provides a unique match.
 
+     CWG2918 allows multiple functions to match if they all have the same type,
+     so that we can choose the most constrained later.
+
      So if we found multiple possibilities, we return success but don't
      deduce anything.  */
 
diff --git a/gcc/testsuite/g++.dg/DRs/dr2918.C b/gcc/testsuite/g++.dg/DRs/dr2918.C
new file mode 100644
index 00000000000..982ced71f1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/DRs/dr2918.C
@@ -0,0 +1,11 @@ 
+// CWG 2918 makes this OK
+// { dg-do compile { target c++20 } }
+
+template<bool B> struct X {
+  static void f(short) requires B; // #1
+  static void f(short);		   // #2
+};
+void test() {
+  auto x = &X<true>::f;		// OK, deduces void(*)(short), selects #1
+  auto y = &X<false>::f;	// OK, deduces void(*)(short), selects #2
+}