Message ID | 20220104180113.141274-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: "more constrained" vs staticness of memfn [PR103783] | expand |
On 1/4/22 13:01, Patrick Palka wrote: > Here we're rejecting the calls to g1 and g2 as ambiguous even though one > overload is more constrained than the other (and otherwise equivalent), > because the implicit 'this' parameter of the non-static overload causes > cand_parms_match to think the function parameter lists aren't equivalent. > > This patch fixes this by making cand_parms_match skip over 'this' > appropriately. Note that this bug only occurs with non-template member > functions because for the template case more_specialized_fns seems to > already skips over 'this' appropriately. > > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk and perhaps 11? OK for both. > PR c++/103783 > > gcc/cp/ChangeLog: > > * call.c (cand_parms_match): Skip over 'this' when given one > static and one non-static member function. Declare static. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp2a/concepts-memfun2.C: New test. > --- > gcc/cp/call.c | 17 ++++++++++--- > gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C | 25 +++++++++++++++++++ > 2 files changed, 39 insertions(+), 3 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C > > diff --git a/gcc/cp/call.c b/gcc/cp/call.c > index 7f7ee88deed..ed74b907828 100644 > --- a/gcc/cp/call.c > +++ b/gcc/cp/call.c > @@ -11918,7 +11918,7 @@ joust_maybe_elide_copy (z_candidate *&cand) > /* True if the defining declarations of the two candidates have equivalent > parameters. */ > > -bool > +static bool > cand_parms_match (z_candidate *c1, z_candidate *c2) > { > tree fn1 = c1->fn; > @@ -11940,8 +11940,19 @@ cand_parms_match (z_candidate *c1, z_candidate *c2) > fn1 = DECL_TEMPLATE_RESULT (t1); > fn2 = DECL_TEMPLATE_RESULT (t2); > } > - return compparms (TYPE_ARG_TYPES (TREE_TYPE (fn1)), > - TYPE_ARG_TYPES (TREE_TYPE (fn2))); > + tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1)); > + tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2)); > + if (DECL_FUNCTION_MEMBER_P (fn1) > + && DECL_FUNCTION_MEMBER_P (fn2) > + && (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn1) > + != DECL_NONSTATIC_MEMBER_FUNCTION_P (fn2))) > + { > + /* Ignore 'this' when comparing the parameters of a static member > + function with those of a non-static one. */ > + parms1 = skip_artificial_parms_for (fn1, parms1); > + parms2 = skip_artificial_parms_for (fn2, parms2); > + } > + return compparms (parms1, parms2); > } > > /* Compare two candidates for overloading as described in > diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C > new file mode 100644 > index 00000000000..e3845e48387 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C > @@ -0,0 +1,25 @@ > +// PR c++/103783 > +// { dg-do compile { target c++20 } } > + > +template<bool B> > +struct A { > + template<class...> void f1() = delete; > + template<class...> static void f1() requires B; > + > + template<class...> void f2() requires B; > + template<class...> static void f2() = delete; > + > + void g1() = delete; > + static void g1() requires B; > + > + void g2() requires B; > + static void g2() = delete; > +}; > + > +int main() { > + A<true> a; > + a.f1(); // OK > + a.f2(); // OK > + a.g1(); // OK, previously rejected as ambiguous > + a.g2(); // OK, previously rejected as ambiguous > +}
diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 7f7ee88deed..ed74b907828 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -11918,7 +11918,7 @@ joust_maybe_elide_copy (z_candidate *&cand) /* True if the defining declarations of the two candidates have equivalent parameters. */ -bool +static bool cand_parms_match (z_candidate *c1, z_candidate *c2) { tree fn1 = c1->fn; @@ -11940,8 +11940,19 @@ cand_parms_match (z_candidate *c1, z_candidate *c2) fn1 = DECL_TEMPLATE_RESULT (t1); fn2 = DECL_TEMPLATE_RESULT (t2); } - return compparms (TYPE_ARG_TYPES (TREE_TYPE (fn1)), - TYPE_ARG_TYPES (TREE_TYPE (fn2))); + tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1)); + tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2)); + if (DECL_FUNCTION_MEMBER_P (fn1) + && DECL_FUNCTION_MEMBER_P (fn2) + && (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn1) + != DECL_NONSTATIC_MEMBER_FUNCTION_P (fn2))) + { + /* Ignore 'this' when comparing the parameters of a static member + function with those of a non-static one. */ + parms1 = skip_artificial_parms_for (fn1, parms1); + parms2 = skip_artificial_parms_for (fn2, parms2); + } + return compparms (parms1, parms2); } /* Compare two candidates for overloading as described in diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C new file mode 100644 index 00000000000..e3845e48387 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun2.C @@ -0,0 +1,25 @@ +// PR c++/103783 +// { dg-do compile { target c++20 } } + +template<bool B> +struct A { + template<class...> void f1() = delete; + template<class...> static void f1() requires B; + + template<class...> void f2() requires B; + template<class...> static void f2() = delete; + + void g1() = delete; + static void g1() requires B; + + void g2() requires B; + static void g2() = delete; +}; + +int main() { + A<true> a; + a.f1(); // OK + a.f2(); // OK + a.g1(); // OK, previously rejected as ambiguous + a.g2(); // OK, previously rejected as ambiguous +}