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 few checks from process_partial_specialization.
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 removed). For now this patch makes a minimal amount of changes to for_each_template_parm_r so we continue to reject existing ill-formed partial specializations within the testsuite. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk? Patch generated with -w to hide noisy whitespace changes. DR 1315 PR c++/96555 PR c++/100779 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 unset. 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/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. --- gcc/cp/pt.c | 28 ++++++++-------------- gcc/testsuite/g++.dg/cpp0x/pr68724.C | 2 +- gcc/testsuite/g++.dg/cpp0x/variadic38.C | 3 ++- gcc/testsuite/g++.dg/cpp1z/pr81016.C | 2 +- gcc/testsuite/g++.dg/template/partial16.C | 8 +++++++ gcc/testsuite/g++.dg/template/partial17.C | 14 +++++++++++ gcc/testsuite/g++.dg/template/partial18.C | 19 +++++++++++++++ gcc/testsuite/g++.dg/template/partial5.C | 2 +- gcc/testsuite/g++.old-deja/g++.pt/spec21.C | 3 +-- 9 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 gcc/testsuite/g++.dg/template/partial16.C create mode 100644 gcc/testsuite/g++.dg/template/partial17.C create mode 100644 gcc/testsuite/g++.dg/template/partial18.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f3fa9c192ad..6b0bc815404 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 @@ -5221,13 +5217,6 @@ process_partial_specialization (tree decl) && !((REFERENCE_REF_P (arg) || 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 @@ -5281,7 +5270,6 @@ process_partial_specialization (tree decl) } } } - } /* We should only get here once. */ if (TREE_CODE (decl) == TYPE_DECL) @@ -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 always 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 4e99d53d5a9..6df7f718a7e 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<bool, true> inst; template <typename _Tp> -struct integral_constant<bool, __is_enum(_Tp)> // { dg-error "32:template argument" } +struct integral_constant<bool, __is_enum(_Tp)> // { dg-error "not deducible" } { }; diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic38.C b/gcc/testsuite/g++.dg/cpp0x/variadic38.C index b569404cdf2..9155445dce1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/variadic38.C +++ b/gcc/testsuite/g++.dg/cpp0x/variadic38.C @@ -3,4 +3,5 @@ template<int... Values> struct int_vec {}; template<int... Values> -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 358b12056c0..a17afcc6b65 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 <typename a, a> struct b; -template <typename c> struct b<bool, c::d>; // { dg-error "template parameter" } +template <typename c> struct b<bool, c::d>; // { 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 00000000000..30c34c3e0d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial16.C @@ -0,0 +1,8 @@ +// [temp.spec.partial.general]/9 + +template <class T, T t> struct C {}; +template <class T> struct C<T, 1>; // { dg-error "depends on a template parameter" } + +template< int X, int (*array_ptr)[X] > class A {}; +int array[5]; +template< int X > class A<X,&array> { }; // { 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 00000000000..d5c82d26db3 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial17.C @@ -0,0 +1,14 @@ +// [temp.spec.partial.match]/3 + +template <int I, int J> struct A; +template <int I> struct A<I+5, I*2> {}; // { dg-error "not deducible" } + +template <int I> struct A<I, I> {}; // OK + +template <int I, int J, int K> struct B; +template <int I> struct B<I, I*2, I> {}; // OK +template <int I> struct B<I, I*2, 2> { 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 00000000000..7b7614ebc6b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/partial18.C @@ -0,0 +1,19 @@ +// PR c++/96555 + +template<class T, int i> +struct X; + +template<class T> +struct X<T, sizeof(T)> {}; + +X<int, sizeof(int)> x1; +X<int, sizeof(int)+1> x2; // { dg-error "incomplete" } + + +struct A { int x; } a; +template<int, int> struct B; +template<int y> +struct B<y, sizeof(a.x)> { }; + +B<0, sizeof(int)> b1; +B<0, sizeof(int)+1> b2; // { dg-error "incomplete" } diff --git a/gcc/testsuite/g++.dg/template/partial5.C b/gcc/testsuite/g++.dg/template/partial5.C index 40d8c45b087..037f684cbd2 100644 --- a/gcc/testsuite/g++.dg/template/partial5.C +++ b/gcc/testsuite/g++.dg/template/partial5.C @@ -21,4 +21,4 @@ template<typename T, T V> struct Z { }; template<typename T> -struct Z<T, (T)0> { }; // { dg-error "13:template argument" } +struct Z<T, (T)0> { }; // { 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 cf89d6b325a..bf25c0ebb39 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 <class T> struct S {}; template <class T = int> struct S<T*> {}; // { dg-error "" } default argument template <int I, int J> struct A {}; -template <int I> struct A<I+5, I*2> {}; // { dg-error "28:template argument" } -// { dg-error "33:template argument" "" { target *-*-* } .-1 } +template <int I> struct A<I+5, I*2> {}; // { dg-error "not deducible" } template <class T, T t> struct C {}; template <class T> struct C<T, 1>; // { dg-error "" } type depends on parameter int i; -- 2.32.0.rc0