c++: constrained lambda inside template [PR92633]
authorPatrick Palka <ppalka@redhat.com>
Tue, 2 Jun 2020 01:37:04 +0000 (21:37 -0400)
committerPatrick Palka <ppalka@redhat.com>
Tue, 2 Jun 2020 01:37:04 +0000 (21:37 -0400)
When regenerating a constrained lambda during instantiation of an
enclosing template, we are forgetting to substitute into the lambda's
constraints.  Fix this by substituting through the constraints during
tsubst_lambda_expr.

gcc/cp/ChangeLog:

PR c++/92633
PR c++/92838
* pt.c (tsubst_function_decl): Don't do set_constraints when
regenerating a lambda.
(tsubst_lambda_expr): Substitute into the lambda's constraints
and do set_constraints here.

gcc/testsuite/ChangeLog:

PR c++/92633
PR c++/92838
* g++.dg/cpp2a/concepts-lambda11.C: New test.
* g++.dg/cpp2a/concepts-lambda12.C: New test.

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

index df647af..907ca87 100644 (file)
@@ -13854,7 +13854,10 @@ tsubst_function_decl (tree t, tree args, tsubst_flags_t complain,
      don't substitute through the constraints; that's only done when
      they are checked.  */
   if (tree ci = get_constraints (t))
-    set_constraints (r, ci);
+    /* Unless we're regenerating a lambda, in which case we'll set the
+       lambda's constraints in tsubst_lambda_expr.  */
+    if (!lambda_fntype)
+      set_constraints (r, ci);
 
   if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t))
     SET_DECL_FRIEND_CONTEXT (r,
@@ -19029,6 +19032,17 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
          finish_member_declaration (fn);
        }
 
+      if (tree ci = get_constraints (oldfn))
+       {
+         /* Substitute into the lambda's constraints.  */
+         if (oldtmpl)
+           ++processing_template_decl;
+         ci = tsubst_constraint_info (ci, args, complain, in_decl);
+         if (oldtmpl)
+           --processing_template_decl;
+         set_constraints (fn, ci);
+       }
+
       /* Let finish_function set this.  */
       DECL_DECLARED_CONSTEXPR_P (fn) = false;
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda11.C
new file mode 100644 (file)
index 0000000..dd9cd4e
--- /dev/null
@@ -0,0 +1,17 @@
+// PR c++/92838
+// { dg-do compile { target c++20 } }
+
+template<int N>
+auto foo()
+{
+  [] () requires (N != 0) { }(); // { dg-error "no match" }
+  [] () requires (N == 0) { }();
+
+  [] <int M=1> () requires (N == M) { }(); // { dg-error "no match" }
+  [] <int M=1> () requires (N != M) { }();
+}
+
+void bar()
+{
+  foo<0>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda12.C
new file mode 100644 (file)
index 0000000..2bc9fd0
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/92633
+// { dg-do compile { target c++20 } }
+
+template<class A, class B>
+concept different_than = !__is_same_as(A, B);
+
+template<class B>
+auto diff(B) {
+    return [](different_than<B> auto a) {};
+}
+
+int main() {
+    diff(42)("");
+    diff(42)(42); // { dg-error "no match" }
+}