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