C++20 NB CA378 - Remove constrained non-template functions.
authorJason Merrill <jason@redhat.com>
Wed, 6 Nov 2019 20:20:00 +0000 (15:20 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 6 Nov 2019 20:20:00 +0000 (15:20 -0500)
No real use cases have ever arisen for constraints on non-templated
functions, and handling of them has never been entirely clear, so the
committee agreed to accept this national body comment proposing that we
remove them.

* decl.c (grokfndecl): Reject constraints on non-templated function.

From-SVN: r277891

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/concepts-lambda2.C
gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C
gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C

index e60a45b869ea575dbb8b03b85acfca1fa6594a9b..c185af408b0247bfa8fd0aafc4bca2e53b363623 100644 (file)
@@ -1,3 +1,8 @@
+2019-11-06  Jason Merrill  <jason@redhat.com>
+
+       C++20 NB CA378 - Remove constrained non-template functions.
+       * decl.c (grokfndecl): Reject constraints on non-templated function.
+
 2019-11-06  Matthias Kretz  <m.kretz@gsi.de>
 
        * parser.c (cp_parser_operator): Parse operator?: as an
index 3bfcfb2c6b73fec3dc38588175507fd46b784679..5c5a85e3221e6886f8f7dbc42ea2220b4ca849de 100644 (file)
@@ -9262,7 +9262,9 @@ grokfndecl (tree ctype,
   if (flag_concepts)
     {
       tree tmpl_reqs = NULL_TREE;
-      if (processing_template_decl > template_class_depth (ctype))
+      tree ctx = friendp ? current_class_type : ctype;
+      bool memtmpl = (processing_template_decl > template_class_depth (ctx));
+      if (memtmpl)
         tmpl_reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
       tree ci = build_constraints (tmpl_reqs, decl_reqs);
       if (concept_p && ci)
@@ -9270,6 +9272,14 @@ grokfndecl (tree ctype,
           error_at (location, "a function concept cannot be constrained");
           ci = NULL_TREE;
         }
+      /* C++20 CA378: Remove non-templated constrained functions.  */
+      if (ci && !flag_concepts_ts
+         && (!processing_template_decl
+             || (friendp && !memtmpl && !funcdef_flag)))
+       {
+         error_at (location, "constraints on a non-templated function");
+         ci = NULL_TREE;
+       }
       set_constraints (decl, ci);
     }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C
new file mode 100644 (file)
index 0000000..88f9fe8
--- /dev/null
@@ -0,0 +1,13 @@
+// C++20 NB comment US115
+// { dg-do compile { target c++2a } }
+
+template <class T> concept Any = true;
+
+template <class T>
+struct A
+{
+  friend void f() requires Any<T> { } // OK
+  friend void g() requires Any<T>;    // { dg-error "" }
+};
+
+A<int> a;
index ffad95cb77ae59a4927f6ad501f50ec7331785bc..a7419d69a4651010886144c78093fb64b6832f50 100644 (file)
@@ -60,19 +60,19 @@ void test0()
   auto g0 = []<False T>(T t) { return t; };
   auto g1 = []<typename T> requires False<T> (T t) { return t; };
   auto g2 = []<typename T>(T t) requires False<decltype(t)> { return t; };
-  auto g3 = [](int t) requires False<decltype(t)> { return t; };
+  auto g3 = [](int t) requires False<decltype(t)> { return t; }; // { dg-error "non-templated" }
   auto g4 = [](False auto t) { return t; };
   auto g5 = [](auto t) requires False<decltype(t)> { return t; };
-  auto g6 = [](int t) requires False<int> { return t; };
-  auto g7 = [](int t) requires false { return t; };
+  auto g6 = [](int t) requires False<int> { return t; }; // { dg-error "non-templated" }
+  auto g7 = [](int t) requires false { return t; };     // { dg-error "non-templated" }
   g0(0); // { dg-error "no match" }
   g1(0); // { dg-error "no match" }
   g2(0); // { dg-error "no match" }
-  g3(0); // { dg-error "no match" }
+  g3(0);
   g4(0); // { dg-error "no match" }
   g5(0); // { dg-error "no match" }
-  g6(0); // { dg-error "no match" }
-  g7(0); // { dg-error "no match" }
+  g6(0);
+  g7(0);
 }
 
 void test1()
@@ -81,19 +81,19 @@ void test1()
   auto g0 = [&]<False T>(T t) { return t; };
   auto g1 = [&]<typename T> requires False<T> (T t) { return t; };
   auto g2 = [&]<typename T>(T t) requires False<decltype(t)> { return t; };
-  auto g3 = [&](int t) requires False<decltype(t)> { return t; };
+  auto g3 = [&](int t) requires False<decltype(t)> { return t; }; // { dg-error "non-templated" }
   auto g4 = [&](False auto t) { return t; };
   auto g5 = [&](auto t) requires False<decltype(t)> { return t; };
-  auto g6 = [&](int t) requires False<int> { return t; };
-  auto g7 = [&](int t) requires false { return t; };
+  auto g6 = [&](int t) requires False<int> { return t; }; // { dg-error "non-templated" }
+  auto g7 = [&](int t) requires false { return t; };     // { dg-error "non-templated" }
   g0(0); // { dg-error "no match" }
   g1(0); // { dg-error "no match" }
   g2(0); // { dg-error "no match" }
-  g3(0); // { dg-error "no match" }
+  g3(0);
   g4(0); // { dg-error "no match" }
   g5(0); // { dg-error "no match" }
-  g6(0); // { dg-error "no match" }
-  g7(0); // { dg-error "no match" }
+  g6(0);
+  g7(0);
 }
 
 void test2()
