This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [c++-concepts] Allow function parameters to be referenced in trailing requires clauses
- From: Andrew Sutton <andrew dot n dot sutton at gmail dot com>
- To: gcc-patches <gcc-patches at gcc dot gnu dot org>, Braden Obrzut <admin at maniacsvault dot net>, Jason Merrill <jason at redhat dot com>
- Date: Wed, 30 Jul 2014 07:49:04 -0400
- Subject: Re: [c++-concepts] Allow function parameters to be referenced in trailing requires clauses
- Authentication-results: sourceware.org; auth=none
- References: <53A00521 dot 7000909 at maniacsvault dot net>
Applied an updated version of this patch.
2014-7-30 Braden Obrzut <admin@maniacsvault.net>
* gcc/cp/parser.c (cp_parser_trailing_requirements): Handle requires
keyword manually so that we can push function parameters back into
scope.
* gcc/cp/decl.c (push_function_parms): New. Recovers and reopens
function parameter scope from declarator.
* gcc/testsuite/g++.dg/concepts/req*.C: New tests.
2014-07-30 Andrew Sutton <andrew.n.sutton@gmail.com>
* gcc/testsuite/g++.dg/concepts/test.C: Removed.
Andrew Sutton
On Tue, Jun 17, 2014 at 5:06 AM, Braden Obrzut <admin@maniacsvault.net> wrote:
> This patch allows function parameters to be referenced by trailing requires
> clauses. Typically this is used to refer to the type of an implicitly
> generated template. For example, the following should now be valid (where C
> is some previously defined concept):
>
> auto f1 (auto x) requires C<decltype(x)> ();
>
> Note that the test case trailing-requires-overload.C will fail to compile
> unless the previously submitted patch is applied first.
>
> 2014-06-17 Braden Obrzut <admin@maniacsvault.net>
> * gcc/cp/parser.c (cp_parser_trailing_requirements): Handle requires
> keyword manually so that we can push function parameters back into
> scope.
> * gcc/cp/decl.c (push_function_parms): New. Recovers and reopens
> function parameter scope from declarator.
> * gcc/testsuite/g++.dg/concepts/trailing-requires.C: New tests.
> * gcc/testsuite/g++.dg/concepts/trailing-requires-overload.C: New tests.
Index: gcc/testsuite/g++.dg/concepts/traits1.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/traits1.C (revision 212456)
+++ gcc/testsuite/g++.dg/concepts/traits1.C (working copy)
@@ -79,21 +79,21 @@ void f18() requires Enum<void>();
int main() {
- f1(); // { dg-error "cannot" }
- f2(); // { dg-error "cannot" }
- f3(); // { dg-error "cannot" }
- f4(); // { dg-error "cannot" }
- f5(); // { dg-error "cannot" }
- f6(); // { dg-error "cannot" }
- f7(); // { dg-error "cannot" }
- f8(); // { dg-error "cannot" }
- f9(); // { dg-error "cannot" }
- f10(); // { dg-error "cannot" }
- f11(); // { dg-error "cannot" }
- f12(); // { dg-error "cannot" }
- f13(); // { dg-error "cannot" }
- f14(); // { dg-error "cannot" }
- f15(); // { dg-error "cannot" }
- f16(); // { dg-error "cannot" }
- f17(); // { dg-error "cannot" }
+ f1(); // { dg-error "cannot call" }
+ f2(); // { dg-error "cannot call" }
+ f3(); // { dg-error "cannot call" }
+ f4(); // { dg-error "cannot call" }
+ f5(); // { dg-error "cannot call" }
+ f6(); // { dg-error "cannot call" }
+ f7(); // { dg-error "cannot call" }
+ f8(); // { dg-error "cannot call" }
+ f9(); // { dg-error "cannot call" }
+ f10(); // { dg-error "cannot call" }
+ f11(); // { dg-error "cannot call" }
+ f12(); // { dg-error "cannot call" }
+ f13(); // { dg-error "cannot call" }
+ f14(); // { dg-error "cannot call" }
+ f15(); // { dg-error "cannot call" }
+ f16(); // { dg-error "cannot call" }
+ f17(); // { dg-error "cannot call" }
}
Index: gcc/testsuite/g++.dg/concepts/req1.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/req1.C (revision 0)
+++ gcc/testsuite/g++.dg/concepts/req1.C (revision 0)
@@ -0,0 +1,15 @@
+// { dg-do run }
+// { dg-options "-std=c++1z" }
+
+template<typename T>
+ concept bool Class () { return __is_class(T); }
+
+void f1(auto a) requires Class<decltype(a)>() { }
+void f2(auto a) requires requires (decltype(a) x) { -x; } { }
+
+struct S { } s;
+
+int main() {
+ f1(s);
+ f2(0);
+}
Index: gcc/testsuite/g++.dg/concepts/req2.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/req2.C (revision 0)
+++ gcc/testsuite/g++.dg/concepts/req2.C (revision 0)
@@ -0,0 +1,21 @@
+// { dg-options "-std=c++1z" }
+
+#include <cassert>
+
+template<typename T>
+ concept bool Class () { return __is_class(T); }
+
+void f1 (auto a) requires Class<decltype(a)>() { }
+
+ // FIXME: This is generating excess errors related to pretty
+ // printing the trailing requires expression.
+void f2(auto a)
+ requires requires (decltype(a) x) { -x; }
+{ }
+
+struct S { } s;
+
+int main() {
+ f1(0); // { dg-error "matching" }
+ f2((void*)0); // { dg-error "matching" }
+}
Index: gcc/testsuite/g++.dg/concepts/req3.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/req3.C (revision 0)
+++ gcc/testsuite/g++.dg/concepts/req3.C (revision 0)
@@ -0,0 +1,18 @@
+// { dg-do run }
+// { dg-options "-std=c++1z" }
+
+template<typename T>
+ concept bool Class () { return __is_class(T); }
+
+struct Test {
+ void f(auto a) requires Class<decltype(a)>();
+} test;
+
+struct S { }s;
+
+int main() {
+ test.f(s);
+}
+
+void Test::f(auto a) requires Class<decltype(a)>() { }
+
Index: gcc/testsuite/g++.dg/concepts/test.C
===================================================================
--- gcc/testsuite/g++.dg/concepts/test.C (revision 212100)
+++ gcc/testsuite/g++.dg/concepts/test.C (working copy)
@@ -1,17 +0,0 @@
-// { dg-options "-I/home/faculty/asutton/Code/origin -std=c++1z" }
-
-#include <algorithm>
-
-// #include <origin/range/stream.hpp>
-
-// int main() {
-// std::string s = "1 2 3 4 5";
-// std::istringstream ss(s);
-// auto is = origin::make_istream<int>(ss);
-
-// for(int x : is) {
-// std::cout << x << '\n';
-// }
-
-// static_assert(not origin::Range<decltype(is)>(), "");
-// }
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c (revision 212456)
+++ gcc/cp/parser.c (working copy)
@@ -16982,14 +16982,22 @@ struct cp_manage_requirements {
static tree
cp_parser_trailing_requirements (cp_parser *parser, cp_declarator *decl)
{
- // A function declaration may have a trailing requires-clause.
if (function_declarator_p (decl))
- if (tree reqs = cp_parser_requires_clause_opt (parser))
- current_template_reqs = save_trailing_requirements (reqs);
+ {
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_REQUIRES))
+ {
+ ++cp_unevaluated_operand;
+ push_function_parms (decl);
+ cp_lexer_consume_token (parser->lexer);
+ tree reqs = cp_parser_requires_clause (parser);
+ current_template_reqs = save_trailing_requirements (reqs);
+ finish_scope();
+ --cp_unevaluated_operand;
+ }
+ }
return current_template_reqs;
}
-
/* Declarators [gram.dcl.decl] */
/* Parse an init-declarator.
Index: gcc/cp/decl.c
===================================================================
--- gcc/cp/decl.c (revision 212456)
+++ gcc/cp/decl.c (working copy)
@@ -13864,6 +13864,30 @@ store_parm_decls (tree current_function_
current_eh_spec_block = begin_eh_spec_block ();
}
+// Bring the parameters of a function declaration back into
+// scope without entering the function body. The declarator
+// must be a function declarator. The caller is responsible
+// for calling finish_scope.
+void
+push_function_parms (cp_declarator *declarator)
+{
+ // Find the actual function declarator.
+ while (declarator)
+ {
+ if (declarator->kind == cdk_function)
+ break;
+ declarator = declarator->declarator;
+ }
+
+ begin_scope (sk_function_parms, NULL_TREE);
+ tree p = declarator->u.function.parameters;
+ while (p != NULL_TREE && !VOID_TYPE_P (TREE_VALUE (p)))
+ {
+ pushdecl (TREE_VALUE (p));
+ p = TREE_CHAIN (p);
+ }
+}
+
/* We have finished doing semantic analysis on DECL, but have not yet
generated RTL for its body. Save away our current state, so that
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h (revision 213130)
+++ gcc/cp/cp-tree.h (working copy)
@@ -5432,6 +5432,7 @@ extern bool defer_mark_used_calls;
extern GTY(()) vec<tree, va_gc> *deferred_mark_used_calls;
extern tree finish_case_label (location_t, tree, tree);
extern tree cxx_maybe_build_cleanup (tree, tsubst_flags_t);
+extern void push_function_parms (cp_declarator *);
/* in decl2.c */
extern bool check_java_method (tree);