aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/lambda.cc8
-rw-r--r--gcc/cp/parser.cc35
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/lambda-requires2.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/lambda-requires3.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/lambda-requires4.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/lambda-requires5.C10
6 files changed, 61 insertions, 12 deletions
diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index ed70bb0..f0a54b6 100644
--- a/gcc/cp/lambda.cc
+++ b/gcc/cp/lambda.cc
@@ -59,7 +59,13 @@ build_lambda_object (tree lambda_expr)
vec<constructor_elt, va_gc> *elts = NULL;
tree node, expr, type;
- if (processing_template_decl || lambda_expr == error_mark_node)
+ if (processing_template_decl && !in_template_context
+ && current_binding_level->requires_expression)
+ /* As in cp_parser_lambda_expression, don't get confused by
+ cp_parser_requires_expression setting processing_template_decl. In that
+ case we want to return the result of finish_compound_literal, to avoid
+ tsubst_lambda_expr. */;
+ else if (processing_template_decl || lambda_expr == error_mark_node)
return lambda_expr;
/* Make sure any error messages refer to the lambda-introducer. */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 53e6237..812a7c5 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -11736,21 +11736,34 @@ cp_parser_lambda_expression (cp_parser* parser)
if (cp_parser_error_occurred (parser))
return error_mark_node;
- type = begin_lambda_type (lambda_expr);
- if (type == error_mark_node)
- return error_mark_node;
+ {
+ /* OK, this is a bit tricksy. cp_parser_requires_expression sets
+ processing_template_decl to make checking more normal, but that confuses
+ lambda parsing terribly. In non-template context, we want to parse the
+ lambda once and not tsubst_lambda_expr. So in that case, clear
+ processing_template_decl now, and restore it before the call to
+ build_lambda_object; that way we end up with what looks like a templatey
+ functional cast to the closure type, which is suitable for the
+ requires-expression tsubst_expr. This is PR99546 and friends. */
+ processing_template_decl_sentinel ptds (/*reset*/false);
+ if (processing_template_decl && !in_template_context
+ && current_binding_level->requires_expression)
+ processing_template_decl = 0;
+
+ type = begin_lambda_type (lambda_expr);
+ if (type == error_mark_node)
+ return error_mark_node;
- record_lambda_scope (lambda_expr);
- record_lambda_scope_discriminator (lambda_expr);
+ record_lambda_scope (lambda_expr);
+ record_lambda_scope_discriminator (lambda_expr);
- /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
- determine_visibility (TYPE_NAME (type));
+ /* Do this again now that LAMBDA_EXPR_EXTRA_SCOPE is set. */
+ determine_visibility (TYPE_NAME (type));
- /* Now that we've started the type, add the capture fields for any
- explicit captures. */
- register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr));
+ /* Now that we've started the type, add the capture fields for any
+ explicit captures. */
+ register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr));
- {
/* Inside the class, surrounding template-parameter-lists do not apply. */
unsigned int saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-requires2.C b/gcc/testsuite/g++.dg/cpp2a/lambda-requires2.C
new file mode 100644
index 0000000..be5a71a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-requires2.C
@@ -0,0 +1,8 @@
+// PR c++/99546
+// { dg-do compile { target c++20 } }
+
+int main() {
+ constexpr auto b = requires { []{}; };
+ static_assert(b);
+ static_assert(!b); // { dg-error "assertion failed" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-requires3.C b/gcc/testsuite/g++.dg/cpp2a/lambda-requires3.C
new file mode 100644
index 0000000..8c4ef06
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-requires3.C
@@ -0,0 +1,6 @@
+// PR c++/113925
+// { dg-do compile { target c++20 } }
+
+template<bool B>
+struct b{};
+static_assert(requires { b<([]()consteval{ return true; }())>{}; });
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-requires4.C b/gcc/testsuite/g++.dg/cpp2a/lambda-requires4.C
new file mode 100644
index 0000000..f3bb041
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-requires4.C
@@ -0,0 +1,6 @@
+// PR c++/106976
+// { dg-do compile { target c++20 } }
+
+struct S{
+ constexpr static auto s = requires { []; }; // { dg-error "expected '\{'" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-requires5.C b/gcc/testsuite/g++.dg/cpp2a/lambda-requires5.C
new file mode 100644
index 0000000..c818313
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-requires5.C
@@ -0,0 +1,10 @@
+// PR c++/109961
+// { dg-do compile { target c++20 } }
+
+auto a = requires{
+ []( int b ) consteval {
+ if( b ) {
+ throw b;
+ }
+ }( 0 );
+};