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 <si...@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;
+}
-- 
2.44.0

Reply via email to