The substitution we do in build_deduction_guide needs processing_template_decl set, since it's only partial instantiation, and also needs to be done on the template; substituting the FUNCTION_DECL pattern doesn't properly adjust the template parameters on the template, which we will use in building the deduction guide.
Tested x86_64-pc-linux-gnu, applying to trunk and 7.
commit a1ecbf88833602a7d37fd44f831d4c1efd6ffaf8 Author: Jason Merrill <ja...@redhat.com> Date: Thu Jun 29 14:12:09 2017 -0400 PR c++/81180 - ICE with C++17 deduction of member class template. * pt.c (build_deduction_guide): Correct member template handling. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 047d3ba..3ecacbd 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -25216,17 +25216,16 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) } else { + ++processing_template_decl; + + tree fn_tmpl + = (TREE_CODE (ctor) == TEMPLATE_DECL ? ctor + : DECL_TI_TEMPLATE (ctor)); if (outer_args) - ctor = tsubst (ctor, outer_args, complain, ctor); + fn_tmpl = tsubst (fn_tmpl, outer_args, complain, ctor); + ctor = DECL_TEMPLATE_RESULT (fn_tmpl); + type = DECL_CONTEXT (ctor); - tree fn_tmpl; - if (TREE_CODE (ctor) == TEMPLATE_DECL) - { - fn_tmpl = ctor; - ctor = DECL_TEMPLATE_RESULT (fn_tmpl); - } - else - fn_tmpl = DECL_TI_TEMPLATE (ctor); tparms = DECL_TEMPLATE_PARMS (fn_tmpl); /* If type is a member class template, DECL_TI_ARGS (ctor) will have @@ -25248,7 +25247,6 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) /* For a member template constructor, we need to flatten the two template parameter lists into one, and then adjust the function signature accordingly. This gets...complicated. */ - ++processing_template_decl; tree save_parms = current_template_parms; /* For a member template we should have two levels of parms/args, one @@ -25309,8 +25307,8 @@ build_deduction_guide (tree ctor, tree outer_args, tsubst_flags_t complain) ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor); current_template_parms = save_parms; - --processing_template_decl; } + --processing_template_decl; } if (!memtmpl) diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction40.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction40.C new file mode 100644 index 0000000..eeffa69 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction40.C @@ -0,0 +1,19 @@ +// PR c++/81180 +// { dg-options -std=c++1z } + +template < int I > struct int_{}; + +template < typename T > +struct A{ + template < typename U, int I > + struct B{ + B(U u, int_< I >){} + }; +}; + + +int main(){ + A< int >::B v(0, int_< 0 >()); + (void)v; +} +