diff mbox series

c++: P0848R3 and member function templates [PR95181]

Message ID 20200522142819.215677-1-ppalka@redhat.com
State New
Headers show
Series c++: P0848R3 and member function templates [PR95181] | expand

Commit Message

Patrick Palka May 22, 2020, 2:28 p.m. UTC
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?

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

Comments

Patrick Palka May 22, 2020, 2:31 p.m. UTC | #1
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.
Patrick Palka May 22, 2020, 2:56 p.m. UTC | #2
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
> 
>
Jason Merrill May 29, 2020, 10:19 p.m. UTC | #3
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:
Patrick Palka May 30, 2020, 4:17 a.m. UTC | #4
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 mbox series

Patch

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;