diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 8d65a6e5bd2..a4686e0affb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28643,7 +28643,7 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com tree ctmpl = CLASSTYPE_TI_TEMPLATE (type); tparms = DECL_TEMPLATE_PARMS (ctmpl); - targs = CLASSTYPE_TI_ARGS (type); + targs = INNERMOST_TEMPLATE_ARGS (CLASSTYPE_TI_ARGS (type)); ci = NULL_TREE; fargs = NULL_TREE; loc = DECL_SOURCE_LOCATION (ctmpl); @@ -28866,8 +28866,22 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) if (init == NULL_TREE) return NULL_TREE; + /* We might be creating a guide for a class member template, e.g., + + template struct A { + template struct B { T t; }; + }; + + At this point, A will have been instantiated. Below, we need to + use both A::B (TEMPLATE_TYPE) and A::B (TYPE) types. */ + const bool member_template_p + = (DECL_TEMPLATE_INFO (tmpl) + && DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (tmpl))); tree type = TREE_TYPE (tmpl); - if (!CP_AGGREGATE_TYPE_P (type)) + tree template_type = (member_template_p + ? TREE_TYPE (DECL_TI_TEMPLATE (tmpl)) + : type); + if (!CP_AGGREGATE_TYPE_P (template_type)) return NULL_TREE; /* No aggregate candidate for copy-initialization. */ @@ -28884,10 +28898,21 @@ maybe_aggr_guide (tree tmpl, tree init, vec *args) tree parms = NULL_TREE; if (BRACE_ENCLOSED_INITIALIZER_P (init)) { - init = reshape_init (type, init, complain); + init = reshape_init (template_type, init, complain); if (init == error_mark_node) return NULL_TREE; parms = collect_ctor_idx_types (init, parms); + /* If we're creating a deduction guide for a member class template, + we've used the original template pattern type for the reshape_init + above; this is done because we want PARMS to be a template parameter + type, something that can be deduced when used as a function template + parameter. At this point the outer class template has already been + partially instantiated (we deferred the deduction until the enclosing + scope is non-dependent). Therefore we have to partially instantiate + PARMS, so that its template level is properly reduced and we don't get + mismatches when deducing types using the guide with PARMS. */ + if (member_template_p) + parms = tsubst (parms, DECL_TI_ARGS (tmpl), complain, init); } else if (TREE_CODE (init) == TREE_LIST) { @@ -29225,6 +29250,11 @@ do_class_deduction (tree ptype, tree tmpl, tree init, if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)) return ptype; + /* Wait until the enclosing scope is non-dependent. */ + if (DECL_CLASS_SCOPE_P (tmpl) + && dependent_type_p (DECL_CONTEXT (tmpl))) + return ptype; + /* Initializing one placeholder from another. */ if (init && TREE_CODE (init) == TEMPLATE_PARM_INDEX && is_auto (TREE_TYPE (init)) diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C new file mode 100644 index 00000000000..86a68248157 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction81.C @@ -0,0 +1,20 @@ +// PR c++/97034 +// { dg-do compile { target c++17 } } + +template +struct E { + template + struct G { + T t; + G(T) { } + }; + + void fn() { G{1}; } +}; + +void +g () +{ + E e; + e.fn (); +} diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C new file mode 100644 index 00000000000..238024c508f --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction82.C @@ -0,0 +1,12 @@ +// PR c++/99009 +// { dg-do compile { target c++17 } } + +template struct B { + B(int = A()) {} + template struct A; +}; + +template struct X { + template struct Y; + X() { Y y; }; +}; diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C new file mode 100644 index 00000000000..be922bbfb73 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr10.C @@ -0,0 +1,21 @@ +// PR c++/97034 +// { dg-do compile { target c++20 } } + +namespace N { +template struct S { + template S(T, U); +}; +} // namespace N +template struct E { + template struct M { + template struct G { T t; }; + void fn() { G{N::S{'a', 1}}; } + }; +}; + +void +g () +{ + E<1>::M m; + m.fn (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C new file mode 100644 index 00000000000..399061100ae --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr8.C @@ -0,0 +1,19 @@ +// PR c++/97034 +// { dg-do compile { target c++20 } } + +namespace N { +template struct S { + template S(T, U); +}; +} // namespace N +template struct E { + template struct G { T t; }; + void fn() { G{N::S{'a', 1}}; } +}; + +void +g () +{ + E<1> e; + e.fn (); +} diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C new file mode 100644 index 00000000000..245a04cd5f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr9.C @@ -0,0 +1,18 @@ +// PR c++/97034 +// { dg-do compile { target c++20 } } + +template +struct E { + template + struct G { + T t; + }; + + void fn() { G{1}; } +}; + +void +g () { + E e; + e.fn (); +}