]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: implicit dummy object in requires clause [PR103198]
authorPatrick Palka <ppalka@redhat.com>
Fri, 19 Nov 2021 00:32:22 +0000 (19:32 -0500)
committerPatrick Palka <ppalka@redhat.com>
Fri, 19 Nov 2021 00:32:22 +0000 (19:32 -0500)
In the testcase below satisfaction misbehaves for f and g ultimately
because find_template_parameters fails to notice that the constraint
'val.x' depends on the template parms of the class template.  In
contrast, satisfaction works just fine for h.

The problem seems to come down to a difference in how any_template_parm_r
handles 'this' vs a dummy object: it walks the TREE_TYPE of the former
but not the latter, and this causes us to miss the tparm dependencies in
f/g's constraints since in their case the implicit object parm through
which we access 'val' is a dummy object.  (For h, since we know it's a
non-static member function when parsing its trailing constraints, the
implicit object parm is 'this', not a dummy object.)

This patch fixes this inconsistency by making any_template_parm_r walk
into the TREE_TYPE of a dummy object, like it already does for 'this'.

PR c++/103198

gcc/cp/ChangeLog:

* pt.c (any_template_parm_r): Walk the TREE_TYPE of a dummy
object.

gcc/testsuite/ChangeLog:

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

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

index 71a771fd0f2e3b134c744c98e9590b61d12e59f0..6a2a937764842d72ef3b2e14d682b447f688e885 100644 (file)
@@ -10766,6 +10766,11 @@ any_template_parm_r (tree t, void *data)
        WALK_SUBTREE (TREE_TYPE (t));
       break;
 
+    case CONVERT_EXPR:
+      if (is_dummy_object (t))
+       WALK_SUBTREE (TREE_TYPE (t));
+      break;
+
     default:
       break;
     }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-this1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-this1.C
new file mode 100644 (file)
index 0000000..d717028
--- /dev/null
@@ -0,0 +1,30 @@
+// PR c++/103198
+// { dg-do compile { target c++20 } }
+
+template<class T, class = void>
+struct A {
+  T val;
+
+  template<class U>
+    requires requires { val.x; }
+  void f(U);
+
+  static void g(int)
+    requires requires { val.x; };
+
+  void h(int)
+    requires requires { val.x; };
+};
+
+struct B { int x; };
+struct C { };
+
+int main() {
+  A<B>().f(0);
+  A<B>().g(0);
+  A<B>().h(0);
+
+  A<C>().f(0); // { dg-error "no match" }
+  A<C>().g(0); // { dg-error "no match" }
+  A<C>().h(0); // { dg-error "no match" }
+}