aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-11-06 15:20:00 -0500
committerJason Merrill <jason@gcc.gnu.org>2019-11-06 15:20:00 -0500
commitbabd71c168ad447d2d11886683dea263ba1d814d (patch)
tree890e5bf75cb35d71ba7b7d79a17c57c0156edc10 /gcc
parent5d24b4f2dad8883db004481ebd633a0bf8d4f8e9 (diff)
downloadgcc-babd71c168ad447d2d11886683dea263ba1d814d.zip
gcc-babd71c168ad447d2d11886683dea263ba1d814d.tar.gz
gcc-babd71c168ad447d2d11886683dea263ba1d814d.tar.bz2
C++20 NB CA378 - Remove constrained non-template functions.
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/decl.c12
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-lambda2.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-lambda3.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-requires1.C4
6 files changed, 46 insertions, 18 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e60a45b..c185af4 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 3bfcfb2..5c5a85e 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 0000000..88f9fe8
--- /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 ffad95c..a7419d6 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 7e668ff..96da785 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 0c26516..62cc21d 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" }