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

Reply via email to