diff mbox series

c++: Check template parameter number in member class template specialization [PR115716]

Message ID 010201917b0007f4-5efc7097-713a-4643-a96d-fd4ef225b9ef-000000@eu-west-1.amazonses.com
State New
Headers show
Series c++: Check template parameter number in member class template specialization [PR115716] | expand

Commit Message

Simon Martin Aug. 22, 2024, 4:51 p.m. UTC
We currently ICE upon the following invalid code, because we don't check the
number of template parameters in member class template specializations. This
patch fixes the PR by adding such a check.

=== cut here ===
template <typename T> struct x {
  template <typename U> struct y {
    typedef T result2;
  };
};
template<> template<typename U, typename> struct x<int>::y {
  typedef double result2;
};
int main() {
  x<int>::y<int>::result2 xxx2;
}
=== cut here ===

Successfully tested on x86_64-pc-linux-gnu.

	PR c++/115716

gcc/cp/ChangeLog:

	* pt.cc (maybe_process_partial_specialization): Check number of
	template parameters in specialization.

gcc/testsuite/ChangeLog:

	* g++.dg/template/spec42.C: New test.

---
 gcc/cp/pt.cc                           | 14 ++++++++++++++
 gcc/testsuite/g++.dg/template/spec42.C | 17 +++++++++++++++++
 2 files changed, 31 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/spec42.C

Comments

Jason Merrill Aug. 22, 2024, 5:28 p.m. UTC | #1
On 8/22/24 12:51 PM, Simon Martin wrote:
> We currently ICE upon the following invalid code, because we don't check the
> number of template parameters in member class template specializations. This
> patch fixes the PR by adding such a check.
> 
> === cut here ===
> template <typename T> struct x {
>    template <typename U> struct y {
>      typedef T result2;
>    };
> };
> template<> template<typename U, typename> struct x<int>::y {
>    typedef double result2;
> };
> int main() {
>    x<int>::y<int>::result2 xxx2;
> }
> === cut here ===
> 
> Successfully tested on x86_64-pc-linux-gnu.
> 
> 	PR c++/115716
> 
> gcc/cp/ChangeLog:
> 
> 	* pt.cc (maybe_process_partial_specialization): Check number of
> 	template parameters in specialization.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/template/spec42.C: New test.
> 
> ---
>   gcc/cp/pt.cc                           | 14 ++++++++++++++
>   gcc/testsuite/g++.dg/template/spec42.C | 17 +++++++++++++++++
>   2 files changed, 31 insertions(+)
>   create mode 100644 gcc/testsuite/g++.dg/template/spec42.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index bc3ad5edcc5..db8c2a3b4de 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -1173,6 +1173,20 @@ maybe_process_partial_specialization (tree type)
>   		       type, inst);
>   	    }
>   
> +	  /* Check that the number of template parameters matches the template
> +	     being specialized.  */
> +	  gcc_assert (current_template_parms);
> +	  if (TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS
> +			       (CLASSTYPE_TI_ARGS (type)))
> +	      != TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
> +				  (current_template_parms)))
> +	    {
> +	      error ("wrong number of template parameters for %qT", type);
> +	      inform (DECL_SOURCE_LOCATION (tmpl), "from definition of %q#D",
> +		      tmpl);

How about printing the numbers for each place?

What if the mismatch is other than in the number of parameters?  Can you 
use template_parameter_lists_equivalent_p?  Or if that's complicated, 
compare current_template_args() to CLASSTYPE_TI_ARGS (type)?

Jason
Simon Martin Aug. 26, 2024, 8:26 a.m. UTC | #2
Hi Jason,

On 22 Aug 2024, at 19:28, Jason Merrill wrote:

> On 8/22/24 12:51 PM, Simon Martin wrote:
>> We currently ICE upon the following invalid code, because we don't 
>> check the
>> number of template parameters in member class template 
>> specializations. This
>> patch fixes the PR by adding such a check.
>>
>> === cut here ===
>> template <typename T> struct x {
>>    template <typename U> struct y {
>>      typedef T result2;
>>    };
>> };
>> template<> template<typename U, typename> struct x<int>::y {
>>    typedef double result2;
>> };
>> int main() {
>>    x<int>::y<int>::result2 xxx2;
>> }
>> === cut here ===
>>
>> Successfully tested on x86_64-pc-linux-gnu.
>>
>> 	PR c++/115716
>>
>> gcc/cp/ChangeLog:
>>
>> 	* pt.cc (maybe_process_partial_specialization): Check number of
>> 	template parameters in specialization.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	* g++.dg/template/spec42.C: New test.
>>
>> ---
>>   gcc/cp/pt.cc                           | 14 ++++++++++++++
>>   gcc/testsuite/g++.dg/template/spec42.C | 17 +++++++++++++++++
>>   2 files changed, 31 insertions(+)
>>   create mode 100644 gcc/testsuite/g++.dg/template/spec42.C
>>
>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
>> index bc3ad5edcc5..db8c2a3b4de 100644
>> --- a/gcc/cp/pt.cc
>> +++ b/gcc/cp/pt.cc
>> @@ -1173,6 +1173,20 @@ maybe_process_partial_specialization (tree 
>> type)
>>   		       type, inst);
>>   	    }
>>  +	  /* Check that the number of template parameters matches the 
>> template
>> +	     being specialized.  */
>> +	  gcc_assert (current_template_parms);
>> +	  if (TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS
>> +			       (CLASSTYPE_TI_ARGS (type)))
>> +	      != TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
>> +				  (current_template_parms)))
>> +	    {
>> +	      error ("wrong number of template parameters for %qT", type);
>> +	      inform (DECL_SOURCE_LOCATION (tmpl), "from definition of 
>> %q#D",
>> +		      tmpl);
>
> How about printing the numbers for each place?
>
> What if the mismatch is other than in the number of parameters?  Can 
> you use template_parameter_lists_equivalent_p?  Or if that's 
> complicated, compare current_template_args() to CLASSTYPE_TI_ARGS 
> (type)?
>
Thanks for the review. After checking further, I believe we just miss a 
call to redeclare_class_template, that will catch various template 
parameter mismatch and properly report them.

This is what the updated attached patch does, successfully tested on 
x86_64-pc-linux-gnu. OK for trunk?

Thanks,
   Simon

> Jason
From 7e817c158e7d2e83e0283c3fa892370dbf9a238a Mon Sep 17 00:00:00 2001
From: Simon Martin <simon@nasilyan.com>
Date: Sun, 25 Aug 2024 21:59:31 +0200
Subject: [PATCH] c++: Check template parameters in member class template specialization [PR115716]

We currently ICE upon the following invalid code, because we don't check
that the template parameters in a member class template specialization
are correct.

=== cut here ===
template <typename T> struct x {
  template <typename U> struct y {
    typedef T result2;
  };
};
template<> template<typename U, typename> struct x<int>::y {
  typedef double result2;
};
int main() {
  x<int>::y<int>::result2 xxx2;
}
=== cut here ===

This patch fixes the PR by calling redeclare_class_template.

Successfully tested on x86_64-pc-linux-gnu.

	PR c++/115716

gcc/cp/ChangeLog:

	* pt.cc (maybe_process_partial_specialization): Call
	redeclare_class_template.

gcc/testsuite/ChangeLog:

	* g++.dg/template/spec42.C: New test.
	* g++.dg/template/spec43.C: New test.

---
 gcc/cp/pt.cc                           |  5 +++++
 gcc/testsuite/g++.dg/template/spec42.C | 17 +++++++++++++++++
 gcc/testsuite/g++.dg/template/spec43.C | 18 ++++++++++++++++++
 3 files changed, 40 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/template/spec42.C
 create mode 100644 gcc/testsuite/g++.dg/template/spec43.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bc3ad5edcc5..24a6241d3a5 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1173,6 +1173,11 @@ maybe_process_partial_specialization (tree type)
 		       type, inst);
 	    }
 
