Message ID | 20200522142819.215677-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: P0848R3 and member function templates [PR95181] | expand |
On Fri, 22 May 2020, Patrick Palka wrote: > When comparing two special member function templates to see if one hides > the other (as per P0848R3), we need to check satisfaction which we can't > do on templates. So this patch makes add_method skip the eligibility > test on member function templates and just lets them coexist. > > Passes 'make check-c++', does this look OK to commit to master and later > to the 10 branch? ... after a full bootstrap and regtest on x86_64-pc-linux-gnu, of course.
On Fri, 22 May 2020, Patrick Palka wrote: > When comparing two special member function templates to see if one hides > the other (as per P0848R3), we need to check satisfaction which we can't > do on templates. So this patch makes add_method skip the eligibility > test on member function templates and just lets them coexist. It just occurred to me that this problem isn't limited to member function templates. Consider this valid testcase which we currently reject: template<bool B> struct g { g() requires B && false; g() requires B; }; g<true> b; // error During add_method, we check satisfaction of both default constructors, and since their constraints are dependent, constraints_satisfied_p returns true for both sets of constraints. We then see that 'B && false' is more constrained than 'B' and therefore discard the second constructor. Since we discarded the second default constructor at definition time, the instantiation g<true> has no eligible default constructor. I am not sure what to do from here... > > Passes 'make check-c++', does this look OK to commit to master and later > to the 10 branch? > > gcc/cp/ChangeLog: > > PR c++/95181 > * class.c (add_method): Let special member function templates > coexist if they are not equivalently constrained. > > gcc/testsuite/ChangeLog: > > PR c++/95181 > * g++.dg/concepts/pr95181.C: New test. > --- > gcc/cp/class.c | 10 ++++++---- > gcc/testsuite/g++.dg/concepts/pr95181.C | 9 +++++++++ > 2 files changed, 15 insertions(+), 4 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/concepts/pr95181.C > > diff --git a/gcc/cp/class.c b/gcc/cp/class.c > index bab15524a60..cb268d191d6 100644 > --- a/gcc/cp/class.c > +++ b/gcc/cp/class.c > @@ -1079,10 +1079,12 @@ add_method (tree type, tree method, bool via_using) > { > special_function_kind sfk = special_memfn_p (method); > > - if (sfk == sfk_none || DECL_INHERITED_CTOR (fn)) > - /* Non-special member functions coexist if they are not > - equivalently constrained. A member function is not hidden > - by an inherited constructor. */ > + if (sfk == sfk_none > + || DECL_INHERITED_CTOR (fn) > + || TREE_CODE (fn) == TEMPLATE_DECL) > + /* Member function templates and non-special member functions > + coexist if they are not equivalently constrained. A member > + function is not hidden by an inherited constructor. */ > continue; > > /* P0848: For special member functions, deleted, unsatisfied, or > diff --git a/gcc/testsuite/g++.dg/concepts/pr95181.C b/gcc/testsuite/g++.dg/concepts/pr95181.C > new file mode 100644 > index 00000000000..0185c86b438 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/concepts/pr95181.C > @@ -0,0 +1,9 @@ > +// PR c++/95181 > +// { dg-do compile { target concepts } } > + > +template <typename> struct f { > + template <typename T=int> f(); > + template <typename T=int> requires false f(); > +}; > + > +f<int> a; > -- > 2.27.0.rc1.5.gae92ac8ae3 > >
On 5/22/20 10:56 AM, Patrick Palka wrote: > On Fri, 22 May 2020, Patrick Palka wrote: > >> When comparing two special member function templates to see if one hides >> the other (as per P0848R3), we need to check satisfaction which we can't >> do on templates. So this patch makes add_method skip the eligibility >> test on member function templates and just lets them coexist. > > It just occurred to me that this problem isn't limited to member function > templates. Consider this valid testcase which we currently reject: > > template<bool B> struct g { > g() requires B && false; > g() requires B; > }; > > g<true> b; // error > > During add_method, we check satisfaction of both default constructors, > and since their constraints are dependent, constraints_satisfied_p > returns true for both sets of constraints. We then see that > 'B && false' is more constrained than 'B' and therefore discard the second > constructor. Since we discarded the second default constructor at > definition time, the instantiation g<true> has no eligible default > constructor. > > I am not sure what to do from here... I looked at this and it seems enough to let the functions coexist without trying to compare their constraints if processing_template_decl; we'll handle the hiding properly when the class template is instantiated. So this is what I'm committing:
On Fri, 29 May 2020, Jason Merrill wrote: > On 5/22/20 10:56 AM, Patrick Palka wrote: > > On Fri, 22 May 2020, Patrick Palka wrote: > > > > > When comparing two special member function templates to see if one hides > > > the other (as per P0848R3), we need to check satisfaction which we can't > > > do on templates. So this patch makes add_method skip the eligibility > > > test on member function templates and just lets them coexist. > > > > It just occurred to me that this problem isn't limited to member function > > templates. Consider this valid testcase which we currently reject: > > > > template<bool B> struct g { > > g() requires B && false; > > g() requires B; > > }; > > > > g<true> b; // error > > > > During add_method, we check satisfaction of both default constructors, > > and since their constraints are dependent, constraints_satisfied_p > > returns true for both sets of constraints. We then see that > > 'B && false' is more constrained than 'B' and therefore discard the second > > constructor. Since we discarded the second default constructor at > > definition time, the instantiation g<true> has no eligible default > > constructor. > > > > I am not sure what to do from here... > > I looked at this and it seems enough to let the functions coexist without > trying to compare their constraints if processing_template_decl; we'll handle > the hiding properly when the class template is instantiated. > > So this is what I'm committing: Aha, that makes sense now, thanks! Somehow I convinced myself that during class template instantiation we don't call add_method, so I instead tried to remove that block of code from add_method altogether. Needless to say that didn't work very well..
diff --git a/gcc/cp/class.c b/gcc/cp/class.c index bab15524a60..cb268d191d6 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -1079,10 +1079,12 @@ add_method (tree type, tree method, bool via_using) { special_function_kind sfk = special_memfn_p (method); - if (sfk == sfk_none || DECL_INHERITED_CTOR (fn)) - /* Non-special member functions coexist if they are not - equivalently constrained. A member function is not hidden - by an inherited constructor. */ + if (sfk == sfk_none + || DECL_INHERITED_CTOR (fn) + || TREE_CODE (fn) == TEMPLATE_DECL) + /* Member function templates and non-special member functions + coexist if they are not equivalently constrained. A member + function is not hidden by an inherited constructor. */ continue; /* P0848: For special member functions, deleted, unsatisfied, or diff --git a/gcc/testsuite/g++.dg/concepts/pr95181.C b/gcc/testsuite/g++.dg/concepts/pr95181.C new file mode 100644 index 00000000000..0185c86b438 --- /dev/null +++ b/gcc/testsuite/g++.dg/concepts/pr95181.C @@ -0,0 +1,9 @@ +// PR c++/95181 +// { dg-do compile { target concepts } } + +template <typename> struct f { + template <typename T=int> f(); + template <typename T=int> requires false f(); +}; + +f<int> a;