From: Patrick Palka Date: Thu, 27 May 2021 16:36:39 +0000 (-0400) Subject: c++: Relax rule for non-type arguments in partial specs [CWG1315] X-Git-Tag: basepoints/gcc-13~7220 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9b94785dedb08b006419bec1a402614d9241317a;p=thirdparty%2Fgcc.git c++: Relax rule for non-type arguments in partial specs [CWG1315] This implements the wording changes of CWG 1315, which permits non-type template arguments in a partial specialization to use template parameters more freely. Delightfully, it seems the only change needed is to remove a single check from process_partial_specialization (amidst a bunch of whitespace changes). But that change alone revealed a latent problem with for_each_template_parm: it ends up looking into some non-deduced contexts even when include_nondeduced_p is false. This causes us to silently accept some partial specializations within the testsuite that contain non-deducible non-type template parameters (and that were previously rejected due to the rule that CWG 1315 relaxed). For now this patch makes a minimal amount of changes to for_each_template_parm_r so that we continue to reject existing ill-formed partial specializations within the testsuite. I opened PR c++/100779 to track this issue. DR 1315 PR c++/67593 PR c++/96555 gcc/cp/ChangeLog: * pt.c (process_partial_specialization): Don't error on a non-simple non-type template argument that involves template parameters. (for_each_template_parm_r): Don't walk TRAIT_EXPR, PLUS_EXPR, MULT_EXPR, or SCOPE_REF when include_nondeduced_p is false. gcc/testsuite/ChangeLog: * g++.dg/template/partial16.C: New test. * g++.dg/template/partial17.C: New test. * g++.dg/template/partial18.C: New test. * g++.dg/template/partial19.C: New test. * g++.dg/cpp0x/pr68724.C: Adjust expected diagnostic for ill-formed partial specialization. * g++.dg/cpp0x/variadic38.C: Likewise. * g++.dg/cpp1z/pr81016.C: Likewise. * g++.dg/template/partial5.C: Likewise. * g++.old-deja/g++.pt/spec21.C: Likewise. --- diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f3fa9c192ad5..e4950aa448a5 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5157,11 +5157,7 @@ process_partial_specialization (tree decl) maintmpl); } - /* [temp.class.spec] - - A partially specialized non-type argument expression shall not - involve template parameters of the partial specialization except - when the argument expression is a simple identifier. + /* [temp.spec.partial] The type of a template parameter corresponding to a specialized non-type argument shall not be dependent on a parameter of the @@ -5222,63 +5218,55 @@ process_partial_specialization (tree decl) || TREE_CODE (arg) == VIEW_CONVERT_EXPR) && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_PARM_INDEX)) { - if ((!packed_args && tpd.arg_uses_template_parms[i]) - || (packed_args && uses_template_parms (arg))) - error_at (cp_expr_loc_or_input_loc (arg), - "template argument %qE involves template " - "parameter(s)", arg); - else - { - /* Look at the corresponding template parameter, - marking which template parameters its type depends - upon. */ - tree type = TREE_TYPE (parm); + /* Look at the corresponding template parameter, + marking which template parameters its type depends + upon. */ + tree type = TREE_TYPE (parm); - if (!tpd2.parms) - { - /* We haven't yet initialized TPD2. Do so now. */ - tpd2.arg_uses_template_parms = XALLOCAVEC (int, nargs); - /* The number of parameters here is the number in the - main template, which, as checked in the assertion - above, is NARGS. */ - tpd2.parms = XALLOCAVEC (int, nargs); - tpd2.level = - TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl)); - } + if (!tpd2.parms) + { + /* We haven't yet initialized TPD2. Do so now. */ + tpd2.arg_uses_template_parms = XALLOCAVEC (int, nargs); + /* The number of parameters here is the number in the + main template, which, as checked in the assertion + above, is NARGS. */ + tpd2.parms = XALLOCAVEC (int, nargs); + tpd2.level = + TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (maintmpl)); + } - /* Mark the template parameters. But this time, we're - looking for the template parameters of the main - template, not in the specialization. */ - tpd2.current_arg = i; - tpd2.arg_uses_template_parms[i] = 0; - memset (tpd2.parms, 0, sizeof (int) * nargs); - for_each_template_parm (type, - &mark_template_parm, - &tpd2, - NULL, - /*include_nondeduced_p=*/false); - - if (tpd2.arg_uses_template_parms [i]) - { - /* The type depended on some template parameters. - If they are fully specialized in the - specialization, that's OK. */ - int j; - int count = 0; - for (j = 0; j < nargs; ++j) - if (tpd2.parms[j] != 0 - && tpd.arg_uses_template_parms [j]) - ++count; - if (count != 0) - error_n (input_location, count, - "type %qT of template argument %qE depends " - "on a template parameter", - "type %qT of template argument %qE depends " - "on template parameters", - type, - arg); - } - } + /* Mark the template parameters. But this time, we're + looking for the template parameters of the main + template, not in the specialization. */ + tpd2.current_arg = i; + tpd2.arg_uses_template_parms[i] = 0; + memset (tpd2.parms, 0, sizeof (int) * nargs); + for_each_template_parm (type, + &mark_template_parm, + &tpd2, + NULL, + /*include_nondeduced_p=*/false); + + if (tpd2.arg_uses_template_parms [i]) + { + /* The type depended on some template parameters. + If they are fully specialized in the + specialization, that's OK. */ + int j; + int count = 0; + for (j = 0; j < nargs; ++j) + if (tpd2.parms[j] != 0 + && tpd.arg_uses_template_parms [j]) + ++count; + if (count != 0) + error_n (input_location, count, + "type %qT of template argument %qE depends " + "on a template parameter", + "type %qT of template argument %qE depends " + "on template parameters", + type, + arg); + } } } } @@ -10502,6 +10490,15 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) return error_mark_node; break; + case TRAIT_EXPR: + case PLUS_EXPR: + case MULT_EXPR: + case SCOPE_REF: + /* These are non-deduced contexts. */ + if (!pfd->include_nondeduced_p) + *walk_subtrees = 0; + break; + case MODOP_EXPR: case CAST_EXPR: case IMPLICIT_CONV_EXPR: @@ -10517,11 +10514,6 @@ for_each_template_parm_r (tree *tp, int *walk_subtrees, void *d) return error_mark_node; break; - case SCOPE_REF: - if (pfd->include_nondeduced_p) - WALK_SUBTREE (TREE_OPERAND (t, 0)); - break; - case REQUIRES_EXPR: { if (!fn) diff --git a/gcc/testsuite/g++.dg/cpp0x/pr68724.C b/gcc/testsuite/g++.dg/cpp0x/pr68724.C index 4e99d53d5a94..6df7f718a7e1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/pr68724.C +++ b/gcc/testsuite/g++.dg/cpp0x/pr68724.C @@ -9,7 +9,7 @@ struct integral_constant integral_constant inst; template -struct integral_constant // { dg-error "32:template argument" } +struct integral_constant // { dg-error "not deducible" } { }; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic38.C b/gcc/testsuite/g++.dg/cpp0x/variadic38.C index b569404cdf2a..49fa48c3bd29 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic38.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic38.C @@ -3,4 +3,4 @@ template struct int_vec {}; template -struct int_vec<0, (Values+1)...> {}; // { dg-error "26:template argument" } +struct int_vec<0, (Values+1)...> {}; // { dg-error "not deducible" } diff --git a/gcc/testsuite/g++.dg/cpp1z/pr81016.C b/gcc/testsuite/g++.dg/cpp1z/pr81016.C index 358b12056c0e..a17afcc6b65f 100644 --- a/gcc/testsuite/g++.dg/cpp1z/pr81016.C +++ b/gcc/testsuite/g++.dg/cpp1z/pr81016.C @@ -1,4 +1,4 @@ // { dg-do compile { target c++17 } } template struct b; -template struct b; // { dg-error "template parameter" } +template struct b; // { dg-error "not deducible" } diff --git a/gcc/testsuite/g++.dg/template/partial16.C b/gcc/testsuite/g++.dg/template/partial16.C new file mode 100644 index 000000000000..30c34c3e0d98 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial16.C @@ -0,0 +1,8 @@ +// [temp.spec.partial.general]/9 + +template struct C {}; +template struct C; // { dg-error "depends on a template parameter" } + +template< int X, int (*array_ptr)[X] > class A {}; +int array[5]; +template< int X > class A { }; // { dg-error "depends on a template parameter" } diff --git a/gcc/testsuite/g++.dg/template/partial17.C b/gcc/testsuite/g++.dg/template/partial17.C new file mode 100644 index 000000000000..d5c82d26db30 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial17.C @@ -0,0 +1,14 @@ +// [temp.spec.partial.match]/3 + +template struct A; +template struct A {}; // { dg-error "not deducible" } + +template struct A {}; // OK + +template struct B; +template struct B {}; // OK +template struct B { typedef int type; }; // OK + +B<1, 2, 1> b1; +B<1, 2, 2>::type b2; +B<1, 2, 3> b3; // { dg-error "incomplete" } diff --git a/gcc/testsuite/g++.dg/template/partial18.C b/gcc/testsuite/g++.dg/template/partial18.C new file mode 100644 index 000000000000..7b7614ebc6b3 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial18.C @@ -0,0 +1,19 @@ +// PR c++/96555 + +template +struct X; + +template +struct X {}; + +X x1; +X x2; // { dg-error "incomplete" } + + +struct A { int x; } a; +template struct B; +template +struct B { }; + +B<0, sizeof(int)> b1; +B<0, sizeof(int)+1> b2; // { dg-error "incomplete" } diff --git a/gcc/testsuite/g++.dg/template/partial19.C b/gcc/testsuite/g++.dg/template/partial19.C new file mode 100644 index 000000000000..39149d220b46 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial19.C @@ -0,0 +1,11 @@ +// PR c++/67593 +// { dg-do compile { target c++11 } } + +template +struct outer { + template struct inner; + template struct inner {}; +}; + +outer::inner<0, 0> x1; +outer::inner<1, 0> x2; // { dg-error "incomplete" } diff --git a/gcc/testsuite/g++.dg/template/partial5.C b/gcc/testsuite/g++.dg/template/partial5.C index 40d8c45b0879..037f684cbd2a 100644 --- a/gcc/testsuite/g++.dg/template/partial5.C +++ b/gcc/testsuite/g++.dg/template/partial5.C @@ -21,4 +21,4 @@ template struct Z { }; template -struct Z { }; // { dg-error "13:template argument" } +struct Z { }; // { dg-error "depends on a template parameter" } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec21.C b/gcc/testsuite/g++.old-deja/g++.pt/spec21.C index cf89d6b325a9..bf25c0ebb39e 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec21.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec21.C @@ -4,8 +4,7 @@ template struct S {}; template struct S {}; // { dg-error "" } default argument template struct A {}; -template struct A {}; // { dg-error "28:template argument" } -// { dg-error "33:template argument" "" { target *-*-* } .-1 } +template struct A {}; // { dg-error "not deducible" } template struct C {}; template struct C; // { dg-error "" } type depends on parameter int i;