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. */
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);
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. */
--- /dev/null
+// 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>;