Tested x86_64-pc-linux-gnu, applying to trunk.

-- 8< --

Since r10-7441 we set processing_template_decl in a requires-expression so
that we can use tsubst_expr to evaluate the requirements, but that confuses
lambdas terribly; begin_lambda_type silently returns error_mark_node and we
continue into other failures.  This patch clears processing_template_decl
again while we're defining the closure and op() function, so it only remains
set while parsing the introducer (i.e. any init-captures) and building the
resulting object.  This properly avoids trying to create another lambda in
tsubst_lambda_expr.

        PR c++/99546
        PR c++/113925
        PR c++/106976
        PR c++/109961
        PR c++/117336

gcc/cp/ChangeLog:

        * lambda.cc (build_lambda_object): Handle fake
        requires-expr processing_template_decl.
        * parser.cc (cp_parser_lambda_expression): Likewise.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/lambda-requires2.C: New test.
        * g++.dg/cpp2a/lambda-requires3.C: New test.
        * g++.dg/cpp2a/lambda-requires4.C: New test.
        * g++.dg/cpp2a/lambda-requires5.C: New test.
---
 gcc/cp/lambda.cc                              |  8 +++-
 gcc/cp/parser.cc                              | 41 ++++++++++++-------
 gcc/testsuite/g++.dg/cpp2a/lambda-requires2.C |  8 ++++
 gcc/testsuite/g++.dg/cpp2a/lambda-requires3.C |  6 +++
 gcc/testsuite/g++.dg/cpp2a/lambda-requires4.C |  6 +++
 gcc/testsuite/g++.dg/cpp2a/lambda-requires5.C | 10 +++++
 6 files changed, 64 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-requires2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-requires3.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-requires4.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-requires5.C

diff --git a/gcc/cp/lambda.cc b/gcc/cp/lambda.cc
index ed70bb0ba8e..f0a54b60275 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 53e6237f6c4..812a7c5ae7d 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;
-
-  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));
-
-  /* Now that we've started the type, add the capture fields for any
-     explicit captures.  */
-  register_capture_members (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr));
-
   {
+    /* 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);
+
+    /* 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));
+
     /* 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 00000000000..be5a71abefe
--- /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 00000000000..8c4ef064e52
--- /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 00000000000..f3bb041310c
--- /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 00000000000..c81831381e3
--- /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 );
+};

base-commit: 2a36d22ab52d6ffce9a1fcaf7aca83336679e111
-- 
2.49.0

Reply via email to