+	  /* Make sure that the specialization is valid.  */
+	  if (!redeclare_class_template (type, current_template_parms,
+					 current_template_constraints ()))
+	    return error_mark_node;
+
 	  /* Mark TYPE as a specialization.  And as a result, we only
 	     have one level of template argument for the innermost
 	     class template.  */
diff --git a/gcc/testsuite/g++.dg/template/spec42.C b/gcc/testsuite/g++.dg/template/spec42.C
new file mode 100644
index 00000000000..cac1264fc9f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/spec42.C
@@ -0,0 +1,17 @@
+// PR c++/115716
+// { dg-do compile }
+template <typename T> struct x {
+  template <typename U> struct y { // { dg-note "used 1 template parameter" }
+    typedef T result2;
+  };
+};
+
+template<>
+template<typename U, typename>
+struct x<int>::y { // { dg-error "redeclared with 2 template parameters" }
+  typedef double result2;
+};
+
+int main() {
+  x<int>::y<int>::result2 xxx2;
+}
diff --git a/gcc/testsuite/g++.dg/template/spec43.C b/gcc/testsuite/g++.dg/template/spec43.C
new file mode 100644
index 00000000000..d33659dd506
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/spec43.C
@@ -0,0 +1,18 @@
+// PR c++/115716
+// { dg-do compile { target c++20 } }
+template <typename T> struct x {
+  template <typename U> struct y { // { dg-note "original" }
+    typedef T result2;
+  };
+};
+
+template<>
+template<typename U>
+requires true
+struct x<int>::y { // { dg-error "different constraints" }
+  typedef double result2;
+};
+
+int main() {
+  x<int>::y<int>::result2 xxx2;
+}
Jason Merrill Aug. 26, 2024, 3:02 p.m. UTC | #3
On 8/26/24 4:26 AM, Simon Martin wrote:
> Hi Jason,
> 
> On 22 Aug 2024, at 19:28, Jason Merrill wrote:
> 
>> On 8/22/24 12:51 PM, Simon Martin wrote:
>>> We currently ICE upon the following invalid code, because we don't
>>> check the
>>> number of template parameters in member class template
>>> specializations. This
>>> patch fixes the PR by adding such a check.
>>>
>>> === cut here ===
>>> template <typename T> struct x {
>>>     template <typename U> struct y {
>>>       typedef T result2;
>>>     };
>>> };
>>> template<> template<typename U, typename> struct x<int>::y {
>>>     typedef double result2;
>>> };
>>> int main() {
>>>     x<int>::y<int>::result2 xxx2;
>>> }
>>> === cut here ===
>>>
>>> Successfully tested on x86_64-pc-linux-gnu.
>>>
>>> 	PR c++/115716
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 	* pt.cc (maybe_process_partial_specialization): Check number of
>>> 	template parameters in specialization.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	* g++.dg/template/spec42.C: New test.
>>>
>>> ---
>>>    gcc/cp/pt.cc                           | 14 ++++++++++++++
>>>    gcc/testsuite/g++.dg/template/spec42.C | 17 +++++++++++++++++
>>>    2 files changed, 31 insertions(+)
>>>    create mode 100644 gcc/testsuite/g++.dg/template/spec42.C
>>>
>>> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
>>> index bc3ad5edcc5..db8c2a3b4de 100644
>>> --- a/gcc/cp/pt.cc
>>> +++ b/gcc/cp/pt.cc
>>> @@ -1173,6 +1173,20 @@ maybe_process_partial_specialization (tree
>>> type)
>>>    		       type, inst);
>>>    	    }
>>>   +	  /* Check that the number of template parameters matches the
>>> template
>>> +	     being specialized.  */
>>> +	  gcc_assert (current_template_parms);
>>> +	  if (TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS
>>> +			       (CLASSTYPE_TI_ARGS (type)))
>>> +	      != TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
>>> +				  (current_template_parms)))
>>> +	    {
>>> +	      error ("wrong number of template parameters for %qT", type);
>>> +	      inform (DECL_SOURCE_LOCATION (tmpl), "from definition of
>>> %q#D",
>>> +		      tmpl);
>>
>> How about printing the numbers for each place?
>>
>> What if the mismatch is other than in the number of parameters?  Can
>> you use template_parameter_lists_equivalent_p?  Or if that's
>> complicated, compare current_template_args() to CLASSTYPE_TI_ARGS
>> (type)?
>>
> Thanks for the review. After checking further, I believe we just miss a
> call to redeclare_class_template, that will catch various template
> parameter mismatch and properly report them.
> 
> This is what the updated attached patch does, successfully tested on
> x86_64-pc-linux-gnu. OK for trunk?

OK.
diff mbox series

Patch

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index bc3ad5edcc5..db8c2a3b4de 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1173,6 +1173,20 @@  maybe_process_partial_specialization (tree type)
 		       type, inst);
 	    }
 
