On Fri, Jun 26, 2015 at 7:40 AM, Patrick Palka <patr...@parcs.ath.cx> wrote: > Here is a more modest approach to fixing this PR. Instead of updating > current_template_parms with each newly processed template parameter, > this patch just updates it with a "dummy" parameter level once per > parameter list. So now in tsubst(), to fix the reported ICE we just > have to avoid substituting a template parameter if it corresponds to an > empty "dummy" argument level. > > One caveat with this approach is that since template template decls will > now have dummy parameter levels in their DECL_TEMPLATE_PARMS fields, we > have to avoid emitting such dummy levels inside error messages when > printing template template parameters. Otherwise the parameter B in > > template<template<class A> class B> struct Foo { }; > > would get printed in error messages as > > template<> template <class A> class B> > > Two new test files are added in this version: shadow2.C, which checks > that we emit a shadowing error for identical template parameter names > across nested parameter lists, and error55.C, which checks that we > correctly emit template template decls in error messages. > > With this approach the test case provided by Markus no longer takes > forever to compile because the added parameter lists are always empty so > when doing structural type comparison of a TEMPLATE_TEMPLATE_PARM there > is nothing extra to recurse into. > > Does this approach seem sensible? > > gcc/cp/ChangeLog: > > PR c++/30044 > * pt.c (begin_template_parm_list): Add a dummy parameter level > to current_template_parms. > (end_template_parm_list): Remove the dummy parameter level > before adding the real one. > (tsubst): Don't attempt to substitute for template parameters > corresponding to a dummy argument level. > (template_parms_to_args): Remove obsolete hack for > giving template template arguments the proper level. > (splite_late_return_type): Remove obsolete hack for giving > template template arguments the proper level. > * error.c (dump_template_decl): Don't print dummy template > levels. > > gcc/testsuite/ChangeLog > > PR c++/30044 > * g++.dg/cpp0x/auto45.C: New test. > * g++.dg/template/pr30044.C: New test. > * g++.dg/template/shadow2.C: New test. > * g++.dg/template/error55.C: New test. > * g++.dg/template/crash83.C: Accept any error string. > * g++.dg/cpp0x/variadic18.C: Adjust to avoid shadowing template > parameters. > * g++.dg/cpp0x/variadic18.C: Likewise > * g++.dg/template/canon-type-13.C: Likewise. > * g++.old-deja/g++.pt/ttp42.C: Likewise. > * g++.dg/torture/20070621-1.C: Likewise. > --- > gcc/cp/error.c | 7 ++++++ > gcc/cp/pt.c | 32 > +++++++++------------------ > gcc/testsuite/g++.dg/cpp0x/auto45.C | 5 +++++ > gcc/testsuite/g++.dg/cpp0x/variadic18.C | 2 +- > gcc/testsuite/g++.dg/cpp0x/variadic19.C | 2 +- > gcc/testsuite/g++.dg/template/canon-type-13.C | 2 +- > gcc/testsuite/g++.dg/template/crash83.C | 2 +- > gcc/testsuite/g++.dg/template/error55.C | 8 +++++++ > gcc/testsuite/g++.dg/template/pr30044.C | 14 ++++++++++++ > gcc/testsuite/g++.dg/template/shadow2.C | 3 +++ > gcc/testsuite/g++.dg/torture/20070621-1.C | 2 +- > gcc/testsuite/g++.old-deja/g++.pt/ttp42.C | 2 +- > 12 files changed, 54 insertions(+), 27 deletions(-) > create mode 100644 gcc/testsuite/g++.dg/cpp0x/auto45.C > create mode 100644 gcc/testsuite/g++.dg/template/error55.C > create mode 100644 gcc/testsuite/g++.dg/template/pr30044.C > create mode 100644 gcc/testsuite/g++.dg/template/shadow2.C > > diff --git a/gcc/cp/error.c b/gcc/cp/error.c > index 96fa94d..b21befe 100644 > --- a/gcc/cp/error.c > +++ b/gcc/cp/error.c > @@ -1296,6 +1296,13 @@ dump_template_decl (cxx_pretty_printer *pp, tree t, > int flags) > tree inner_parms = INNERMOST_TEMPLATE_PARMS (parms); > int len = TREE_VEC_LENGTH (inner_parms); > > + if (len == 0) > + { > + /* Skip over the dummy template levels of a template template > parm. */ > + gcc_assert (TREE_CODE (TREE_TYPE (t)) == > TEMPLATE_TEMPLATE_PARM); > + continue; > + } > + > pp_cxx_ws_string (pp, "template"); > pp_cxx_begin_template_argument_list (pp); > > diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c > index fe5fc14..e7c35d3 100644 > --- a/gcc/cp/pt.c > +++ b/gcc/cp/pt.c > @@ -658,6 +658,12 @@ begin_template_parm_list (void) > ++processing_template_decl; > ++processing_template_parmlist; > note_template_header (0); > + > + /* Add a dummy parameter level while we process the parameter list. */ > + current_template_parms > + = tree_cons (size_int (processing_template_decl), > + make_tree_vec (0), > + current_template_parms); > } > > /* This routine is called when a specialization is declared. If it is > @@ -3854,6 +3860,9 @@ end_template_parm_list (tree parms) > tree parm, next; > tree saved_parmlist = make_tree_vec (list_length (parms)); > > + /* Pop the dummy parameter level and add the real one. */ > + current_template_parms = TREE_CHAIN (current_template_parms); > + > current_template_parms > = tree_cons (size_int (processing_template_decl), > saved_parmlist, current_template_parms); > @@ -3989,21 +3998,6 @@ template_parms_to_args (tree parms) > args = a; > } > > - if (length > 1 && TREE_VEC_ELT (args, 0) == NULL_TREE) > - /* This can happen for template parms of a template template > - parameter, e.g: > - > - template<template<class T, class U> class TT> struct S; > - > - Consider the level of the parms of TT; T and U both have > - level 2; TT has no template parm of level 1. So in this case > - the first element of full_template_args is NULL_TREE. If we > - leave it like this TMPL_ARGS_DEPTH on args returns 1 instead > - of 2. This will make tsubst wrongly consider that T and U > - have level 1. Instead, let's create a dummy vector as the > - first element of full_template_args so that TMPL_ARGS_DEPTH > - returns the correct depth for args. */ > - TREE_VEC_ELT (args, 0) = make_tree_vec (1); > return args; > } > > @@ -12029,7 +12023,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, > tree in_decl) > template_parm_level_and_index (t, &level, &idx); > > levels = TMPL_ARGS_DEPTH (args); > - if (level <= levels) > + if (level <= levels > + && TREE_VEC_LENGTH (TMPL_ARGS_LEVEL (args, level)) > 0) > { > arg = TMPL_ARG (args, level, idx); > > @@ -22394,11 +22389,6 @@ splice_late_return_type (tree type, tree > late_return_type) > return type; > argvec = make_tree_vec (1); > TREE_VEC_ELT (argvec, 0) = late_return_type; > - if (processing_template_parmlist) > - /* For a late-specified return type in a template type-parameter, we > - need to add a dummy argument level for its parmlist. */ > - argvec = add_to_template_args > - (make_tree_vec (processing_template_parmlist), argvec); > if (current_template_parms) > argvec = add_to_template_args (current_template_args (), argvec); > return tsubst (type, argvec, tf_warning_or_error, NULL_TREE); > diff --git a/gcc/testsuite/g++.dg/cpp0x/auto45.C > b/gcc/testsuite/g++.dg/cpp0x/auto45.C > new file mode 100644 > index 0000000..09e9f44 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/cpp0x/auto45.C > @@ -0,0 +1,5 @@ > +// Addendum to auto23.C, now with nested template parameter lists > +// { dg-do compile { target c++11 } } > + > +template<template <auto f()->int> class> struct A { }; > +template<template <template <auto f()->int> class> class> struct B { }; > diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic18.C > b/gcc/testsuite/g++.dg/cpp0x/variadic18.C > index fc0e2dd..57fdc86 100644 > --- a/gcc/testsuite/g++.dg/cpp0x/variadic18.C > +++ b/gcc/testsuite/g++.dg/cpp0x/variadic18.C > @@ -1,7 +1,7 @@ > // { dg-do compile { target c++11 } } > template<typename...> class tuple { }; > > -template<typename T, template<typename T> class... Metafunctions> > +template<typename T, template<typename U> class... Metafunctions> > struct apply_all > { > typedef tuple<typename Metafunctions<T>::type...> type; > diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic19.C > b/gcc/testsuite/g++.dg/cpp0x/variadic19.C > index 0ae2672..3be9bb0 100644 > --- a/gcc/testsuite/g++.dg/cpp0x/variadic19.C > +++ b/gcc/testsuite/g++.dg/cpp0x/variadic19.C > @@ -4,7 +4,7 @@ struct tuple { > static const int value = 0; > }; > > -template<typename T, template<class T> class... Metafunctions> > +template<typename T, template<class U> class... Metafunctions> > struct tuple<Metafunctions<T>...> { > static const int value = 1; > }; > diff --git a/gcc/testsuite/g++.dg/template/canon-type-13.C > b/gcc/testsuite/g++.dg/template/canon-type-13.C > index 4f3702b..5a8d37d 100644 > --- a/gcc/testsuite/g++.dg/template/canon-type-13.C > +++ b/gcc/testsuite/g++.dg/template/canon-type-13.C > @@ -11,7 +11,7 @@ struct S1 > { > }; > > -template<class T, template<class T> class A, template<class T> class B = A> > +template<class T, template<class U> class A, template<class U> class B = A> > struct C > { > B<T> m; > diff --git a/gcc/testsuite/g++.dg/template/crash83.C > b/gcc/testsuite/g++.dg/template/crash83.C > index b83dd21..7dcbed9 100644 > --- a/gcc/testsuite/g++.dg/template/crash83.C > +++ b/gcc/testsuite/g++.dg/template/crash83.C > @@ -2,4 +2,4 @@ > > template<int> struct A {}; > > -template<typename = class A<0>: > struct B {}; // { dg-error "explicit > specialization|expected" } > +template<typename = class A<0>: > struct B {}; // { dg-error "" } > diff --git a/gcc/testsuite/g++.dg/template/error55.C > b/gcc/testsuite/g++.dg/template/error55.C > new file mode 100644 > index 0000000..41f9595 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/error55.C > @@ -0,0 +1,8 @@ > +// Check that template template parameters get printed properly in error > +// messages. > + > +template <template <class A> class B> > +struct Y > +{ > + B<5> y; // { dg-error "for 'template<class A> class B'" } > +}; > diff --git a/gcc/testsuite/g++.dg/template/pr30044.C > b/gcc/testsuite/g++.dg/template/pr30044.C > new file mode 100644 > index 0000000..415e6f0 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/pr30044.C > @@ -0,0 +1,14 @@ > +// PR c++/30044 > + > +template <typename T1, typename T2, template <T2> class Comp, class Result = > Comp<1> > > +struct sort { }; > + > + > +template <typename Type, template <Type, Type> class Comp, class Result = > Comp<1, 2> > > +struct sort2 { }; > + > +template <typename Type, template <int, Type> class Comp, class Result = > Comp<1, 2> > > +struct sort3 { }; > + > +template <template <typename T1, typename T2, template <T2> class Comp, > class Result = Comp<1> > class Foo> > +struct sort4 { }; > diff --git a/gcc/testsuite/g++.dg/template/shadow2.C > b/gcc/testsuite/g++.dg/template/shadow2.C > new file mode 100644 > index 0000000..7f6a6dc > --- /dev/null > +++ b/gcc/testsuite/g++.dg/template/shadow2.C > @@ -0,0 +1,3 @@ > +template <class A, // { dg-error "shadows template parm 'class A'" } > + template <class A> class B> // { dg-error "declaration of 'class > A'" } > +class X; > diff --git a/gcc/testsuite/g++.dg/torture/20070621-1.C > b/gcc/testsuite/g++.dg/torture/20070621-1.C > index 15d1ac7..9bd8cc3 100644 > --- a/gcc/testsuite/g++.dg/torture/20070621-1.C > +++ b/gcc/testsuite/g++.dg/torture/20070621-1.C > @@ -89,7 +89,7 @@ namespace __gnu_test { > SharedInfo->first=ptr; > } > }; > - template <class T, template<class T> class ItType> struct > test_container { > + template <class T, template<class U> class ItType> struct > test_container { > typename ItType<T>::ContainerType bounds; > test_container(T* _first, T* _last):bounds(_first, _last) { > } > diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ttp42.C > b/gcc/testsuite/g++.old-deja/g++.pt/ttp42.C > index 53bdae1..a2ac239 100644 > --- a/gcc/testsuite/g++.old-deja/g++.pt/ttp42.C > +++ b/gcc/testsuite/g++.old-deja/g++.pt/ttp42.C > @@ -1,5 +1,5 @@ > // { dg-do run } > -template <class T, template <class T> class C> > +template <class T, template <class U> class C> > struct X > {}; > > -- > 2.5.0.rc0.5.g91e10c5.dirty >
Ping.