lambda-declarator:
< template-parameter-list [opt] >
+ requires-clause [opt]
( parameter-declaration-clause [opt] )
attribute-specifier [opt]
decl-specifier-seq [opt]
exception-specification [opt]
lambda-return-type-clause [opt]
+ requires-clause [opt]
LAMBDA_EXPR is the current representation of the lambda expression. */
tree template_param_list = NULL_TREE;
tree tx_qual = NULL_TREE;
tree return_type = NULL_TREE;
+ tree trailing_requires_clause = NULL_TREE;
cp_decl_specifier_seq lambda_specs;
clear_decl_specs (&lambda_specs);
cp_lexer_consume_token (parser->lexer);
template_param_list = cp_parser_template_parameter_list (parser);
-
cp_parser_skip_to_end_of_template_parameter_list (parser);
+ /* We may have a constrained generic lambda; parse the requires-clause
+ immediately after the template-parameter-list and combine with any
+ shorthand constraints present. */
+ tree dreqs = cp_parser_requires_clause_opt (parser);
+ if (flag_concepts)
+ {
+ tree reqs = get_shorthand_constraints (current_template_parms);
+ if (dreqs)
+ reqs = combine_constraint_expressions (reqs, dreqs);
+ TEMPLATE_PARMS_CONSTRAINTS (current_template_parms) = reqs;
+ }
+
/* We just processed one more parameter list. */
++parser->num_template_parameter_lists;
}
if (cp_next_tokens_can_be_gnu_attribute_p (parser))
gnu_attrs = cp_parser_gnu_attributes_opt (parser);
+ /* Parse optional trailing requires clause. */
+ trailing_requires_clause = cp_parser_requires_clause_opt (parser);
+
/* The function parameters must be in scope all the way until after the
trailing-return-type in case of decltype. */
pop_bindings_and_leave_scope ();
tx_qual,
exception_spec,
return_type,
- /*requires_clause*/NULL_TREE);
+ trailing_requires_clause);
declarator->std_attributes = std_attrs;
fco = grokmethod (&return_type_specs,
--- /dev/null
+// { dg-do compile { target c++2a } }
+
+template<typename T>
+concept False = false;
+
+template<typename T>
+concept C1 = __is_same_as(T, int)
+ || __is_same_as(T, long long)
+ || __is_same_as(T, char);
+
+template<typename T>
+concept IsNotLarge = !__is_same_as(T, long long);
+
+template<typename T>
+concept IsNotTiny = !__is_same_as(T, char);
+
+template<IsNotLarge T>
+struct Foo
+{
+ static constexpr auto a = [](auto n) { return n; };
+ template<IsNotTiny S>
+ auto b()
+ {
+ return [](False auto n) { return n; };
+ }
+};
+
+template<IsNotTiny T>
+struct Bar
+{
+ static constexpr auto a =
+ []<IsNotTiny R>(R t) { return t; }('a'); // { dg-error "no match" }
+ char b =
+ []<IsNotTiny R>(R t) { return t; }('b'); // { dg-error "no match" }
+
+ static constexpr auto a2 =
+ [](char t) requires false { return t; }('a'); // { dg-error "no match" }
+ char b2 =
+ [](char t) requires false { return t; }('b'); // { dg-error "no match" }
+};
+
+template<IsNotLarge S>
+S c =
+ []<IsNotTiny R>(R t) { return t; }('c'); // { dg-error "no match" }
+template<IsNotLarge S>
+S c2 =
+ [](char t) requires false { return t; }('c'); // { dg-error "no match" }
+
+Bar<long long> bar;
+
+void test0()
+{
+ auto bar_a = bar.a;
+ auto bar_b = bar.b;
+ auto c = ::c<char>;
+ auto bar_a2 = bar.a2;
+ auto bar_b2 = bar.b2;
+ auto c2 = ::c2<char>;
+
+ 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 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; };
+ g0(0); // { dg-error "no match" }
+ g1(0); // { dg-error "no match" }
+ g2(0); // { dg-error "no match" }
+ g3(0); // { dg-error "no match" }
+ g4(0); // { dg-error "no match" }
+ g5(0); // { dg-error "no match" }
+ g6(0); // { dg-error "no match" }
+ g7(0); // { dg-error "no match" }
+}
+
+void test1()
+{
+ int var{-1};
+ 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 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; };
+ g0(0); // { dg-error "no match" }
+ g1(0); // { dg-error "no match" }
+ g2(0); // { dg-error "no match" }
+ g3(0); // { dg-error "no match" }
+ g4(0); // { dg-error "no match" }
+ g5(0); // { dg-error "no match" }
+ g6(0); // { dg-error "no match" }
+ g7(0); // { dg-error "no match" }
+}
+
+void test2()
+{
+ auto x = []<IsNotTiny T>(auto a, T t, auto b)
+ requires IsNotTiny<decltype(a)> && IsNotLarge<decltype(b)>
+ { return a + t + (T)b; };
+ x(5LL, 2LL, 1);
+
+ x('0', 2LL, 1LL); // { dg-error "no match" }
+ x(5LL, '0', 1LL); // { dg-error "no match" }
+ x(5LL, 2LL, 1LL); // { dg-error "no match" }
+}
+
+void test3()
+{
+ auto x = []<IsNotTiny T>(IsNotTiny auto a, T t, IsNotLarge auto b)
+ { return a + t + (T)b; };
+ x(5LL, 2LL, 1);
+
+ x('0', 2LL, 1LL); // { dg-error "no match" }
+ x(5LL, '0', 1LL); // { dg-error "no match" }
+ x(5LL, 2LL, 1LL); // { dg-error "no match" }
+}
+
+void test4()
+{
+ auto g = []<C1 T> requires IsNotTiny<T>(T t) -> T
+ requires IsNotLarge<decltype(t)> { return t; };
+ g(5.5); // { dg-error "no match" }
+ g('a'); // { dg-error "no match" }
+ g(1LL); // { dg-error "no match" }
+}
+
+void test5()
+{
+ Foo<int> foo1;
+ foo1.a(5.5);
+ foo1.a(1LL);
+ foo1.b<char>(); // { dg-error "no match" }
+ foo1.b<long long>()(5); // { dg-error "no match" }
+
+ Foo<double> foo2;
+ foo2.a(5.5);
+ foo2.a(1LL);
+ foo2.b<char>(); // { dg-error "no match" }
+ foo2.b<long long>()(5); // { dg-error "no match" }
+}
+
+using Func = int(*)(int);
+
+void test6()
+{
+ Func f1 = [](int a) requires false { return a; }; // { dg-error "cannot convert" }
+ Func f2 = [](auto a) requires false { return a; }; // { dg-error "cannot convert" }
+}
+
--- /dev/null
+// { dg-do run { target c++2a } }
+
+template<typename T>
+concept C1 = __is_same_as(T, int)
+ || __is_same_as(T, long long)
+ || __is_same_as(T, char);
+
+template<typename T>
+concept IsNotLarge = !__is_same_as(T, long long);
+
+template<typename T>
+concept IsNotTiny = !__is_same_as(T, char);
+
+template<IsNotLarge T>
+struct Foo
+{
+ static constexpr auto a = [](auto n) { return n; };
+ template<IsNotTiny S>
+ auto b()
+ {
+ return [](auto n) { return n; };
+ }
+};
+
+using Func = int(*)(int);
+
+int main(int, char**)
+{
+ auto g = []<C1 T> requires IsNotTiny<T>(T t) -> T
+ requires IsNotLarge<decltype(t)> { return t; };
+ g(5);
+ g.operator()<int>(5.5);
+
+ 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);
+ [](C1 auto t) { return t; }(5);
+
+ auto a0 = [](IsNotLarge auto a) { return [](auto b){ return b; }; };
+ auto a1 = a0(1);
+ auto a2 = a1(5LL);
+
+ auto b0 = [](auto a) { return [](IsNotLarge auto b){ return b; }; };
+ auto b1 = b0(5LL);
+ auto b2 = b1(1);
+
+ Foo<int> foo1;
+ foo1.a(5.5);
+ foo1.a(1LL);
+ foo1.b<int>()(5);
+ foo1.b<long long>()(5);
+
+ Foo<double> foo2;
+ foo2.a(5.5);
+ foo2.a(1LL);
+ foo2.b<int>()(5);
+ foo2.b<long long>()(5);
+
+ Func m1 = [](int a) -> int requires true { return a; };
+
+ return 0;
+}
+