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 |
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
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; +}
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 --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; +}