Message ID | 20210604034607.3582211-1-ppalka@redhat.com |
---|---|
State | New |
Headers | show |
Series | c++: tsubst_function_decl and excess arg levels [PR100102] | expand |
On 6/3/21 11:46 PM, Patrick Palka wrote: > Here, when instantiating the dependent alias template > duration::__is_harmonic with args={{T,U},{int}}, we find ourselves > substituting the function decl _S_gcd. Since we have more arg levels > than _S_gcd has parm levels, an old special case in tsubst_function_decl > causes us to unwantedly reduce args to its innermost level, yielding > args={int}, which leads to a nonsensical substitution into the decl's > context and an eventual crash. > > The comment for this special case refers to three examples for which we > ought to see more arg levels than parm levels here, but none of the > examples actually demonstrate this. In the first example, when > defining S<int>::f(U) parms_depth is 2 and args_depth is 1, and > later when instantiating say S<int>::f<char> both depths are 2. In the > second example, when substituting the template friend declaration > parms_depth is 2 and args_depth is 1, and later when instantiating f > both depths are 1. Finally, the third example is invalid since we can't > specialize a member template of an unspecialized class template like > that. > > Given that this reduction code seems no longer relevant for its > documented purpose and that it causes problems as in the PR, this patch > just removes it. Note that as far as bootstrap/regtest is concerned, > this code is dead; the below two tests would be the first to trigger the > removed code. Interesting! > Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for > trunk and perhaps backports? Also tested on various other libraries, > e.g. range-v3 and cmcstl2. OK I think for 10/11/12; 9 doesn't have the <chrono> change that revealed this issue. > PR c++/100102 > > gcc/cp/ChangeLog: > > * pt.c (tsubst_function_decl): Remove old code for reducing > args when it has excess levels. > > gcc/testsuite/ChangeLog: > > * g++.dg/cpp0x/alias-decl-72.C: New test. > * g++.dg/cpp0x/alias-decl-72a.C: New test. > --- > gcc/cp/pt.c | 39 --------------------- > gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C | 9 +++++ > gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C | 9 +++++ > 3 files changed, 18 insertions(+), 39 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C > create mode 100644 gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index 3cac073ed50..a6acdf864d1 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -13909,45 +13909,6 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, > if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash)) > return spec; > } > - > - /* We can see more levels of arguments than parameters if > - there was a specialization of a member template, like > - this: > - > - template <class T> struct S { template <class U> void f(); } > - template <> template <class U> void S<int>::f(U); > - > - Here, we'll be substituting into the specialization, > - because that's where we can find the code we actually > - want to generate, but we'll have enough arguments for > - the most general template. > - > - We also deal with the peculiar case: > - > - template <class T> struct S { > - template <class U> friend void f(); > - }; > - template <class U> void f() {} > - template S<int>; > - template void f<double>(); > - > - Here, the ARGS for the instantiation of will be {int, > - double}. But, we only need as many ARGS as there are > - levels of template parameters in CODE_PATTERN. We are > - careful not to get fooled into reducing the ARGS in > - situations like: > - > - template <class T> struct S { template <class U> void f(U); } > - template <class T> template <> void S<T>::f(int) {} > - > - which we can spot because the pattern will be a > - specialization in this case. */ > - int args_depth = TMPL_ARGS_DEPTH (args); > - int parms_depth = > - TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t))); > - > - if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t)) > - args = get_innermost_template_args (args, parms_depth); > } > else > { > diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C > new file mode 100644 > index 00000000000..8009756dcba > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C > @@ -0,0 +1,9 @@ > +// PR c++/100102 > +// { dg-do compile { target c++11 } } > + > +template<int()> struct ratio; > +template<class T, class U> struct duration { > + static constexpr int _S_gcd(); > + template<class> using __is_harmonic = ratio<_S_gcd>; > + using type = __is_harmonic<int>; > +}; > diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C > new file mode 100644 > index 00000000000..a4443e18f9d > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C > @@ -0,0 +1,9 @@ > +// PR c++/100102 > +// { dg-do compile { target c++11 } } > + > +template<int> struct ratio; > +template<class T> struct duration { > + static constexpr int _S_gcd(); > + template<class> using __is_harmonic = ratio<(duration::_S_gcd)()>; > + using type = __is_harmonic<int>; > +}; >
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3cac073ed50..a6acdf864d1 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -13909,45 +13909,6 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain, if (tree spec = retrieve_specialization (gen_tmpl, argvec, hash)) return spec; } - - /* We can see more levels of arguments than parameters if - there was a specialization of a member template, like - this: - - template <class T> struct S { template <class U> void f(); } - template <> template <class U> void S<int>::f(U); - - Here, we'll be substituting into the specialization, - because that's where we can find the code we actually - want to generate, but we'll have enough arguments for - the most general template. - - We also deal with the peculiar case: - - template <class T> struct S { - template <class U> friend void f(); - }; - template <class U> void f() {} - template S<int>; - template void f<double>(); - - Here, the ARGS for the instantiation of will be {int, - double}. But, we only need as many ARGS as there are - levels of template parameters in CODE_PATTERN. We are - careful not to get fooled into reducing the ARGS in - situations like: - - template <class T> struct S { template <class U> void f(U); } - template <class T> template <> void S<T>::f(int) {} - - which we can spot because the pattern will be a - specialization in this case. */ - int args_depth = TMPL_ARGS_DEPTH (args); - int parms_depth = - TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (t))); - - if (args_depth > parms_depth && !DECL_TEMPLATE_SPECIALIZATION (t)) - args = get_innermost_template_args (args, parms_depth); } else { diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C new file mode 100644 index 00000000000..8009756dcba --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72.C @@ -0,0 +1,9 @@ +// PR c++/100102 +// { dg-do compile { target c++11 } } + +template<int()> struct ratio; +template<class T, class U> struct duration { + static constexpr int _S_gcd(); + template<class> using __is_harmonic = ratio<_S_gcd>; + using type = __is_harmonic<int>; +}; diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C new file mode 100644 index 00000000000..a4443e18f9d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-72a.C @@ -0,0 +1,9 @@ +// PR c++/100102 +// { dg-do compile { target c++11 } } + +template<int> struct ratio; +template<class T> struct duration { + static constexpr int _S_gcd(); + template<class> using __is_harmonic = ratio<(duration::_S_gcd)()>; + using type = __is_harmonic<int>; +};