]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: unqualified member template in constraint [PR101247]
authorPatrick Palka <ppalka@redhat.com>
Fri, 2 Jul 2021 17:54:57 +0000 (13:54 -0400)
committerPatrick Palka <ppalka@redhat.com>
Fri, 2 Jul 2021 17:54:57 +0000 (13:54 -0400)
Here any_template_parm_r is failing to mark the template parameters
implicitly used by the unqualified use of 'd' inside the constraint
because the code to do so assumes each level of a template parameter
list points to the corresponding primary template, but here the
parameter level for A in the out-of-line definition of A::B does not
(nor do the parameter levels for A and C in the definition of A::C),
which causes us to overlook the sharing.

So it seems we can't in general depend on the TREE_TYPE of a template
parameter level being non-empty here.  This patch partially fixes this
by rewriting the relevant part of any_template_parm_r to not depend on
the TREE_TYPE of outer levels.  We still depend on the innermost level
to point to the innermost primary template, so we still crash on the
commented out line in the below testcase.

PR c++/101247

gcc/cp/ChangeLog:

* pt.c (any_template_parm_r) <case TEMPLATE_DECL>: Rewrite to
use common_enclosing_class and to not depend on the TREE_TYPE
of outer levels pointing to the corresponding primary template.

gcc/testsuite/ChangeLog:

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

gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl4.C [new file with mode: 0644]

index dda6c9e940d436b07f11dbb58337d82cfdf6e6a0..7e56ccfc45fceb43c517020e8a3ef6ccf85cfe7b 100644 (file)
@@ -10731,24 +10731,11 @@ any_template_parm_r (tree t, void *data)
       {
        /* If T is a member template that shares template parameters with
           ctx_parms, we need to mark all those parameters for mapping.  */
-       tree dparms = DECL_TEMPLATE_PARMS (t);
-       tree cparms = ftpi->ctx_parms;
-       while (TMPL_PARMS_DEPTH (dparms) > ftpi->max_depth)
-         dparms = TREE_CHAIN (dparms);
-       while (TMPL_PARMS_DEPTH (cparms) > TMPL_PARMS_DEPTH (dparms))
-         cparms = TREE_CHAIN (cparms);
-       while (dparms
-              && (TREE_TYPE (TREE_VALUE (dparms))
-                  != TREE_TYPE (TREE_VALUE (cparms))))
-         dparms = TREE_CHAIN (dparms),
-           cparms = TREE_CHAIN (cparms);
-       if (dparms)
-         {
-           int ddepth = TMPL_PARMS_DEPTH (dparms);
-           tree dargs = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (t)));
-           for (int i = 0; i < ddepth; ++i)
-             WALK_SUBTREE (TMPL_ARGS_LEVEL (dargs, i+1));
-         }
+       if (tree ctmpl = TREE_TYPE (INNERMOST_TEMPLATE_PARMS (ftpi->ctx_parms)))
+         if (tree com = common_enclosing_class (DECL_CONTEXT (t),
+                                                DECL_CONTEXT (ctmpl)))
+           if (tree ti = CLASSTYPE_TEMPLATE_INFO (com))
+             WALK_SUBTREE (TI_ARGS (ti));
       }
       break;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-memtmpl4.C
new file mode 100644 (file)
index 0000000..625149e
--- /dev/null
@@ -0,0 +1,28 @@
+// PR c++/101247
+// { dg-do compile { target concepts } }
+// A variant of concepts-memtmpl3.C where f is defined outside A's definition.
+
+template <typename> struct A {
+  template <typename c> static constexpr bool d = true;
+  struct B;
+  template <typename> struct C;
+};
+
+template <typename a>
+struct A<a>::B {
+  template <typename c> static void f(c) requires d<c>;
+};
+
+template <typename a>
+template <typename b>
+struct A<a>::C {
+  template <typename c> static void f(c) requires d<c>;
+  static void g() requires d<b>;
+};
+
+int main()
+{
+  A<void>::B::f(0);
+  A<void>::C<int>::f(0);
+  // A<void>::C<int>::g();
+}