From 79802c5dcc043a515f429bb2bec7573b8537c32a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Tue, 28 Sep 2021 10:02:04 -0400 Subject: [PATCH] c++: array cv-quals and template specialization [PR101402] To: gcc-patches@gcc.gnu.org PRs 101402, 102033, etc. demonstrated that the fix for PR92010 wasn't handling all cases of the CWG1001/1322 issue with parameter type qual stripping and arrays with templates. The problem turned out to be in determine_specialization, which did an extra substitution without the 92010 fix and then complained that the result didn't match. But just removing that wrong/redundant code meant that we were accepting specializations with different numbers of parameters, because the code in fn_type_unification that compares types in this case wasn't checking for length mismatch. After fixing that, I realized that fn_type_unification couldn't tell the difference between variadic and non-variadic function types, because the args array doesn't include the terminal void we use to indicate non-variadic function type. So I added it, and made the necessary adjustments. Thanks to qingzhe "nick" huang for the patch that led me to dig more into this, and the extensive testcases. PR c++/51851 PR c++/101402 PR c++/102033 PR c++/102034 PR c++/102039 PR c++/102044 gcc/cp/ChangeLog: * pt.c (determine_specialization): Remove redundant code. (fn_type_unification): Check for mismatched length. (type_unification_real): Ignore terminal void. (get_bindings): Don't stop at void_list_node. * class.c (resolve_address_of_overloaded_function): Likewise. gcc/testsuite/ChangeLog: * g++.dg/template/fnspec2.C: New test. * g++.dg/template/parm-cv1.C: New test. * g++.dg/template/parm-cv2.C: New test. * g++.dg/template/parm-cv3.C: New test. --- gcc/cp/class.c | 2 +- gcc/cp/pt.c | 30 +++-- gcc/testsuite/g++.dg/template/fnspec2.C | 9 ++ gcc/testsuite/g++.dg/template/parm-cv1.C | 15 +++ gcc/testsuite/g++.dg/template/parm-cv2.C | 23 ++++ gcc/testsuite/g++.dg/template/parm-cv3.C | 142 +++++++++++++++++++++++ 6 files changed, 204 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/fnspec2.C create mode 100644 gcc/testsuite/g++.dg/template/parm-cv1.C create mode 100644 gcc/testsuite/g++.dg/template/parm-cv2.C create mode 100644 gcc/testsuite/g++.dg/template/parm-cv3.C diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 59611627d18..f16e50b9de9 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -8382,7 +8382,7 @@ resolve_address_of_overloaded_function (tree target_type, nargs = list_length (target_arg_types); args = XALLOCAVEC (tree, nargs); for (arg = target_arg_types, ia = 0; - arg != NULL_TREE && arg != void_list_node; + arg != NULL_TREE; arg = TREE_CHAIN (arg), ++ia) args[ia] = TREE_VALUE (arg); nargs = ia; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 009fe6db573..287cf4ce9d0 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -2230,7 +2230,6 @@ determine_specialization (tree template_id, { tree decl_arg_types; tree fn_arg_types; - tree insttype; /* In case of explicit specialization, we need to check if the number of template headers appearing in the specialization @@ -2356,20 +2355,6 @@ determine_specialization (tree template_id, template argument. */ continue; - /* Remove, from the set of candidates, all those functions - whose constraints are not satisfied. */ - if (flag_concepts && !constraints_satisfied_p (fn, targs)) - continue; - - // Then, try to form the new function type. - insttype = tsubst (TREE_TYPE (fn), targs, tf_fndecl_type, NULL_TREE); - if (insttype == error_mark_node) - continue; - fn_arg_types - = skip_artificial_parms_for (fn, TYPE_ARG_TYPES (insttype)); - if (!compparms (fn_arg_types, decl_arg_types)) - continue; - /* Save this template, and the arguments deduced. */ templates = tree_cons (targs, fn, templates); } @@ -21862,6 +21847,15 @@ fn_type_unification (tree fn, TREE_VALUE (sarg)); goto fail; } + if ((i < nargs || sarg) + /* add_candidates uses DEDUCE_EXACT for x.operator foo(), but args + doesn't contain the trailing void, and conv fns are always (). */ + && !DECL_CONV_FN_P (decl)) + { + unsigned nsargs = i + list_length (sarg); + unify_arity (explain_p, nargs, nsargs); + goto fail; + } } /* After doing deduction with the inherited constructor, actually return an @@ -22385,6 +22379,10 @@ type_unification_real (tree tparms, args = xargs; nargs = xnargs; + /* Only fn_type_unification cares about terminal void. */ + if (nargs && args[nargs-1] == void_type_node) + --nargs; + ia = 0; while (parms && parms != void_list_node && ia < nargs) @@ -24886,7 +24884,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype) nargs = list_length (decl_arg_types); args = XALLOCAVEC (tree, nargs); for (arg = decl_arg_types, ix = 0; - arg != NULL_TREE && arg != void_list_node; + arg != NULL_TREE; arg = TREE_CHAIN (arg), ++ix) args[ix] = TREE_VALUE (arg); diff --git a/gcc/testsuite/g++.dg/template/fnspec2.C b/gcc/testsuite/g++.dg/template/fnspec2.C new file mode 100644 index 00000000000..7a4b1012d89 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/fnspec2.C @@ -0,0 +1,9 @@ +template +void f(T); + +template<> void f(int, ...); // { dg-error "match" } + +template +void g(T, ...); + +template<> void g(int); // { dg-error "match" } diff --git a/gcc/testsuite/g++.dg/template/parm-cv1.C b/gcc/testsuite/g++.dg/template/parm-cv1.C new file mode 100644 index 00000000000..2677992770d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/parm-cv1.C @@ -0,0 +1,15 @@ +// CWG 1001 + +template struct A { + typedef T arr[3]; +}; + +template void f(const typename A::arr) { } // #1 + +template void f(const A::arr); + +template struct B { + void g(T); +}; + +template void B::g(const T) { } // #2 diff --git a/gcc/testsuite/g++.dg/template/parm-cv2.C b/gcc/testsuite/g++.dg/template/parm-cv2.C new file mode 100644 index 00000000000..cd40e868017 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/parm-cv2.C @@ -0,0 +1,23 @@ +// PR c++/51851 + +template +struct A +{ + typedef double Point[2]; + virtual double calculate(const Point point) const = 0; +}; + +template +struct B : public A +{ + virtual double calculate(const typename A::Point point) const + { + return point[0]; + } +}; + +int main() +{ + B b; + return 0; +} diff --git a/gcc/testsuite/g++.dg/template/parm-cv3.C b/gcc/testsuite/g++.dg/template/parm-cv3.C new file mode 100644 index 00000000000..1b69c3b2a48 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/parm-cv3.C @@ -0,0 +1,142 @@ +// CWG 1001/1322 + +// PR c++/101402 +// PR c++/102033 +// PR c++/102034 +// PR c++/102039 +// PR c++/102044 + +namespace test2{ +template +void f(const T); + +template<> +void f(const int*){} +} + +namespace test3{ +template +struct A{ +void f(T); +}; + +template +void A::f(const T){} + +template<> +void A::f(const int*){} +} + +namespace test4 { +template +struct A{ + template + struct B{ + typedef TB Arr3[3]; + }; +}; +template +void f(const typename A::template B::Arr3){} +template <> +void f(const typename A::B::Arr3){} +} + +namespace test5 +{ +struct A{ + typedef int Arr3[3]; +}; + +template +void f(const typename T::Arr3){} + +template<> +void f(const int[3]){} +} + +namespace test6 +{ +struct A{ + typedef int Arr3[3]; +}; +template +void f(const typename T::Arr3){} +template<> +void f(const int*){} +} + +#if __cpp_alias_templates +namespace test7 +{ +template +struct A{ + template + using Type=TB[3]; +}; +template +void f(const typename A::template Type){} +template <> +void f(const typename A::template Type){} +} +namespace test8 +{ +template +struct A{ + template + struct B{ + using TB_Alias=TB; + template + struct C{ + typedef TC Arr3[3]; + }; + }; +}; +template +void f(const typename A::template B::template C<>::Arr3){} +template <> +void f(const typename A::template B::template C<>::Arr3){} +} +#endif + +#if __cpp_decltype +namespace test0 +{ +template +struct A{ + T arr3[3]; +}; +template +void f(const decltype(A::arr3)){} +template <> +void f(const int[3]){} +} + +#if __cpp_variable_templates +namespace test9 +{ +template +void f(const T[N]){} + +template +using fPtr=decltype(f)*; + +template +fPtr af[N]={&f}; + +template +void g(const decltype(af)){} + +template<> +void g<1,int>(const fPtr<1,int>[1]){} +} +#endif +#endif + +#if __cpp_concepts +template +concept IsLambdaAry3=__is_same(T, decltype(+[]{})[3]); +template +void bar(const T){} +template<> +void bar(const decltype(+[]{})[3]){} +#endif -- 2.27.0