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

gcc/cp/ChangeLog:

        * cp-tree.h (CONSTEVAL_BLOCK_P): Define.
        (finish_static_assert): Adjust declaration.
        * parser.cc (cp_parser_lambda_expression): New parameter for
        consteval blocks.  Use it.
        (cp_parser_lambda_declarator_opt): Likewise.
        (build_empty_string): New.
        (cp_parser_next_tokens_are_consteval_block_p): New.
        (cp_parser_consteval_block): New.
        (cp_parser_block_declaration): Handle consteval blocks.
        (cp_parser_static_assert): Use build_empty_string.
        (cp_parser_member_declaration): Handle consteval blocks.
        * pt.cc (tsubst_stmt): Adjust a call to finish_static_assert.
        * semantics.cc (finish_static_assert): New parameter for consteval
        blocks.  Set CONSTEVAL_BLOCK_P.  Evaluate consteval blocks specially.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp26/consteval-block1.C: New test.
        * g++.dg/cpp26/consteval-block2.C: New test.
        * g++.dg/cpp26/consteval-block3.C: New test.
        * g++.dg/cpp26/consteval-block4.C: New test.
        * g++.dg/cpp26/consteval-block5.C: New test.
        * g++.dg/cpp26/consteval-block6.C: New test.
        * g++.dg/cpp26/consteval-block7.C: New test.
---
  gcc/cp/cp-tree.h                              |   7 +-
  gcc/cp/parser.cc                              | 134 ++++++++++++++----
  gcc/cp/pt.cc                                  |   3 +-
  gcc/cp/semantics.cc                           |  16 ++-
  gcc/testsuite/g++.dg/cpp26/consteval-block1.C |  92 ++++++++++++
  gcc/testsuite/g++.dg/cpp26/consteval-block2.C |  49 +++++++
  gcc/testsuite/g++.dg/cpp26/consteval-block3.C |  41 ++++++
  gcc/testsuite/g++.dg/cpp26/consteval-block4.C |  41 ++++++
  gcc/testsuite/g++.dg/cpp26/consteval-block5.C |  70 +++++++++
  gcc/testsuite/g++.dg/cpp26/consteval-block6.C | 108 ++++++++++++++
  gcc/testsuite/g++.dg/cpp26/consteval-block7.C |  12 ++
  11 files changed, 543 insertions(+), 30 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/cpp26/consteval-block1.C
  create mode 100644 gcc/testsuite/g++.dg/cpp26/consteval-block2.C
  create mode 100644 gcc/testsuite/g++.dg/cpp26/consteval-block3.C
  create mode 100644 gcc/testsuite/g++.dg/cpp26/consteval-block4.C
  create mode 100644 gcc/testsuite/g++.dg/cpp26/consteval-block5.C
  create mode 100644 gcc/testsuite/g++.dg/cpp26/consteval-block6.C
  create mode 100644 gcc/testsuite/g++.dg/cpp26/consteval-block7.C

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 68102501569..a365237a769 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -453,6 +453,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
        RETURN_EXPR_LOCAL_ADDR_P (in RETURN_EXPR)
        PACK_INDEX_PARENTHESIZED_P (in PACK_INDEX_*)
        MUST_NOT_THROW_NOEXCEPT_P (in MUST_NOT_THROW_EXPR)
+      CONSTEVAL_BLOCK_P (in STATIC_ASSERT)

This is in the _0 block...

     1: IDENTIFIER_KIND_BIT_1 (in IDENTIFIER_NODE)
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
@@ -1433,6 +1434,10 @@ struct GTY (()) tree_deferred_noexcept {
  #define STATIC_ASSERT_SOURCE_LOCATION(NODE) \
    (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->location)
+/* True if this static assert represents a C++26 consteval block. */
+#define CONSTEVAL_BLOCK_P(NODE) \
+  TREE_LANG_FLAG_1 (STATIC_ASSERT_CHECK (NODE))

...and then this uses _1.  Please change one or the other.

+++ 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.

Jason

Reply via email to