On 7/21/25 6:28 PM, Marek Polacek wrote:
On Mon, Jul 21, 2025 at 11:26:08AM -0400, Jason Merrill wrote:
On 7/18/25 5:11 PM, Marek Polacek wrote:
On Thu, Jul 17, 2025 at 06:44:08PM -0400, Jason Merrill wrote:
On 7/17/25 6:25 PM, Jakub Jelinek wrote:
On Thu, Jul 17, 2025 at 05:31:27PM -0400, Jason Merrill wrote:
On 7/16/25 10:49 AM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This patch implements consteval blocks, as specified by P2996.
They aren't very useful without define_aggregate, but having
a reviewed implementation on trunk would be great.

consteval {} can be anywhere where a member-declaration or
block-declaration can be.  The expression corresponding to it is:

      [] -> void static consteval compound-statement ()

and it must be a constant expression.

I've used cp_parser_lambda_expression to take care of most of the
parsing.  Since a consteval block can find itself in a template, we
need a vehicle to carry the block for instantiation.  Rather than
inventing a new tree, I'm using STMT_EXPR.

If we need something to trigger immediate evaluation, why not a
STATIC_ASSERT as the proposal suggests?

I thought a STMT_EXPR might be a more appropriate means due to static_assert's
true/false nature.  But using a STATIC_ASSERT does simplify the code, so
I've made that change.

Isn't it a problem that static_assert constant evaluates it multiple times
(at least when it isn't constant)?

Hmm, perhaps, for stateful evaluation like define_aggregate.  But we could
address that with a flag on the STATIC_ASSERT like this patch puts on the
STMT_EXPR.

Thanks.  What do you think about this?  I didn't have to change the
tests at all.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This patch implements consteval blocks, as specified by P2996.
They aren't very useful without define_aggregate, but having
a reviewed implementation on trunk would be great.

consteval {} can be anywhere where a member-declaration or
block-declaration can be.  The expression corresponding to it is:

    [] -> void static consteval compound-statement ()

and it must be a constant expression.

I've used cp_parser_lambda_expression to take care of most of the
parsing.  Since a consteval block can find itself in a template, we
need a vehicle to carry the block for instantiation.  Rather than
inventing a new tree, I'm using STATIC_ASSERT.

A consteval block can't return a value but that is checked by virtue
of the lambda having a void return type.

        PR c++/120775

+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block1.C
...
+/* __func__ won't be set.  Make sure we don't crash.  */
+consteval { __func__; }
+struct F {
+  consteval { __func__; }
+};
+template<typename>
+struct TF {
+  consteval { __func__; }
+};

If it isn't set (per
https://eel.is/c++draft/expr.prim.lambda.closure#16), we should get the
usual "not defined outside function scope" diagnostic.

Ah right.  But then I need another flag (LAMBDA_EXPR_CONSTEVAL_BLOCK_P)
because I can have a consteval block in a lambda and a lambda in
a consteval block etc.  But I guess I will need such a flag anyway
for Reflection later.  That should be OK because LAMBDA_EXPR flags
aren't that scarce (and we have tree_lambda_expr too).

Agreed, but...

  tree
  finish_fname (tree id)
  {
-  tree decl;
-
-  decl = fname_decl (input_location, C_RID_CODE (id), id);
+  tree decl = fname_decl (input_location, C_RID_CODE (id), id);
+  /* [expr.prim.lambda.closure]/16 "Unless the compound-statement is that
+     of a consteval-block-declaration, a variable __func__ is implicitly
+     defined...".  */
+  if (in_consteval_block_p ())
+    pedwarn (input_location, 0, "%qD is not defined outside of function scope",
+            decl);

Rather than this I think we want cp_make_fname_decl to look through consteval block lambdas (with a variant of current_nonlambda_function that only skips consteval block lambdas?), so...

diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block8.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block8.C
new file mode 100644
index 00000000000..7695338b367
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block8.C
@@ -0,0 +1,38 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+
+/* __func__ won't be set.  Make sure we warn.  */
+consteval { __func__; }          // { dg-error "outside of function scope" }
+consteval { { __func__; } }      // { dg-error "outside of function scope" }
+consteval { []() mutable consteval -> void { __func__; } (); }      // { dg-bogus 
"outside of function scope" }
+consteval { []() mutable consteval -> void { consteval { __func__; } } (); } // { 
dg-error "outside of function scope" }

...this should work, lookup should find the __func__ for the normal lambda. And similarly for several of the other examples in the testcase.

Jason

Reply via email to