Applied an updated version of this patch. 2014-7-30 Braden Obrzut <ad...@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.sut...@gmail.com> * gcc/testsuite/g++.dg/concepts/test.C: Removed. Andrew Sutton On Tue, Jun 17, 2014 at 5:06 AM, Braden Obrzut <ad...@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 <ad...@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);