]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: NTTP constraint depending on outer parms [PR109160]
authorPatrick Palka <ppalka@redhat.com>
Sat, 1 Apr 2023 16:01:30 +0000 (12:01 -0400)
committerPatrick Palka <ppalka@redhat.com>
Sat, 1 Apr 2023 16:01:30 +0000 (12:01 -0400)
Here we're crashing during satisfaction for the NTTP 'C<B> auto V'
ultimately because convert_template_argument / unify don't pass all
outer template arguments to do_auto_deduction, and during satisfaction
we need to know all arguments.  While these callers do pass some outer
arguments, they are only sufficient to properly substitute the
(level-lowered) 'auto' and are not necessarily the entire set.

Fortunately it seems these callers have access to the full set of outer
arguments via convert_template_argument's 'in_decl' parameter and
unify's 'tparms' parameter.  So this patch adds a new parameter to
do_auto_deduction, used only during adc_unify deduction, through which
these callers can pass the enclosing (partially instantiated) template
and from which do_auto_deduction can obtain _all_ outer template
arguments for sake of satisfaction.

This patch also ensures that the 'in_decl' argument passed to
coerce_template_parms is always a TEMPLATE_DECL, which in turn allows us
to pass it as-is to do_auto_deduction; the only coerce_template_parms
caller that needed adjustment was tsubst_decl it seems.

PR c++/109160

gcc/cp/ChangeLog:

* cp-tree.h (do_auto_deduction): Add defaulted tmpl parameter.
* pt.cc (convert_template_argument): Pass 'in_decl' as 'tmpl' to
do_auto_deduction.
(tsubst_decl) <case VAR_/TYPE_DECL>: Pass 'tmpl' instead of 't' as
'in_decl' to coerce_template_parms.
(unify) <case TEMPLATE_PARM_INDEX>: Pass TPARMS_PRIMARY_TEMPLATE
as 'tmpl' to do_auto_deduction.
(do_auto_deduction): Document default arguments.  Rename local
variable 'tmpl' to 'ctmpl'.  Use 'tmpl' to obtain a full set of
template arguments for satisfaction in the adc_unify case.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-placeholder12.C: New test.

gcc/cp/cp-tree.h
gcc/cp/pt.cc
gcc/testsuite/g++.dg/cpp2a/concepts-placeholder12.C [new file with mode: 0644]

index d450b3d5b78adc9e208fbdacc196b1201247fc7d..622752ae4e6e9d5967f844f3c79e7cbbc5856d9c 100644 (file)
@@ -7326,7 +7326,8 @@ extern tree do_auto_deduction                   (tree, tree, tree,
                                                  auto_deduction_context
                                                 = adc_unspecified,
                                                 tree = NULL_TREE,
-                                                int = LOOKUP_NORMAL);
+                                                int = LOOKUP_NORMAL,
+                                                tree = NULL_TREE);
 extern tree type_uses_auto                     (tree);
 extern tree type_uses_auto_or_concept          (tree);
 extern void append_type_to_template_for_access_check (tree, tree, tree,
index 022f295b36f8bc26fa8d78bae6e4232bd50453a0..4429ae66b68218a7c34e21b6fce38b68c47a9dc6 100644 (file)
@@ -8644,7 +8644,7 @@ convert_template_argument (tree parm,
       else if (tree a = type_uses_auto (t))
        {
          t = do_auto_deduction (t, arg, a, complain, adc_unify, args,
-                                LOOKUP_IMPLICIT);
+                                LOOKUP_IMPLICIT, /*tmpl=*/in_decl);
          if (t == error_mark_node)
            return error_mark_node;
        }
@@ -15252,7 +15252,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
                     the template.  */
                  argvec = (coerce_template_parms
                            (DECL_TEMPLATE_PARMS (gen_tmpl),
-                            argvec, t, complain));
+                            argvec, tmpl, complain));
                if (argvec == error_mark_node)
                  RETURN (error_mark_node);
                hash = spec_hasher::hash (gen_tmpl, argvec);
