From babd71c168ad447d2d11886683dea263ba1d814d Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 6 Nov 2019 15:20:00 -0500 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 5 ++++ 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 +-- 6 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-friend4.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e60a45b869e..c185af408b0 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2019-11-06 Jason Merrill + + C++20 NB CA378 - Remove constrained non-template functions. + * decl.c (grokfndecl): Reject constraints on non-templated function. + 2019-11-06 Matthias Kretz * parser.c (cp_parser_operator): Parse operator?: as an 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 concept Any = true; + +template +struct A +{ + friend void f() requires Any { } // OK + friend void g() requires Any; // { dg-error "" } +}; + +A 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 = [](T t) { return t; }; auto g1 = [] requires False (T t) { return t; }; auto g2 = [](T t) requires False { return t; }; - auto g3 = [](int t) requires False { return t; }; + auto g3 = [](int t) requires False { return t; }; // { dg-error "non-templated" } auto g4 = [](False auto t) { return t; }; auto g5 = [](auto t) requires False { return t; }; - auto g6 = [](int t) requires False { return t; }; - auto g7 = [](int t) requires false { return t; }; + auto g6 = [](int t) requires False { 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 = [&](T t) { return t; }; auto g1 = [&] requires False (T t) { return t; }; auto g2 = [&](T t) requires False { return t; }; - auto g3 = [&](int t) requires False { return t; }; + auto g3 = [&](int t) requires False { return t; }; // { dg-error "non-templated" } auto g4 = [&](False auto t) { return t; }; auto g5 = [&](auto t) requires False { return t; }; - auto g6 = [&](int t) requires False { return t; }; - auto g7 = [&](int t) requires false { return t; }; + auto g6 = [&](int t) requires False { 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 = [](T t) requires (N < 4) { return t; }; z.operator()(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()(5); foo2.b()(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 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" } -- 2.30.2