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.

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:

        * class.cc (maybe_add_class_template_decl_list): Update comment.
        * cp-tree.h (CONSTEVAL_BLOCK_P): Define.
        (evaluate_consteval_block): Declare.
        * parser.cc (cp_parser_lambda_expression): New parameter for
        consteval blocks.  Use it.
        (cp_parser_lambda_declarator_opt): Likewise.
        (cp_parser_consteval_block): New.
        (cp_parser_block_declaration): Handle consteval blocks.
        (cp_parser_member_declaration): Likewise.
        * pt.cc (instantiate_class_template): tsubst_expr consteval blocks.
        (evaluate_consteval_block): New.
        (tsubst_expr) <case STMT_EXPR>: Evaluate consteval blocks.

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/class.cc                               |   3 +-
 gcc/cp/cp-tree.h                              |   6 +
 gcc/cp/parser.cc                              | 124 ++++++++++++++----
 gcc/cp/pt.cc                                  |  31 +++++
 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, 553 insertions(+), 24 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/class.cc b/gcc/cp/class.cc
index f5d20e5c539..63207b6ba8a 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -3403,7 +3403,8 @@ finish_struct_anon (tree t)
    a typedef (TYPE_DECL) or a member class template (TEMPLATE_DECL)
    When FRIEND_P is nonzero, T is either a friend class
    (RECORD_TYPE, TEMPLATE_DECL) or a friend function
-   (FUNCTION_DECL, TEMPLATE_DECL).  */
+   (FUNCTION_DECL, TEMPLATE_DECL).  This function also adds other
+   entities, such as STATIC_ASSERT or STMT_EXPR.  */
 
 void
 maybe_add_class_template_decl_list (tree type, tree t, int friend_p)
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 68102501569..52629d1aeb5 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -474,6 +474,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
       ATOMIC_CONSTR_EXPR_FROM_CONCEPT_P (in ATOMIC_CONSTR)
       STATIC_INIT_DECOMP_BASE_P (in the TREE_LIST for {static,tls}_aggregates)
       MUST_NOT_THROW_THROW_P (in MUST_NOT_THROW_EXPR)
+      CONSTEVAL_BLOCK_P (in STMT_EXPR)
    2: IDENTIFIER_KIND_BIT_2 (in IDENTIFIER_NODE)
       ICS_THIS_FLAG (in _CONV)
       DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
@@ -767,6 +768,10 @@ typedef struct ptrmem_cst * ptrmem_cst_t;
 #define STMT_EXPR_NO_SCOPE(NODE) \
    TREE_LANG_FLAG_0 (STMT_EXPR_CHECK (NODE))
 
+/* True if this statement-expression represents a C++26 consteval block.  */
+#define CONSTEVAL_BLOCK_P(NODE) \
+  TREE_LANG_FLAG_1 (STMT_EXPR_CHECK (NODE))
+
 #define COND_EXPR_IS_VEC_DELETE(NODE) \
   TREE_LANG_FLAG_0 (COND_EXPR_CHECK (NODE))
 
@@ -7962,6 +7967,7 @@ extern tree add_to_template_args          (tree, tree);
 extern tree add_outermost_template_args                (tree, tree);
 extern tree add_extra_args                     (tree, tree, tsubst_flags_t, 
tree);
 extern tree build_extra_args                   (tree, tree, tsubst_flags_t);
+extern void evaluate_consteval_block           (tree);
 
 /* in rtti.cc */
 /* A vector of all tinfo decls that haven't been emitted yet.  */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 0d9ed2ea82b..569ed939093 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -2576,11 +2576,11 @@ static cp_expr cp_parser_constant_expression
 static cp_expr cp_parser_builtin_offsetof
   (cp_parser *);
 static cp_expr cp_parser_lambda_expression
-  (cp_parser *);
+  (cp_parser *, bool = false);
 static void cp_parser_lambda_introducer
   (cp_parser *, tree);
 static bool cp_parser_lambda_declarator_opt
-  (cp_parser *, tree);
+  (cp_parser *, tree, bool = false);
 static void cp_parser_lambda_body
   (cp_parser *, tree);
 
@@ -11739,10 +11739,14 @@ cp_parser_trait (cp_parser* parser, const cp_trait* 
trait)
      lambda-introducer < template-parameter-list > requires-clause [opt]
        lambda-declarator [opt] compound-statement
 
+   If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+   is syntactic sugar for a consteval lambda.
+
    Returns a representation of the expression.  */
 
 static cp_expr