@@ -24730,7 +24730,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
          if (tree a = type_uses_auto (tparm))
            {
              tparm = do_auto_deduction (tparm, arg, a,
-                                        complain, adc_unify, targs);
+                                        complain, adc_unify, targs,
+                                        LOOKUP_NORMAL,
+                                        TPARMS_PRIMARY_TEMPLATE (tparms));
              if (tparm == error_mark_node)
                return 1;
            }
@@ -30779,13 +30781,20 @@ unparenthesized_id_or_class_member_access_p (tree init)
    adc_requirement contexts to communicate the necessary template arguments
    to satisfaction.  OUTER_TARGS is ignored in other contexts.
 
-   For partial-concept-ids, extra args may be appended to the list of deduced
-   template arguments prior to determining constraint satisfaction.  */
+   Additionally for adc_unify contexts TMPL is the template for which TYPE
+   is a template parameter type.
+
+   For partial-concept-ids, extra args from OUTER_TARGS, TMPL and the current
+   scope may be appended to the list of deduced template arguments prior to
+   determining constraint satisfaction as appropriate.  */
 
 tree
 do_auto_deduction (tree type, tree init, tree auto_node,
-                   tsubst_flags_t complain, auto_deduction_context context,
-                  tree outer_targs, int flags)
+                  tsubst_flags_t complain /* = tf_warning_or_error */,
+                  auto_deduction_context context /* = adc_unspecified */,
+                  tree outer_targs /* = NULL_TREE */,
+                  int flags /* = LOOKUP_NORMAL */,
+                  tree tmpl /* = NULL_TREE */)
 {
   if (init == error_mark_node)
     return error_mark_node;
@@ -30821,9 +30830,9 @@ do_auto_deduction (tree type, tree init, tree auto_node,
                                        /*return*/true)))
     init = r;
 
-  if (tree tmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
+  if (tree ctmpl = CLASS_PLACEHOLDER_TEMPLATE (auto_node))
     /* C++17 class template argument deduction.  */
-    return do_class_deduction (type, tmpl, init, flags, complain);
+    return do_class_deduction (type, ctmpl, init, flags, complain);
 
   if (init == NULL_TREE || TREE_TYPE (init) == NULL_TREE)
     /* Nothing we can do with this, even in deduction context.  */
@@ -30975,7 +30984,10 @@ do_auto_deduction (tree type, tree init, tree auto_node,
                }
            }
 
-      tree full_targs = add_to_template_args (outer_targs, targs);
+      tree full_targs = outer_targs;
+      if (context == adc_unify && tmpl)
+       full_targs = add_outermost_template_args (tmpl, full_targs);
+      full_targs = add_to_template_args (full_targs, targs);
 
       /* HACK: Compensate for callers not always communicating all levels of
         outer template arguments by filling in the outermost missing levels
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-placeholder12.C
new file mode 100644 (file)
index 0000000..22f0ac5
--- /dev/null
@@ -0,0 +1,29 @@
+// PR c++/109160
+// { dg-do compile { target c++20 } }
+
+template<class T, bool B>
+concept C = B;
+
+template<int> struct X { };
+
+template<bool B>
+struct A {
+  template<C<B> auto V> static void f();
+  template<C<B> auto V> static void g(X<V>);
+  template<C<B> auto V> static inline int value;
+  template<C<B> auto V> struct D { };
+};
+
+int main() {
+  A<true>::f<0>();
+  A<false>::f<0>(); // { dg-error "no match|constraints" }
+
+  A<true>::g(X<0>{});
+  A<false>::g(X<0>{}); // { dg-error "no match|constraints" }
+
+  bool v1 = A<true>::value<0>;
+  bool v2 = A<false>::value<0>;  // { dg-error "constraints" }
+
+  A<true>::D<0> d1;
+  A<false>::D<0> d2; // { dg-error "constraints" }
+}