diff mbox series

C++20 CA378 - Remove constrained non-template functions.

Message ID 20191106201949.25790-1-jason@redhat.com
State New
Headers show
Series C++20 CA378 - Remove constrained non-template functions. | expand

Commit Message

Jason Merrill Nov. 6, 2019, 8:19 p.m. UTC
No real use cases have 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.

Tested x86_64-pc-linux-gnu, applying to trunk.

	* decl.c (grokfndecl): Reject constraints on non-templated function.
---
 gcc/cp/decl.c                                 | 12 ++++++++-
 gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C | 13 ++++++++++
 gcc/testsuite/g++.dg/cpp2a/concepts-lambda2.C | 26 +++++++++----------
 gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C |  4 +--
 .../g++.dg/cpp2a/concepts-requires1.C         |  4 +--
 5 files changed, 41 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C


base-commit: c86ac070c0efbe6240b6ad56823af4d697562d90
diff mbox series

Patch

diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3bfcfb2c6b7..5c5a85e3221 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
index 00000000000..88f9fe825f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C
@@ -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;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda2.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda2.C
index ffad95cb77a..a7419d69a46 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda2.C
@@ -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" }
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C
index 7e668ffeddd..96da7852a70 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C
@@ -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;
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C b/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
index 0c2651620ba..62cc21dd7e1 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C
@@ -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" }