+	  /* Check that the number of template parameters matches the template
+	     being specialized.  */
+	  gcc_assert (current_template_parms);
+	  if (TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS
+			       (CLASSTYPE_TI_ARGS (type)))
+	      != TREE_VEC_LENGTH (INNERMOST_TEMPLATE_PARMS
+				  (current_template_parms)))
+	    {
+	      error ("wrong number of template parameters for %qT", type);
+	      inform (DECL_SOURCE_LOCATION (tmpl), "from definition of %q#D",
+		      tmpl);
+	      return error_mark_node;
+	    }
+
 	  /* Mark TYPE as a specialization.  And as a result, we only
 	     have one level of template argument for the innermost
 	     class template.  */
diff --git a/gcc/testsuite/g++.dg/template/spec42.C b/gcc/testsuite/g++.dg/template/spec42.C
new file mode 100644
index 00000000000..e00a48d12a9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/spec42.C
@@ -0,0 +1,17 @@ 
+// PR c++/115716
+// { dg-do compile }
+template <typename T> struct x {
+  template <typename U> struct y { // { dg-note "from definition" }
+    typedef T result2;
+  };
+};
+
+template<>
+template<typename U, typename>
+struct x<int>::y { // { dg-error "wrong number" }
+  typedef double result2;
+};
+
+int main() {
+  x<int>::y<int>::result2 xxx2;
+}