-cp_parser_lambda_expression (cp_parser* parser)
+cp_parser_lambda_expression (cp_parser* parser,
+                            bool consteval_block_p/*=false*/)
 {
   tree lambda_expr = build_lambda_expr ();
   tree type;
@@ -11794,9 +11798,12 @@ cp_parser_lambda_expression (cp_parser* parser)
      it now.  */
   push_deferring_access_checks (dk_no_deferred);
 
-  cp_parser_lambda_introducer (parser, lambda_expr);
-  if (cp_parser_error_occurred (parser))
-    return error_mark_node;
+  if (!consteval_block_p)
+    {
+      cp_parser_lambda_introducer (parser, lambda_expr);
+      if (cp_parser_error_occurred (parser))
+       return error_mark_node;
+    }
 
   {
     /* OK, this is a bit tricksy.  cp_parser_requires_expression sets
@@ -11868,7 +11875,8 @@ cp_parser_lambda_expression (cp_parser* parser)
     if (cp_parser_start_tentative_firewall (parser))
       start = token;
 
-    ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr);
+    ok &= cp_parser_lambda_declarator_opt (parser, lambda_expr,
+                                          consteval_block_p);
 
     if (ok && cp_parser_error_occurred (parser))
       ok = false;
@@ -12251,10 +12259,13 @@ cp_parser_lambda_introducer (cp_parser* parser, tree 
lambda_expr)
      decl-specifier-seq [opt] noexcept-specifier [opt]
        attribute-specifier-seq [opt] trailing-return-type [opt]
 
-   LAMBDA_EXPR is the current representation of the lambda expression.  */
+   LAMBDA_EXPR is the current representation of the lambda expression.
+   If CONSTEVAL_BLOCK_P is true, we are parsing a consteval block, which
+   is syntactic sugar for a consteval lambda.  */
 
 static bool
-cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr)
+cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr,
+                                bool consteval_block_p/*=false*/)
 {
   /* 5.1.1.4 of the standard says:
        If a lambda-expression does not include a lambda-declarator, it is as if
@@ -12357,6 +12368,18 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, 
tree lambda_expr)
                                  CP_PARSER_FLAGS_ONLY_MUTABLE_OR_CONSTEXPR,
                                  &lambda_specs, &declares_class_or_enum);
 
+  /* [dcl.pre] For a consteval-block-declaration D, the expression E
+     corresponding to D is:
+       [] -> void static consteval compound-statement ()
+     Make it so.  */
+  if (consteval_block_p)
+    {
+      return_type = void_type_node;
+      lambda_specs.storage_class = sc_static;
+      set_and_check_decl_spec_loc (&lambda_specs, ds_consteval,
+                                  cp_lexer_peek_token (parser->lexer));
+    }
+
   if (omitted_parms_loc && lambda_specs.any_specifiers_p)
     {
       pedwarn (omitted_parms_loc, OPT_Wc__23_extensions,
@@ -16294,6 +16317,46 @@ cp_parser_toplevel_declaration (cp_parser* parser)
     cp_parser_declaration (parser, NULL_TREE);
 }
 
+/* Parse a consteval-block-declaration.
+
+   consteval-block-declaration:
+     consteval compound-statement
+
+   If MEMBER_P, this consteval block is a member declaration.  */
+
+static void
+cp_parser_consteval_block (cp_parser *parser, bool member_p)
+{
+  /* Consume the 'consteval'.  */
+  cp_lexer_consume_token (parser->lexer);
+
+  /* We know the next token is '{'.  Let cp_parser_lambda_body handle it.  */
+  cp_expr lam = cp_parser_lambda_expression (parser,
+                                            /*consteval_block_p=*/true);
+  if (!cp_parser_error_occurred (parser))
+    {
+      releasing_vec args;
+      tree call = finish_call_expr (lam, &args,
+                                   /*disallow_virtual=*/false,
+                                   /*koenig_p=*/false,
+                                   tf_warning_or_error);
+      if (!instantiation_dependent_expression_p (call))
+       evaluate_consteval_block (call);
+      else
+       {
+         tree expr = begin_stmt_expr ();
+         expr = finish_stmt_expr_expr (call, expr);
+         expr = finish_stmt_expr (expr, false);
+         CONSTEVAL_BLOCK_P (expr) = true;
+         if (member_p)
+           maybe_add_class_template_decl_list (current_class_type, expr,
+                                               /*friend_p=*/0);
+         else
+           add_stmt (expr);
+       }
+    }
+}
+
 /* Parse a block-declaration.
 
    block-declaration:
@@ -16301,18 +16364,18 @@ cp_parser_toplevel_declaration (cp_parser* parser)
      asm-definition
      namespace-alias-definition
      using-declaration
+     using-enum-declaration
      using-directive
+     static_assert-declaration
+     consteval-block-declaration
+     alias-declaration
+     opaque-enum-declaration
 
    GNU Extension:
 
    block-declaration:
      __extension__ block-declaration
 
-   C++0x Extension:
-
-   block-declaration:
-     static_assert-declaration
-
    If STATEMENT_P is TRUE, then this block-declaration is occurring as
    part of a declaration-statement.  */
 
@@ -16389,6 +16452,10 @@ cp_parser_block_declaration (cp_parser *parser,
   /* If the next token is `static_assert' we have a static assertion.  */
   else if (token1->keyword == RID_STATIC_ASSERT)
     cp_parser_static_assert (parser, /*member_p=*/false);
+  else if (cxx_dialect >= cxx26
+          && token1->keyword == RID_CONSTEVAL
+          && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE))
+    cp_parser_consteval_block (parser, /*member_p=*/false);
   else
     {
       size_t attr_idx = cp_parser_skip_std_attribute_spec_seq (parser, 1);
@@ -28824,12 +28891,20 @@ cp_parser_member_specification_opt (cp_parser* parser)
 /* Parse a member-declaration.
 
    member-declaration:
-     decl-specifier-seq [opt] member-declarator-list [opt] ;
-     function-definition ; [opt]
-     :: [opt] nested-name-specifier template [opt] unqualified-id ;
+     attribute-specifier-seq [opt] decl-specifier-seq [opt]
+       member-declarator-list [opt] ;
+     function-definition
+     friend-type-declaration
      using-declaration
+     using-enum-declaration
+     static_assert-declaration
+     consteval-block-declaration
      template-declaration
+     explicit-specialization
+     deduction-guide
      alias-declaration
+     opaque-enum-declaration
+     empty-declaration
 
    member-declarator-list:
      member-declarator
@@ -28848,12 +28923,7 @@ cp_parser_member_specification_opt (cp_parser* parser)
    member-declarator:
      declarator attributes [opt] pure-specifier [opt]
      declarator attributes [opt] constant-initializer [opt]
-     identifier [opt] attributes [opt] : constant-expression
-
-   C++0x Extensions:
-
-   member-declaration:
-     static_assert-declaration  */
+     identifier [opt] attributes [opt] : constant-expression  */
 
 static void
 cp_parser_member_declaration (cp_parser* parser)
@@ -28952,6 +29022,14 @@ cp_parser_member_declaration (cp_parser* parser)
       return;
     }
 
+  if (cxx_dialect >= cxx26
+      && cp_lexer_next_token_is_keyword (parser->lexer, RID_CONSTEVAL)
+      && cp_lexer_nth_token_is (parser->lexer, 2, CPP_OPEN_BRACE))
+    {
+      cp_parser_consteval_block (parser, /*member_p=*/true);
+      return;
+    }
+
   parser->colon_corrects_to_scope_p = false;
 
   cp_omp_declare_simd_data odsd;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ca8d61dbca1..4baf9a7011b 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -12864,6 +12864,10 @@ instantiate_class_template (tree type)
              /* Build new TYPE_FIELDS.  */
               if (TREE_CODE (t) == STATIC_ASSERT)
                tsubst_stmt (t, args, tf_warning_or_error, NULL_TREE);
+             /* Consteval block.  */
+             else if (TREE_CODE (t) == STMT_EXPR
+                      && CONSTEVAL_BLOCK_P (t))
+               tsubst_expr (t, args, tf_warning_or_error, NULL_TREE);
              else if (TREE_CODE (t) != CONST_DECL)
                {
                  tree r;
@@ -20695,6 +20699,26 @@ tsubst_call_args (tree t, tree args, tsubst_flags_t 
complain,
     }
 }
 
+/* Evaluate BLOCK, which is a C++26 consteval block.  */
+
+void
+evaluate_consteval_block (tree block)
+{
+  if (TREE_CODE (block) == CLEANUP_POINT_EXPR)
+    block = TREE_OPERAND (block, 0);
+  if (TREE_CODE (block) == EXPR_STMT)
+    block = TREE_OPERAND (block, 0);
+  /* We have no object to initialize here and finish_call_expr will
+     return something like
+       (void) TARGET_EXPR <D.2675, {}>, <lambda()>::operator() ()
+     which cxx_eval_outermost_constant_expr would not evaluate.  So
+     extract the operator() which will get evaluated since it's an
+     immediate function.  */
+  if (TREE_CODE (block) == COMPOUND_EXPR)
+    block = TREE_OPERAND (block, 1);
+  cxx_constant_value (block);
+}
+
 /* Like tsubst but deals with expressions and performs semantic
    analysis.  */
 
@@ -22522,6 +22546,13 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
        if (empty_expr_stmt_p (stmt_expr))
          stmt_expr = void_node;
 
+       if (CONSTEVAL_BLOCK_P (t))
+         {
+           evaluate_consteval_block (stmt_expr);
+           /* We are done with this block.  */
+           stmt_expr = void_node;
+         }
+
        RETURN (stmt_expr);
       }
 
diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block1.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block1.C
new file mode 100644
index 00000000000..c9461e40de7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block1.C
@@ -0,0 +1,92 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+
+constexpr int fn () { return 42; }
+struct M {
+  static consteval void foo () {}
+};
+
+consteval { }
+consteval { fn (); }
+consteval { M::foo (); }
+consteval { auto x = fn (); return; }
+consteval {
+  [](int i) { return i; }(5);
+}
+auto lam = [] { };
+consteval { lam (); }
+
+struct S {
+  consteval { }
+};
+
+struct S2 {
+  consteval { fn(); }
+};
+
+class C {
+  consteval { }
+};
+
+class C2 {
+  consteval { M::foo (); }
+};
+
+union U {
+  consteval { }
+};
+
+template<typename>
+struct TS {
+  consteval { }
+};
+
+template<typename... Ts>
+struct TS2 {
+  consteval {
+    (Ts::foo (), ...);
+  }
+};
+
+TS2<M> ts2;
+
+void
+g ()
+{
+  consteval { }
+}
+
+template<typename>
+void
+tg ()
+{
+  consteval { }
+}
+
+/* __func__ won't be set.  Make sure we don't crash.  */
+consteval { __func__; }
+struct F {
+  consteval { __func__; }
+};
+template<typename>
+struct TF {
+  consteval { __func__; }
+};
+
+void die ();
+constexpr int
+bar (int i)
+{
+  if (i != 42)
+    die ();
+  return 0;
+}
+
+void
+foo ()
+{
+  constexpr int r = 42;
+  consteval {
+    bar (r);
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block2.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block2.C
new file mode 100644
index 00000000000..895fcb63867
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block2.C
@@ -0,0 +1,49 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+
+void fn ();
+
+consteval { fn (); }       // { dg-error "call to non-.constexpr. function" }
+consteval { return 42; }    // { dg-error "return-statement with a value" }
+
+struct S {
+  consteval {
+    fn ();                 // { dg-error "call to non-.constexpr. function" }
+  }
+  consteval {
+    return 42;             // { dg-error "return-statement with a value" }
+  }
+};
+
+template<typename T>
+constexpr void foo (T t) { return t; } // { dg-error "return-statement with a 
value" }
+
+template<int N>
+struct R {
+  consteval { foo (N); }
+};
+
+R<1> r;
+
+template<typename T>
+constexpr void foo2 (T t) { return t; }        // { dg-error "return-statement 
with a value" }
+
+template<int N>
+void
+f ()
+{
+  consteval { foo2 (1); }
+}
+
+constexpr int bar (int) { return 0; }
+
+void
+g ()
+{
+  f<1>();
+
+  int r = 42;
+  consteval {
+    bar (r);         // { dg-error ".r. is not captured" }
+  }
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block3.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block3.C
new file mode 100644
index 00000000000..c1221c3019f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block3.C
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+// Test that we actually evaluate the consteval block.
+
+void bar () { }
+
+template<int N>
+constexpr void
+fn ()
+{
+  if (N > 0)
+    bar ();                    // { dg-error "call to non-.constexpr. 
function" }
+}
+
+template<int N>
+struct S {
+  consteval { fn<N>(); }       // { dg-error "called in a constant expression" 
}
+};
+
+S<1> s;
+
+template<int N>
+constexpr void
+fn2 ()
+{
+  if (N > 0)
+    bar ();                    // { dg-error "call to non-.constexpr. 
function" }
+}
+
+template<int N>
+void
+g ()
+{
+  consteval { fn2<N>(); }      // { dg-error "called in a constant expression" 
}
+}
+
+void
+f ()
+{
+  g<1>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block4.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block4.C
new file mode 100644
index 00000000000..be95e170ee1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block4.C
@@ -0,0 +1,41 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+// Test that we actually evaluate the consteval block.
+
+void bar () { }
+
+template<int N>
+constexpr void
+fn ()
+{
+  if (N > 0)
+    bar ();
+}
+
+template<int N>
+struct S {
+  consteval { fn<N>(); }
+};
+
+S<0> s;
+
+template<int N>
+constexpr void
+fn2 ()
+{
+  if (N > 0)
+    bar ();
+}
+
+template<int N>
+void
+g ()
+{
+  consteval { fn2<N>(); }
+}
+
+void
+f ()
+{
+  g<0>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block5.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block5.C
new file mode 100644
index 00000000000..462cebe6cc9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block5.C
@@ -0,0 +1,70 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+
+void bar () { }
+
+template<int N>
+constexpr void
+fn ()
+{
+  if (N > 0)
+    bar ();
+}
+
+template<typename>
+struct S {
+  consteval { fn<1>(); }
+};
+
+template<>
+struct S<int> {
+  consteval { fn<0>(); }
+};
+
+S<int> s1;
+
+template<typename T>
+struct S<T*> {
+  consteval { fn<0>(); }
+};
+
+S<int *> s2;
+
+template<typename T, int N>
+struct W {
+  consteval { T t; fn<N - 1>(); }
+};
+
+template<typename T>
+struct W<T, 0> {
+  consteval { T t; fn<0>(); }
+};
+
+template<>
+struct W<char, 0> {
+  consteval { fn<0>(); }
+};
+
+W<int, 0> w1;
+W<int, 1> w2;
+W<char, 0> w3;
+
+template<typename>
+void
+f ()
+{
+  consteval { fn<1>(); }
+}
+
+template<>
+void
+f<int> ()
+{
+  consteval { fn<0>(); }
+}
+
+void
+g ()
+{
+  f<int> ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block6.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block6.C
new file mode 100644
index 00000000000..ca90b3e376f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block6.C
@@ -0,0 +1,108 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+
+void die () {}
+
+template<int N>
+constexpr void
+fn ()
+{
+  if (N > 0)
+    die ();
+}
+
+template<int N>
+void
+fn2 ()
+{
+  struct S {
+    consteval {
+      fn<N>();
+    }
+  };
+}
+
+template<int N>
+struct A {
+  struct B {
+    consteval {
+      fn<N>();
+    }
+  };
+  template<int M>
+  struct C {
+    consteval {
+      fn<N + M>();
+    }
+  };
+};
+
+template<int N>
+struct D {
+  constexpr static int i = 0;
+  struct E {
+    consteval {
+      fn<i>();
+    }
+  };
+};
+
+A<0>::B b;
+A<0>::C<0> c;
+D<0>::E e;
+
+void
+f ()
+{
+  fn2<0>();
+}
+
+static constexpr int j = 0;
+const int x = 0;
+
+consteval {
+  fn<j>();
+  consteval {
+    fn<j + j>();
+    consteval {
+      fn<j + j + j>();
+      consteval {
+       fn<j + j + x>();
+       consteval {
+         fn<j + x>();
+       }
+      }
+    }
+  }
+}
+
+struct R { constexpr R() {} };
+
+template<int N>
+constexpr auto X = N;
+
+consteval {
+  R{};
+  constexpr auto x = 0;
+  fn<x>();
+  fn<X<0>>();
+  if consteval
+    {
+      fn<j>();
+    }
+  else
+    {
+      die ();
+    }
+}
+
+template<typename T>
+struct G {
+  consteval {
+    using U = T[3];
+    U arr{};
+    int i = arr[2];
+  }
+};
+
+G<int> g;
diff --git a/gcc/testsuite/g++.dg/cpp26/consteval-block7.C 
b/gcc/testsuite/g++.dg/cpp26/consteval-block7.C
new file mode 100644
index 00000000000..231682f8adf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp26/consteval-block7.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++26 } }
+// Test consteval blocks, as specified by P2996.
+
+consteval {
+  template <class T> // { dg-error "template declaration cannot appear at 
block scope" }
+  struct X { };
+
+  template <class T> // { dg-error "template declaration cannot appear at 
block scope" }
+  concept C = true;
+
+  return; // OK
+}

base-commit: 39ba01fe70c77e70a00ed65a1e6bac8350479f4d
-- 
2.50.1

Reply via email to