In the testcase below, we're crashing during constraint checking of the implicitly generated deduction guides for the nested class template A::B because we never substitute the outer template arguments (for A) into the constraint, neither ahead of time nor as part of satisfaction.
Ideally we'd like to avoid substituting into a constraint ahead of time, but the "flattening" vector 'tsubst_args' is constructed under the assumption that all outer template arguments are already substituted in, and eliminating this assumption to yield a flattening vector that includes outer (generic) template arguments suitable for substituting into the constraint would be tricky. So this patch takes the approximate approach of substituting the outer arguments into the constraint ahead of time, so that we could subsequently substitute 'tsubst_args' into the constraint. NB: I noticed that [over.match.class.deduct]/1, which describes how guides are formed from constructors of a class template, doesn't mention that a guide inherits the constraints of the corresponding constructor. Though [over.match.class.deduct]/2 later suggests that guides do have constraints: "The associated constraints [of f'] are the conjunction of the associated constraints of [the guide] g and ..." So I'm unsure if we're being conforming by giving guides the constraints of the corresponding constructor. Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look OK for trunk and 10 branch (after 10.3 is released)? gcc/cp/ChangeLog: PR c++/97679 * pt.c (build_deduction_guide): Substitute outer template arguments into the constraints. gcc/testsuite/ChangeLog: PR c++/97679 * g++.dg/cpp2a/concepts-ctad3.C: New test. --- gcc/cp/pt.c | 17 +++++++++++++++-- gcc/testsuite/g++.dg/cpp2a/concepts-ctad3.C | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-ctad3.C diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7917a280804..6f44199e8eb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -28719,7 +28719,15 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com if (fparms == error_mark_node) ok = false; if (ci) - ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor); + { + if (outer_args) + /* FIXME: We'd like to avoid substituting outer template + arguments into the constraint ahead of time, but the + construction of tsubst_args assumes that outer arguments + are already substituted in. */ + ci = tsubst_constraint_info (ci, outer_args, complain, ctor); + ci = tsubst_constraint_info (ci, tsubst_args, complain, ctor); + } /* Parms are to have DECL_CHAIN tsubsted, which would be skipped if cp_unevaluated_operand. */ @@ -28735,7 +28743,12 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com fparms = tsubst_arg_types (fparms, targs, NULL_TREE, complain, ctor); fargs = tsubst (fargs, targs, complain, ctor); if (ci) - ci = tsubst_constraint_info (ci, targs, complain, ctor); + { + if (outer_args) + /* FIXME: As above. */ + ci = tsubst_constraint_info (ci, outer_args, complain, ctor); + ci = tsubst_constraint_info (ci, targs, complain, ctor); + } } --processing_template_decl; diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-ctad3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad3.C new file mode 100644 index 00000000000..3546b7461a8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/concepts-ctad3.C @@ -0,0 +1,16 @@ +// PR c++/97679 +// { dg-do compile { target c++20 } } + +template <bool V> struct A { + template <class T> struct B { + B(T) requires V; + template <class U> B(T, U) requires V || (__is_same(T, char) && __is_same(U, int)); + }; +}; + +A<true>::B x1(0); +A<false>::B x2(0); // { dg-error "deduction|no match" } + +A<true>::B y1(0, '0'); +A<false>::B y2(0, '0'); // { dg-error "deduction|no match" } +A<false>::B y3('0', 0); -- 2.31.1.189.g2e36527f23