@@ -147,7 +147,7 @@ using Func = int(*)(int);
 
 void test6()
 {
-  Func f1 = [](int a) requires false { return a; }; // { dg-error "cannot convert" }
+  Func f1 = [](int a) requires false { return a; }; // { dg-error "non-templated" }
   Func f2 = [](auto a) requires false { return a; }; // { dg-error "cannot convert" }
 }
 
index 7e668ffeddd346efa0d6eb901adf135dd73a49c4..96da7852a70f060aef7b644ac200a6067fbadcd7 100644 (file)
@@ -34,7 +34,7 @@ int main(int, char**)
   auto z = []<typename T, int N = 5>(T t) requires (N < 4) { return t; };
   z.operator()<int, 3>(5);
 
-  [](int t) requires true { return t; }(5);
+  [](auto t) requires true { return t; }(5);
   [](C1 auto t) { return t; }(5);
 
   auto a0 = [](IsNotLarge auto a) { return [](auto b){ return b; }; };
@@ -57,7 +57,7 @@ int main(int, char**)
   foo2.b<int>()(5);
   foo2.b<long long>()(5);
 
-  Func m1 = [](int a) -> int requires true { return a; };
+  Func m1 = [](auto a) -> int requires true { return a; };
 
   return 0;
 }
index 0c2651620babdc3b0369d0ed55827d6369a49816..62cc21dd7e180ae236d3f156e18f3fc6c3e32d50 100644 (file)
@@ -7,8 +7,8 @@ concept Class = __is_class(T);
 template<typename T>
 concept C = requires { typename T::type; };
 
-void f1(int a) requires true;         // OK
-auto f2(int a) -> bool requires true; // OK
+void f1(int a) requires true;         // { dg-error "non-templated" }
+auto f2(int a) -> bool requires true; // { dg-error "non-templated" }
 auto f3(int a) requires true -> bool; // { dg-error "" } requires-clause precedes trailing-return-type
 typedef void fn_t() requires true;    // { dg-error "typedef" }
 void (*pf)() requires true;           // { dg-error "non-function" }