diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 55c23b642bcc1ef8a7836efc840c9fdb07424a98..f9abb21a9a2108997bc4e1ccdb749dc871d3c09b 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30682,7 +30682,7 @@ ctad_template_p (tree tmpl) type. */ static tree -do_class_deduction (tree ptype, tree tmpl, tree init, +do_class_deduction (tree ptype, tree tmpl, tree init, tree outer_targs, int flags, tsubst_flags_t complain) { /* We should have handled this in the caller. */ @@ -30744,6 +30744,23 @@ do_class_deduction (tree ptype, tree tmpl, tree init, if (type_dependent_expression_p (init)) return ptype; + if (outer_targs) + { + int args_depth = TMPL_ARGS_DEPTH (outer_targs); + int parms_depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl)); + if (parms_depth > 1) + { + /* Substitute outer arguments into this CTAD template from the + current instantiation. */ + int want = std::min (args_depth, parms_depth - 1); + outer_targs = strip_innermost_template_args (outer_targs, + args_depth - want); + tmpl = tsubst (tmpl, outer_targs, complain, NULL_TREE); + if (tmpl == error_mark_node) + return error_mark_node; + } + } + /* Don't bother with the alias rules for an equivalent template. */ tmpl = get_underlying_template (tmpl); @@ -30999,7 +31016,7 @@ do_auto_deduction (tree type, tree init, tree auto_node, if (tree ctmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node)) /* C++17 class template argument deduction. */ - return do_class_deduction (type, ctmpl, init, flags, complain); + return do_class_deduction (type, ctmpl, init, outer_targs, flags, complain); if (init == NULL_TREE || TREE_TYPE (init) == NULL_TREE) /* Nothing we can do with this, even in deduction context. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/nontype-class65.C b/gcc/testsuite/g++.dg/cpp2a/nontype-class65.C new file mode 100644 index 0000000000000000000000000000000000000000..8397ea5a886e7029edf409c9b51fae08b120d66a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/nontype-class65.C @@ -0,0 +1,16 @@ +// PR c++/113649 +// { dg-do compile { target c++20 } } + +template<class... Args> +struct A { + template<class Ret> + struct Fun { constexpr Fun(Ret(*)(Args...)) { } }; + + template<Fun f> + struct B { using type = decltype(f); }; +}; + +bool f(char, long); + +using type = A<char, long>::B<&f>::type; +using type = A<char, long>::Fun<bool>;