On Thu, Sep 24, 2026 at 07:32:39PM -0400, Jason Merrill wrote:
> On 9/23/26 5:07 PM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > In my P4101 patch I left the part that deals with taking the address of
> > a consteval function unresolved, leaving it as a follow-up.  Little did
> > I know that the follow-up wouldn't be just a small refinement, but a
> > relatively big change.
> > 
> > So, taking the address of a consteval function is no longer prohibited
> > outside an immediate function context, and a pointer or ptr-to-member
> > that points to an immediate function is a consteval-only value.  So
> > consteval_only_p has to be adjusted.  Since P4101 is a DR and consteval
> > functions are a C++20 thing, consteval_only_p & other spots cannot be
> > guarded with flag_reflection.  That might, unfortunately, penalize code
> > that doesn't use Reflection at all.
> > 
> > find_immediate_fndecl is now gone and instead, check_out_of_consteval_use
> > diagnoses invalid uses of the address of a consteval function.  The
> > diagnostic now looks like:
> > 
> >    error: consteval-only value outside an immediate function context
> >    note: taking address of an immediate function 'constexpr int f(auto:1) 
> > [with auto:1 = int]'
> > 
> > Problem #1: currently we detect out-of-consteval issues in
> > cp_genericize_r, but that runs too early, after parsing a function.  But
> > some functions will only be escalated at the end of the TU, so the
> > out-of-consteval detection needs to be done in cp_fold_immediate_r.  For
> > an example, see consteval-prop20.C and its "auto p = &f<int>;".
> > I think this matches the [expr.const.imm]/2 wording too.  But then
> > cp_fold_immediate_r has to be taught not to walk the initializer of
> > a constexpr variable, sort of like the if consteval code already
> > present.
> > 
> > Problem #2: PTRMEM_CST is a shared constant and carries PTRMEM_CST_LOCATION,
> > but that is the location of the & itself, not its use.  So I've added
> > a location wrapper around it in cp_fold_non_odr_use_1.  Without this,
> > the diagnostic would make no sense.  See e.g. value10.C.
> 
> Did you consider copying the PTRMEM_CST to give it the new location?

I wouldn't do this.  I think _CSTs should be shared, and to me, the
usual location wrapper around it is a better approach.

> > Problem #3: sometimes we fold things too early so we miss some
> > out-of-consteval diagnostics.  Due to this we accept some ill-formed code,
> > e.g. fp (), (o.*pm) (), or tbl[1].fp () where the operand is a constexpr
> > variable; see the comments in value9.C.  I've opened PR127478 though
> > that doesn't cover all of it.  I don't really have a good idea how to fix
> > this right now.  I suspect we might want to delay some folding, if possible.
> > 
> > Relatedly,
> > 
> >    consteval int f () { return 1; }
> >    consteval auto g () { return &f; }
> >    void fn () { int i; i = g () (); }
> > 
> > is still ill-formed, but would work were P3496 adopted.
> > 
> > This patch removes the !consteval_only_p assert in cp_finish_decl
> > because there the decl's DECL_INITIAL is still NULL_TREE (and so in the
> > value model it cannot be true).  In
> > 
> >    struct O { consteval int mf () const { return 1; } };
> >    constexpr auto pm = &O::mf;
> >    void
> >    fn (O o)
> >    {
> >      static constexpr auto spm = &O::mf;
> >    }
> > 
> > both spm and pm are handled by the consteval_only_p check in
> > make_rtl_for_nonlocal_decl.  The consequence is that pm and spm are no 
> > longer
> > emitted, even without -freflection.
> > 
> > Aside: I think Example 2 in [expr.const.const] is now wrong, the first
> > error is no longer expected after P4101.
> > 
> > Aside #2: I think [expr.const.const]/3.2 should say "subobject" instead
> > of "subject".  (I can open a pull request for both.)
> 
> Sounds good, I agree with both.

I've created pull requests for both.

> > @@ -1480,7 +1526,23 @@ cp_fold_immediate_r (tree *stmt_p, int 
> > *walk_subtrees, void *data_)
> >         promote_function_to_consteval (current_function_decl);
> >       else if (complain & tf_error)
> >         {
> > -         if (call_p)
> > +         if (imm_const_p)
> > +           {
> > +             if (!data->pset.add (*stmt_p)
> > +                 && !check_out_of_consteval_use (e, (data->decl
> > +                                                    ? data->decl
> > +                                                    : *stmt_p)))
> 
> Can you elaborate on why the ->decl handling is needed?

Just so that we emit the same "initializer of non-constexpr variable"
diagnostic for all initializers, at namespace scope, in a constexpr
function, in a non-constexpr function.  It's not about correctness,
just the wording of the error.

I've noticed that check_out_of_consteval_use no longer needs the complain
parameter, dropped.
 
> > +      if (INTEGRAL_OR_ENUMERATION_TYPE_P (type) || SCALAR_FLOAT_TYPE_P 
> > (type))
> 
> This seems like an incomplete subset of scalarish_type_p that can't have
> consteval-only values.  How about a new predicate function
> type_has_consteval_only_values?

Yeah, it was supposed to be a quick filter-out test.  I think
type_has_consteval_only_values would mean another walk looking for
std::meta::info and that seems too expensive.  But what we're
looking for here is to find out whether the type can potentially
have a consteval-only value.  So I've added
type_can_have_consteval_only_values which checks
AGGREGATE_TYPE_P || INDIRECT_TYPE_P || REFLECTION_TYPE_P.  That
should be fast enough and filter out all integral etc. types.


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

-- >8 --
In my P4101 patch I left the part that deals with taking the address of
a consteval function unresolved, leaving it as a follow-up.  Little did
I know that the follow-up wouldn't be just a small refinement, but a
relatively big change.

So, taking the address of a consteval function is no longer prohibited
outside an immediate function context, and a pointer or ptr-to-member
that points to an immediate function is a consteval-only value.  So
consteval_only_p has to be adjusted.  Since P4101 is a DR and consteval
functions are a C++20 thing, consteval_only_p & other spots cannot be
guarded with flag_reflection.  That might, unfortunately, penalize code
that doesn't use Reflection at all.

find_immediate_fndecl is now gone and instead, check_out_of_consteval_use
diagnoses invalid uses of the address of a consteval function.  The
diagnostic now looks like:

  error: consteval-only value outside an immediate function context
  note: taking address of an immediate function 'constexpr int f(auto:1) [with 
auto:1 = int]'

Problem #1: currently we detect out-of-consteval issues in
cp_genericize_r, but that runs too early, after parsing a function.  But
some functions will only be escalated at the end of the TU, so the
out-of-consteval detection needs to be done in cp_fold_immediate_r.  For
an example, see consteval-prop20.C and its "auto p = &f<int>;".
I think this matches the [expr.const.imm]/2 wording too.  But then
cp_fold_immediate_r has to be taught not to walk the initializer of
a constexpr variable, sort of like the if consteval code already
present.

Problem #2: PTRMEM_CST is a shared constant and carries PTRMEM_CST_LOCATION,
but that is the location of the & itself, not its use.  So I've added
a location wrapper around it in cp_fold_non_odr_use_1.  Without this,
the diagnostic would make no sense.  See e.g. value10.C.

Problem #3: sometimes we fold things too early so we miss some
out-of-consteval diagnostics.  Due to this we accept some ill-formed code,
e.g. fp (), (o.*pm) (), or tbl[1].fp () where the operand is a constexpr
variable; see the comments in value9.C.  I've opened PR127478 though
that doesn't cover all of it.  I don't really have a good idea how to fix
this right now.  I suspect we might want to delay some folding, if possible.

Relatedly,

  consteval int f () { return 1; }
  consteval auto g () { return &f; }
  void fn () { int i; i = g () (); }

is still ill-formed, but would work were P3496 adopted.

This patch removes the !consteval_only_p assert in cp_finish_decl
because there the decl's DECL_INITIAL is still NULL_TREE (and so in the
value model it cannot be true).  In

  struct O { consteval int mf () const { return 1; } };
  constexpr auto pm = &O::mf;
  void
  fn (O o)
  {
    static constexpr auto spm = &O::mf;
  }

both spm and pm are handled by the consteval_only_p check in
make_rtl_for_nonlocal_decl.  The consequence is that pm and spm are no longer
emitted, even without -freflection.

        PR c++/125820

gcc/c-family/ChangeLog:

        * c-cppbuiltin.cc (c_cpp_builtins): Update __cpp_consteval to
        202606L.

gcc/cp/ChangeLog:

        * constexpr.cc (find_immediate_fndecl): Remove.
        (cxx_eval_outermost_constant_expr): Don't call it.
        * cp-gimplify.cc (struct cp_fold_data): New member decl.
        Initialize it.
        (taking_address_of_imm_fn_error): No longer static.  New parameter
        with a default argument.  Use emit_diagnostic instead of error_at.
        (cp_fold_immediate_r): Unwrap the location wrapper around a
        PTRMEM_CST.  Do not check flag_reflection before clearing
        consteval-only DECL_EXPRs.  Consider consteval-only values
        escalating and diagnose them with check_out_of_consteval_use.
        Remove unreachable code calling taking_address_of_imm_fn_error.
        <case BIND_EXPR>: New.  Don't walk the initializer of a constexpr
        variable.
        <case INIT_EXPR>: New.  Pass down the decl we're initializing.
        (cp_genericize_r): Use NULL_TREE instead of NULL.
        <case ADDR_EXPR>: If check_out_of_consteval_use returns true,
        overwrite *stmt_p and clear *walk_subtrees.
        <case BIND_EXPR>: Don't check flag_reflection.
        (cp_fold_non_odr_use_1): If we've folded to a PTRMEM_CST, wrap
        it in a location wrapper.
        (cp_fully_fold_init): New tree parameter.  Use it.
        * cp-tree.h (cp_fully_fold_init): Adjust declaration.
        (taking_address_of_imm_fn_error): Declare.
        (check_out_of_consteval_use): Adjust declaration.
        * decl.cc (make_rtl_for_nonlocal_decl): Adjust a comment.
        (cp_finish_decl): Remove an assert.
        * reflect.cc (immediate_fn_of): New.
        (consteval_only_value_p): Return true if immediate_fn_of.
        (type_can_have_consteval_only_values): New.
        (consteval_only_p): Don't check flag_reflection.  Return
        early if the tree can't be consteval-only.  Return false
        for DECL_VIRTUAL_P or DECL_TINFO_P or
        !DECL_DECLARED_CONSTEXPR_P.  Use tparm_object_argument for
        DECL_NTTP_OBJECT_P.  Return early if not C++20.
        (check_out_of_consteval_use): New tree parameter.  Don't check
        flag_reflection.  Return early if not C++20.  Adjust diagnostics.
        * typeck2.cc (store_init_value): Don't call cp_fully_fold_init
        on the initializer of a constexpr variable.  Pass decl to
        cp_fully_fold_init and check_out_of_consteval_use.  Don't call
        check_out_of_consteval_use if the value was evaluated to
        error_mark_node.  Don't emit the "is initialized with"
        diagnostic here.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp23/consteval-if12.C: Remove dg-error.
        * g++.dg/cpp23/feat-cxx2b.C: Update the expected value of
        __cpp_consteval.
        * g++.dg/cpp26/feat-cxx26.C: Likewise.
        * g++.dg/cpp29/feat-cxx29.C: Likewise.
        * g++.dg/cpp2a/consteval-prop1.C: Adjust expected diagnostics.
        * g++.dg/cpp2a/consteval-prop10.C: Likewise.
        * g++.dg/cpp2a/consteval-prop19.C: Likewise.
        * g++.dg/cpp2a/consteval-prop2.C: Likewise.
        * g++.dg/cpp2a/consteval-prop20.C: Likewise.
        * g++.dg/cpp2a/consteval-prop9.C: Likewise.
        * g++.dg/cpp2a/consteval20.C: Likewise.
        * g++.dg/cpp2a/consteval22.C: Remove dg-error.
        * g++.dg/cpp2a/consteval24.C: Likewise.
        * g++.dg/cpp2a/consteval3.C: Adjust expected diagnostics.
        * g++.dg/cpp2a/consteval32.C: Likewise.
        * g++.dg/cpp2a/consteval7.C: Remove dg-error.
        * g++.dg/cpp2a/feat-cxx2a.C: Update the expected value of
        __cpp_consteval.
        * g++.dg/cpp2a/srcloc20.C: Adjust expected diagnostics.
        * g++.dg/reflect/diag3.C: Likewise.
        * g++.dg/reflect/init4.C: Remove an XFAIL.
        * g++.dg/reflect/init7.C: Adjust expected diagnostics.
        * g++.dg/reflect/parm4.C: Add a dg-error.
        * g++.dg/reflect/value1.C: Adjust expected diagnostics.
        * g++.dg/reflect/value2.C: Likewise.
        * g++.dg/reflect/value4.C: Likewise.
        * g++.dg/reflect/value5.C: Likewise.
        * g++.dg/reflect/consteval-prop1.C: New test.
        * g++.dg/reflect/value10.C: New test.
        * g++.dg/reflect/value11.C: New test.
        * g++.dg/reflect/value12.C: New test.
        * g++.dg/reflect/value13.C: New test.
        * g++.dg/reflect/value14.C: New test.
        * g++.dg/reflect/value15.C: New test.
        * g++.dg/reflect/value9.C: New test.
---
 gcc/c-family/c-cppbuiltin.cc                  |   2 +-
 gcc/cp/constexpr.cc                           |  43 ---
 gcc/cp/cp-gimplify.cc                         | 166 +++++++----
 gcc/cp/cp-tree.h                              |   6 +-
 gcc/cp/decl.cc                                |   3 +-
 gcc/cp/reflect.cc                             | 111 ++++++--
 gcc/cp/typeck2.cc                             |  33 +--
 gcc/testsuite/g++.dg/cpp23/consteval-if12.C   |  14 +-
 gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C       |   4 +-
 gcc/testsuite/g++.dg/cpp26/feat-cxx26.C       |   4 +-
 gcc/testsuite/g++.dg/cpp29/feat-cxx29.C       |   4 +-
 gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C  |  14 +-
 gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C |   3 +-
 gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C |   3 +-
 gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C  |   3 +-
 gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C |   3 +-
 gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C  |   3 +-
 gcc/testsuite/g++.dg/cpp2a/consteval20.C      |  16 +-
 gcc/testsuite/g++.dg/cpp2a/consteval22.C      |   4 +-
 gcc/testsuite/g++.dg/cpp2a/consteval24.C      |  16 +-
 gcc/testsuite/g++.dg/cpp2a/consteval3.C       |   6 +-
 gcc/testsuite/g++.dg/cpp2a/consteval32.C      |   3 +-
 gcc/testsuite/g++.dg/cpp2a/consteval7.C       |   8 +-
 gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C       |   4 +-
 gcc/testsuite/g++.dg/cpp2a/srcloc20.C         |  13 +-
 .../g++.dg/reflect/consteval-prop1.C          |  20 ++
 gcc/testsuite/g++.dg/reflect/diag3.C          |  18 +-
 gcc/testsuite/g++.dg/reflect/init4.C          |   2 +-
 gcc/testsuite/g++.dg/reflect/init7.C          |  20 +-
 gcc/testsuite/g++.dg/reflect/parm4.C          |   2 +-
 gcc/testsuite/g++.dg/reflect/value1.C         | 122 ++++----
 gcc/testsuite/g++.dg/reflect/value10.C        |  14 +
 gcc/testsuite/g++.dg/reflect/value11.C        |  32 +++
 gcc/testsuite/g++.dg/reflect/value12.C        |  25 ++
 gcc/testsuite/g++.dg/reflect/value13.C        |  40 +++
 gcc/testsuite/g++.dg/reflect/value14.C        |  19 ++
 gcc/testsuite/g++.dg/reflect/value15.C        |  71 +++++
 gcc/testsuite/g++.dg/reflect/value2.C         |  10 +-
 gcc/testsuite/g++.dg/reflect/value4.C         |   4 +-
 gcc/testsuite/g++.dg/reflect/value5.C         |  22 +-
 gcc/testsuite/g++.dg/reflect/value9.C         | 261 ++++++++++++++++++
 41 files changed, 887 insertions(+), 284 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/consteval-prop1.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/value10.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/value11.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/value12.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/value13.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/value14.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/value15.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/value9.C

diff --git a/gcc/c-family/c-cppbuiltin.cc b/gcc/c-family/c-cppbuiltin.cc
index 5c90df81f9c..2778ab3176c 100644
--- a/gcc/c-family/c-cppbuiltin.cc
+++ b/gcc/c-family/c-cppbuiltin.cc
@@ -1078,7 +1078,7 @@ c_cpp_builtins (cpp_reader *pfile)
            cpp_define (pfile, "__cpp_constexpr=202002L");
          cpp_define (pfile, "__cpp_constexpr_in_decltype=201711L");
          cpp_define (pfile, "__cpp_conditional_explicit=201806L");
-         cpp_define (pfile, "__cpp_consteval=202211L");
+         cpp_define (pfile, "__cpp_consteval=202606L");
          cpp_define (pfile, "__cpp_constinit=201907L");
          if (cxx_dialect <= cxx20)
            cpp_define (pfile, "__cpp_deduction_guides=201907L");
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 31ef5bf1111..5aedd449be0 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -11430,22 +11430,6 @@ find_heap_var_refs (tree *tp, int *walk_subtrees, void 
*/*data*/)
   return NULL_TREE;
 }
 
-/* Find immediate function decls in *TP if any.  */
-
-static tree
-find_immediate_fndecl (tree *tp, int *walk_subtrees, void */*data*/)
-{
-  if (TREE_CODE (*tp) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (*tp))
-    return *tp;
-  if (TREE_CODE (*tp) == PTRMEM_CST
-      && TREE_CODE (PTRMEM_CST_MEMBER (*tp)) == FUNCTION_DECL
-      && DECL_IMMEDIATE_FUNCTION_P (PTRMEM_CST_MEMBER (*tp)))
-    return PTRMEM_CST_MEMBER (*tp);
-  if (REFLECT_EXPR_P (*tp))
-    *walk_subtrees = 0;
-  return NULL_TREE;
-}
-
 /* T has TREE_CONSTANT set but has been deemed not a valid C++ constant
    expression.  Return a version of T that has TREE_CONSTANT cleared.  */
 
@@ -11549,7 +11533,6 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
               ? cv_unqualified (TREE_TYPE (object))
               : initialized_type (t));
   tree r = t;
-  bool is_consteval = false;
   if (VOID_TYPE_P (type))
     {
       if (!constexpr_dtor)
@@ -11566,8 +11549,6 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
          tree fndecl = cp_get_callee_fndecl_nofold (x);
          if (fndecl == NULL_TREE || !DECL_IMMEDIATE_FUNCTION_P (fndecl))
            return t;
-         else
-           is_consteval = true;
          tree lam;
          if (manifestly_const_eval == mce_true
              && LAMBDA_FUNCTION_P (fndecl)
@@ -11585,8 +11566,6 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
       if (TREE_CODE (x) == TARGET_EXPR)
        x = TARGET_EXPR_INITIAL (x);
       tree fndecl = cp_get_callee_fndecl_nofold (x);
-      if (fndecl && DECL_IMMEDIATE_FUNCTION_P (fndecl))
-       is_consteval = true;
       /* Don't try to evaluate a std::vector constructor taking an integer, it
         will fail in the 'if (heap_var)' block below after doing all the work
         (c++/113835).  This will need adjustment if P3554 is accepted.  Note
@@ -11781,28 +11760,6 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
        }
     }
 
-  /* Check that immediate invocation does not return an expression referencing
-     any immediate function decls.  */
-  if (!non_constant_p && cxx_dialect >= cxx20)
-    if (tree immediate_fndecl
-       = cp_walk_tree_without_duplicates (&r, find_immediate_fndecl,
-                                          NULL))
-    {
-      if (!allow_non_constant && !non_constant_p)
-       {
-         if (is_consteval)
-           error_at (cp_expr_loc_or_input_loc (t),
-                     "immediate evaluation returns address of immediate "
-                     "function %qD", immediate_fndecl);
-         else
-           error_at (cp_expr_loc_or_input_loc (t),
-                     "constant evaluation returns address of immediate "
-                     "function %qD", immediate_fndecl);
-       }
-      r = t;
-      non_constant_p = true;
-    }
-
   if (!non_constant_p && !constexpr_dtor)
     verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
 
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 0fc44592cd2..8d6a6664106 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -88,7 +88,9 @@ struct cp_fold_data
 {
   hash_set<tree> pset;
   fold_flags_t flags;
-  cp_fold_data (fold_flags_t flags): flags (flags)
+  tree decl;
+  cp_fold_data (fold_flags_t flags, tree decl = NULL_TREE)
+    : flags (flags), decl (decl)
   {
     gcc_checking_assert (!(flags & ff_mce_false)
                         || !(flags & ff_only_non_odr));
@@ -1331,14 +1333,16 @@ struct cp_genericize_data
 /* Emit an error about taking the address of an immediate function.
    EXPR is the whole expression; DECL is the immediate function.  */
 
-static void
-taking_address_of_imm_fn_error (tree expr, tree decl)
+void
+taking_address_of_imm_fn_error (tree expr, tree decl,
+                               diagnostics::kind diag_kind/*=kind::error*/)
 {
   auto_diagnostic_group d;
   const location_t loc = (TREE_CODE (expr) == PTRMEM_CST
                          ? PTRMEM_CST_LOCATION (expr)
                          : EXPR_LOCATION (expr));
-  error_at (loc, "taking address of an immediate function %qD", decl);
+  emit_diagnostic (diag_kind, loc, 0,
+                  "taking address of an immediate function %qD", decl);
   maybe_explain_promoted_consteval (loc, decl);
 }
 
@@ -1374,7 +1378,12 @@ static tree
 cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
 {
   auto data = static_cast<cp_fold_data *>(data_);
-  tree stmt = *stmt_p;
+  /* If we got the location wrapper around a PTRMEM_CST from
+     cp_fold_non_odr_use_1, unwrap it now.  *STMT_P will carry the
+     location for us.  */
+  tree stmt = (location_wrapper_p (*stmt_p)
+              && TREE_CODE (TREE_OPERAND (*stmt_p, 0)) == PTRMEM_CST
+              ? TREE_OPERAND (*stmt_p, 0) : *stmt_p);
   /* The purpose of this is not to emit errors for mce_unknown.  */
   const tsubst_flags_t complain = (data->flags & ff_mce_false
                                   ? tf_error : tf_none);
@@ -1402,12 +1411,11 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, 
void *data_)
     {
     case DECL_EXPR:
       /* Clear consteval-only DECL_EXPRs.  */
-      if (flag_reflection)
-       {
-         tree d = DECL_EXPR_DECL (stmt);
-         if (VAR_P (d) && consteval_only_p (d))
-           *stmt_p = void_node;
-       }
+      {
+       tree d = DECL_EXPR_DECL (stmt);
+       if (VAR_P (d) && consteval_only_p (d))
+         *stmt_p = void_node;
+      }
       break;
     case CALL_EXPR:
     case AGGR_INIT_EXPR:
@@ -1423,6 +1431,38 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, 
void *data_)
       if (!ADDR_EXPR_DENOTES_CALL_P (stmt))
        decl = TREE_OPERAND (stmt, 0);
       break;
+    case BIND_EXPR:
+      if (!data->pset.add (stmt))
+       {
+         /* The initializer of a constexpr variable is an MCE context.  */
+         for (tree v = BIND_EXPR_VARS (stmt); v; v = DECL_CHAIN (v))
+           if (VAR_P (v) && !DECL_DECLARED_CONSTEXPR_P (v))
+             if (tree r = cp_walk_tree (&DECL_INITIAL (v), cp_fold_immediate_r,
+                                        data_, nullptr))
+               return r;
+         if (tree r = cp_walk_tree (&BIND_EXPR_BODY (stmt), 
cp_fold_immediate_r,
+                                    data_, nullptr))
+           return r;
+       }
+      *walk_subtrees = 0;
+      return NULL_TREE;
+    case INIT_EXPR:
+      if (!data->pset.add (stmt))
+       {
+         if (tree r = cp_walk_tree (&TREE_OPERAND (stmt, 0),
+                                    cp_fold_immediate_r, data_, nullptr))
+           return r;
+         /* Pass down the decl we're initializing for a better diagnostic.  */
+         auto ovr = make_temp_override (data->decl);
+         if (VAR_P (TREE_OPERAND (stmt, 0))
+             && !DECL_ARTIFICIAL (TREE_OPERAND (stmt, 0)))
+           data->decl = TREE_OPERAND (stmt, 0);
+         if (tree r = cp_walk_tree (&TREE_OPERAND (stmt, 1),
+                                    cp_fold_immediate_r, data_, nullptr))
+           return r;
+       }
+      *walk_subtrees = 0;
+      return NULL_TREE;
     case IF_STMT:
       if (IF_STMT_CONSTEVAL_P (stmt))
        {
@@ -1467,7 +1507,13 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, 
void *data_)
   if (DECL_IMMEDIATE_FUNCTION_P (decl))
     {
       tree e = cxx_constant_value (stmt, tf_none);
-      if (e == error_mark_node)
+      const bool imm_const_p = consteval_only_p (e);
+      /* [expr.const.imm]/2: A potentially evaluated expression or conversion
+        is immediate-escalating if it is neither initially in an immediate
+        function context nor a subexpression of an immediate invocation, and
+        -- it is an immediate constant expression or
+        -- it is an immediate invocation that is not a constant expression.  */
+      if (e == error_mark_node || imm_const_p)
        {
          /* This takes care of, e.g.,
              template <typename T>
@@ -1480,7 +1526,23 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, 
void *data_)
            promote_function_to_consteval (current_function_decl);
          else if (complain & tf_error)
            {
-             if (call_p)
+             if (imm_const_p)
+               {
+                 if (!data->pset.add (*stmt_p)
+                     && !check_out_of_consteval_use (e, (data->decl
+                                                        ? data->decl
+                                                        : *stmt_p)))
+                   {
+                     /* consteval_only_p said E is consteval-only, so we
+                        should have emitted an error.  */
+                     gcc_checking_assert (false);
+                     error_at (cp_expr_loc_or_input_loc (stmt),
+                               "consteval-only value outside an immediate "
+                               "function context");
+                   }
+                 *stmt_p = error_mark_node;
+               }
+             else if (call_p)
                {
                  auto_diagnostic_group d;
                  location_t loc = cp_expr_loc_or_input_loc (stmt);
@@ -1491,11 +1553,6 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, 
void *data_)
                  *stmt_p = error_mark_node;
                  maybe_explain_promoted_consteval (loc, decl);
                }
-             else if (!data->pset.add (stmt))
-               {
-                 taking_address_of_imm_fn_error (stmt, decl);
-                 *stmt_p = build_zero_cst (TREE_TYPE (stmt));
-               }
              /* If we're giving hard errors, continue the walk rather than
                 bailing out after the first error.  */
              return NULL_TREE;
@@ -1908,7 +1965,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
       || (TREE_CODE (stmt) == AGGR_INIT_EXPR && AGGR_INIT_FROM_THUNK_P (stmt)))
     {
       *walk_subtrees = 0;
-      return NULL;
+      return NULL_TREE;
     }
 
   /* Dereference invisible reference parms.  */
@@ -1917,7 +1974,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
       *stmt_p = convert_from_reference (stmt);
       p_set->add (*stmt_p);
       *walk_subtrees = 0;
-      return NULL;
+      return NULL_TREE;
     }
 
   /* Map block scope extern declarations to visible declarations with the
@@ -1931,7 +1988,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
            TREE_USED (alias) |= TREE_USED (stmt);
          }
        *walk_subtrees = 0;
-       return NULL;
+       return NULL_TREE;
       }
 
   if (TREE_CODE (stmt) == INTEGER_CST
@@ -1976,7 +2033,11 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
          *stmt_p = fold_convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
          *walk_subtrees = 0;
        }
-      check_out_of_consteval_use (stmt);
+      if (check_out_of_consteval_use (stmt))
+       {
+         *stmt_p = error_mark_node;
+         *walk_subtrees = 0;
+       }
       break;
 
     case RETURN_EXPR:
@@ -2154,28 +2215,27 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
              cp_walk_tree (&DECL_INITIAL (decl), cp_genericize_r, data, NULL);
          wtd->no_sanitize_p = no_sanitize_p;
        }
-      if (flag_reflection)
-       /* Adjust consteval-only vars in BIND_EXPR_VARS so that REFLECT_EXPR
-          doesn't leak into the ME.  */
-       for (tree *p = &BIND_EXPR_VARS (stmt); *p; )
-         {
-           if (VAR_P (*p))
-             {
-               /* First, adjust null reflections.  */
-               if (DECL_INITIAL (*p))
-                 rewrite_null_reflection (DECL_INITIAL (*p));
-               /* If the variable is still consteval-only, remove it.  */
-               if (consteval_only_p (*p))
-                 {
-                   if (BIND_EXPR_BLOCK (stmt)
-                       && *p == BLOCK_VARS (BIND_EXPR_BLOCK (stmt)))
-                     BLOCK_VARS (BIND_EXPR_BLOCK (stmt)) = DECL_CHAIN (*p);
-                   *p = DECL_CHAIN (*p);
-                   continue;
-                 }
-             }
-           p = &DECL_CHAIN (*p);
-         }
+      /* Adjust consteval-only vars in BIND_EXPR_VARS so that REFLECT_EXPR
+        doesn't leak into the ME.  */
+      for (tree *p = &BIND_EXPR_VARS (stmt); *p; )
+       {
+         if (VAR_P (*p))
+           {
+             /* First, adjust null reflections.  */
+             if (flag_reflection && DECL_INITIAL (*p))
+               rewrite_null_reflection (DECL_INITIAL (*p));
+             /* If the variable is still consteval-only, remove it.  */
+             if (consteval_only_p (*p))
+               {
+                 if (BIND_EXPR_BLOCK (stmt)
+                     && *p == BLOCK_VARS (BIND_EXPR_BLOCK (stmt)))
+                   BLOCK_VARS (BIND_EXPR_BLOCK (stmt)) = DECL_CHAIN (*p);
+                 *p = DECL_CHAIN (*p);
+                 continue;
+               }
+           }
+         p = &DECL_CHAIN (*p);
+       }
       wtd->bind_expr_stack.safe_push (stmt);
       cp_walk_tree (&BIND_EXPR_BODY (stmt),
                    cp_genericize_r, data, NULL);
@@ -2607,7 +2667,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void 
*data)
 
   p_set->add (*stmt_p);
 
-  return NULL;
+  return NULL_TREE;
 }
 
 /* Lower C++ front end trees to GENERIC in T_P.  */
@@ -3155,6 +3215,7 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
 static tree
 cp_fold_non_odr_use_1 (tree x)
 {
+  location_t loc = cp_expr_location (x);
   tree var = x;
   while (!VAR_P (var))
     switch (TREE_CODE (var))
@@ -3191,7 +3252,13 @@ cp_fold_non_odr_use_1 (tree x)
     return x;
 
   tree t = maybe_constant_value (x);
-  return TREE_CONSTANT (t) ? t : x;
+  if (TREE_CONSTANT (t))
+    {
+      if (TREE_CODE (t) == PTRMEM_CST && loc != UNKNOWN_LOCATION)
+       t = maybe_wrap_with_location (t, loc);
+      return t;
+    }
+  return x;
 }
 
 /* Fold expression X which is used as an rvalue if RVAL is true.  */
@@ -3286,15 +3353,16 @@ cp_fully_fold (tree x)
 }
 
 /* Likewise, but also fold recursively, which cp_fully_fold doesn't perform
-   in some cases.  */
+   in some cases.  DECL, if any, is the variable we are initializing; this is
+   used for better diagnostics in cp_fold_immediate_r.  */
 
 tree
-cp_fully_fold_init (tree x)
+cp_fully_fold_init (tree x, tree decl/*=NULL_TREE*/)
 {
   if (processing_template_decl)
     return x;
   x = cp_fully_fold (x, mce_false);
-  cp_fold_data data (ff_mce_false);
+  cp_fold_data data (ff_mce_false, decl);
   if (cxx_dialect >= cxx20)
     {
       cp_walk_tree (&x, cp_fold_immediate_r, &data, NULL);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 947bf62ff98..ed876db8db2 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9257,7 +9257,7 @@ extern tree cp_fold_maybe_rvalue          (tree, bool);
 extern tree cp_fold_rvalue                     (tree);
 extern tree cp_fold_non_odr_use                        (tree, bool);
 extern tree cp_fully_fold                      (tree);
-extern tree cp_fully_fold_init                 (tree);
+extern tree cp_fully_fold_init                 (tree, tree = NULL_TREE);
 extern tree predeclare_vla                     (tree);
 extern void clear_fold_cache                   (void);
 extern tree lookup_hotness_attribute           (tree);
@@ -9274,6 +9274,8 @@ extern tree cp_fold_immediate                     (tree 
*, mce_value,
                                                 tree = current_function_decl);
 extern void process_and_check_pending_immediate_escalating_fns ();
 extern bool is_invisiref_parm                  (const_tree);
+extern void taking_address_of_imm_fn_error     (tree, tree,
+                                                diagnostics::kind = 
diagnostics::kind::error);
 
 /* in name-lookup.cc */
 extern tree strip_using_decl                    (tree);
@@ -9546,7 +9548,7 @@ extern tree get_null_reflection () ATTRIBUTE_PURE;
 extern bool null_reflection_p (const_tree) ATTRIBUTE_PURE;
 extern void rewrite_null_reflection (tree &);
 extern tree splice (tree);
-extern bool check_out_of_consteval_use (tree, bool = true);
+extern bool check_out_of_consteval_use (tree, tree = NULL_TREE);
 extern bool consteval_only_p (tree);
 extern bool compare_reflections (tree, tree) ATTRIBUTE_PURE;
 extern bool valid_splice_type_p (const_tree) ATTRIBUTE_PURE;
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 067ae20c828..6d439334a9f 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8928,7 +8928,7 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const 
char* asmspec)
   if (DECL_FUNCTION_SCOPE_P (decl) && !TREE_STATIC (decl))
     return;
 
-  /* Don't output reflection variables.  */
+  /* Don't output immediate variables.  */
   if (consteval_only_p (decl))
     {
       /* Disable assemble_variable.  */
@@ -10037,7 +10037,6 @@ cp_finish_decl (tree decl, tree init, bool 
init_const_expr_p,
            }
          /* And make sure it's in the symbol table for
             c_parse_final_cleanups to find.  */
-         gcc_checking_assert (!consteval_only_p (decl));
          varpool_node::get_create (decl);
        }
 
diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 8bf518df64f..0bb6f491f22 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -8842,14 +8842,31 @@ splice (tree refl)
 
 static bool consteval_only_p (tree, hash_set<tree> &);
 
+/* If T is the address of, or a pointer to member for, an immediate
+   function, return that function.  Otherwise return NULL_TREE.  */
+
+static tree
+immediate_fn_of (tree t)
+{
+  tree fn;
+  STRIP_ANY_LOCATION_WRAPPER (t);
+  if (TREE_CODE (t) == ADDR_EXPR && !ADDR_EXPR_DENOTES_CALL_P (t))
+    fn = TREE_OPERAND (t, 0);
+  else if (TREE_CODE (t) == PTRMEM_CST)
+    fn = PTRMEM_CST_MEMBER (t);
+  else
+    return NULL_TREE;
+
+  if (TREE_CODE (fn) == FUNCTION_DECL && DECL_IMMEDIATE_FUNCTION_P (fn))
+    return fn;
+  return NULL_TREE;
+}
+
 /* True if T is a consteval-only value as per [expr.const.const]/1:
    A consteval-only value is either
    -- a reflection value that is not the null reflection value or
    -- a pointer or pointer-to-member that points to an immediate function
-      or to or past the end of an immediate object.
-
-   This function doesn't look for an immediate function; for that, see
-   find_immediate_fndecl.  */
+      or to or past the end of an immediate object.  */
 
 static bool
 consteval_only_value_p (tree t, hash_set<tree> &seen)
@@ -8859,6 +8876,9 @@ consteval_only_value_p (tree t, hash_set<tree> &seen)
   if (REFLECT_EXPR_P (t) && !null_reflection_p (t))
     return true;
 
+  if (immediate_fn_of (t))
+    return true;
+
   switch (TREE_CODE (t))
     {
     case ADDR_EXPR:
@@ -8872,21 +8892,37 @@ consteval_only_value_p (tree t, hash_set<tree> &seen)
   return false;
 }
 
+/* Return true if objects of type TYPE can possibly have consteval-only
+   values.  */
+
+static bool
+type_can_have_consteval_only_values (tree type)
+{
+  return (AGGREGATE_TYPE_P (type)
+         || INDIRECT_TYPE_P (type)
+         || REFLECTION_TYPE_P (type));
+}
+
 /* Return true if T is an immediate object as per [expr.const.const]/2:
    An object is an immediate object if its complete object has
    -- a constituent value that is consteval-only or
    -- a constituent reference that refers to an immediate object or
    immediate function.
 
-   Also return true for consteval-only values.  This doesn't check for
-   immediate functions.  */
+   Also return true for consteval-only values.  */
 
 static bool
 consteval_only_p (tree t, hash_set<tree> &seen)
 {
-  if (!flag_reflection || !t || t == error_mark_node)
+  if (!t || t == error_mark_node)
     return false;
 
+  /* Bail early if a tree of these types can't be consteval-only.  */
+  if (!TYPE_P (t))
+    if (tree type = TREE_TYPE (t))
+      if (!type_can_have_consteval_only_values (type))
+       return false;
+
   /* Say that the wrapper itself is consteval-only so that
      check_out_of_consteval_use_r returns the tree carrying the location.  */
   STRIP_ANY_LOCATION_WRAPPER (t);
@@ -8907,7 +8943,23 @@ consteval_only_p (tree t, hash_set<tree> &seen)
   /* Pull out the initializer.  Don't call fold_non_dependent_expr and
      similar here because that could prematurely instantiate things.  */
   if (VAR_P (t))
-    t = DECL_INITIAL (t);
+    {
+      /* Vtables, VTTs and typeinfo objects aren't objects with constituent
+        values.  We mark them as DECL_DECLARED_CONSTEXPR_P so that the
+        constexpr code can evaluate them.  Note that consteval entries are
+        cleared before they're emitted in clear_consteval_vfns.  */
+      if (DECL_VIRTUAL_P (t)
+         || DECL_TINFO_P (t)
+         /* Only objects associated with constexpr variables or template
+            parameter objects can be immediate objects ([expr.const.const]/3).
+            get_template_parm_object marks DECL_NTTP_OBJECT_P as
+            DECL_DECLARED_CONSTEXPR_P.  */
+         || !DECL_DECLARED_CONSTEXPR_P (t))
+       return false;
+      t = (DECL_NTTP_OBJECT_P (t)
+          ? tparm_object_argument (t)
+          : DECL_INITIAL (t));
+    }
 
   if (t && TREE_CODE (t) == TARGET_EXPR)
     t = TARGET_EXPR_INITIAL (t);
@@ -8928,6 +8980,9 @@ consteval_only_p (tree t, hash_set<tree> &seen)
 bool
 consteval_only_p (tree t)
 {
+  if (cxx_dialect < cxx20)
+    return false;
+
   hash_set<tree> seen;
   return consteval_only_p (t, seen);
 }
@@ -9094,13 +9149,14 @@ check_out_of_consteval_use_r (tree *tp, int 
*walk_subtrees, void *pset_)
        auto z = r;
      }
 
-   is OK.  If COMPLAIN, emit an error; otherwise we're in the search-only
-   mode.  Return true if we found a problematic expression.  */
+   is OK.  ORIGIN, if non-null, is the VAR_DECL whose initializer is being
+   checked, or the immediate invocation that produced EXPR.  Return true if
+   we found a problematic expression.  */
 
 bool
-check_out_of_consteval_use (tree expr, bool complain/*=true*/)
+check_out_of_consteval_use (tree expr, tree origin/*=NULL_TREE*/)
 {
-  if (!flag_reflection || in_immediate_context () || expr == NULL_TREE)
+  if (cxx_dialect < cxx20 || in_immediate_context () || expr == NULL_TREE)
     return false;
 
   if (VAR_P (expr) && DECL_DECLARED_CONSTEXPR_P (expr))
@@ -9109,10 +9165,33 @@ check_out_of_consteval_use (tree expr, bool 
complain/*=true*/)
   hash_set<tree> pset;
   if (tree t = cp_walk_tree (&expr, check_out_of_consteval_use_r, &pset, 
&pset))
     {
-      if (complain)
-       error_at (cp_expr_loc_or_loc (t, cp_expr_loc_or_input_loc (expr)),
-                 "consteval-only value outside an immediate function "
-                 "context");
+      auto_diagnostic_group d;
+      auto kind = diagnostics::kind::note;
+      tree imm_fn = immediate_fn_of (t);
+
+      if (origin && VAR_P (origin))
+       {
+         error_at (DECL_SOURCE_LOCATION (origin),
+                   "initializer of non-%<constexpr%> variable %qD uses "
+                   "a consteval-only value", origin);
+         if (potential_constant_expression (expr))
+           inform (DECL_SOURCE_LOCATION (origin), "add %<constexpr%>");
+       }
+      else if (origin || !imm_fn)
+       {
+         const location_t loc
+           = (origin
+              ? cp_expr_loc_or_input_loc (origin)
+              : cp_expr_loc_or_loc (t, cp_expr_loc_or_input_loc (expr)));
+         error_at (loc, "consteval-only value outside an immediate "
+                   "function context");
+       }
+      else
+       kind = diagnostics::kind::error;
+
+      if (imm_fn)
+       taking_address_of_imm_fn_error (t, imm_fn, kind);
+
       return true;
     }
 
diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc
index 6f17ce8c1bc..85d668c3b39 100644
--- a/gcc/cp/typeck2.cc
+++ b/gcc/cp/typeck2.cc
@@ -1130,26 +1130,30 @@ store_init_value (tree decl, tree init, vec<tree, 
va_gc>** cleanups, int flags)
     }
   /* Don't fold initializers of automatic variables in constexpr functions,
      that might fold away something that needs to be diagnosed at constexpr
-     evaluation time.  */
-  if (!current_function_decl
-      || !maybe_constexpr_fn (current_function_decl)
-      || TREE_STATIC (decl))
-    value = cp_fully_fold_init (value);
+     evaluation time, and don't fold initializers of constexpr variables
+     because they have already been constant-evaluated and we don't want the
+     "uses a consteval-only value" error because the initializer is an MCE
+     context.  */
+  if ((!current_function_decl
+       || !maybe_constexpr_fn (current_function_decl)
+       || TREE_STATIC (decl))
+      && !DECL_DECLARED_CONSTEXPR_P (decl))
+    value = cp_fully_fold_init (value, decl);
 
   /* Handle aggregate NSDMI in non-constant initializers, too.  */
   value = replace_placeholders (value, decl);
 
   /* Detect stuff like 'info r = ^^int;' outside a manifestly
-     constant-evaluated context.  */
-  if (flag_reflection
-      && !processing_template_decl
+     constant-evaluated context.  Also detect 'auto p = &consteval_fn'.  */
+  if (!processing_template_decl
+      && value != error_mark_node
       && !DECL_DECLARED_CONSTEXPR_P (decl))
     {
       const bool mce_p
        = (decl_maybe_constant_var_p (decl)
           || (TREE_STATIC (decl)
               && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)));
-      bool bad = check_out_of_consteval_use (value, /*complain=*/false);
+      bool bad = check_out_of_consteval_use (value, decl);
       /* A non-constexpr variable at namespace scope with a constant
         initializer has constant initialization, so we check the folded
         value not to wrongly reject "int e = (^^int, 42);".  For non-static
@@ -1163,16 +1167,9 @@ store_init_value (tree decl, tree init, vec<tree, 
va_gc>** cleanups, int flags)
         have escalated and so we may find ourselves in an immediate
         context now.  */
       if (!bad && !mce_p && value != init)
-       bad = check_out_of_consteval_use (init, /*complain=*/false);
+       bad = check_out_of_consteval_use (init, decl);
       if (bad)
-       {
-         auto_diagnostic_group d;
-         error_at (DECL_SOURCE_LOCATION (decl),
-                   "%qD is initialized with a consteval-only value but is "
-                   "not declared %<constexpr%>", decl);
-         inform (DECL_SOURCE_LOCATION (decl), "add %<constexpr%>");
-         value = error_mark_node;
-       }
+       value = error_mark_node;
     }
 
   /* A COMPOUND_LITERAL_P CONSTRUCTOR is the syntactic form; by the time we get
diff --git a/gcc/testsuite/g++.dg/cpp23/consteval-if12.C 
b/gcc/testsuite/g++.dg/cpp23/consteval-if12.C
index 03de87c3e09..782945ca2bf 100644
--- a/gcc/testsuite/g++.dg/cpp23/consteval-if12.C
+++ b/gcc/testsuite/g++.dg/cpp23/consteval-if12.C
@@ -19,13 +19,13 @@ bar ()
 {
   S s;
   if consteval {                       // { dg-warning "'if consteval' only 
available with" "" { target c++20_only } }
-    constexpr auto fn1 = foo;          // { dg-error "constant evaluation 
returns address of immediate function" }
-    constexpr auto fn2 = &foo;         // { dg-error "constant evaluation 
returns address of immediate function" }
-    constexpr auto fn3 = &S::foo;      // { dg-error "constant evaluation 
returns address of immediate function" }
-    constexpr auto fn4 = &S::bar;      // { dg-error "constant evaluation 
returns address of immediate function" }
-    constexpr auto fn5 = baz ();       // { dg-error "immediate evaluation 
returns address of immediate function" }
-    constexpr auto fn6 = qux ();       // { dg-error "immediate evaluation 
returns address of immediate function" }
-    constexpr auto fn7 = corge ();     // { dg-error "immediate evaluation 
returns address of immediate function" }
+    constexpr auto fn1 = foo;
+    constexpr auto fn2 = &foo;
+    constexpr auto fn3 = &S::foo;
+    constexpr auto fn4 = &S::bar;
+    constexpr auto fn5 = baz ();
+    constexpr auto fn6 = qux ();
+    constexpr auto fn7 = corge ();
     return fn1 () + fn2 () + (s.*fn3) () + (s.*fn4) () + fn5 () + (s.*fn6) () 
+ (s.*fn7) ();
   }
   return 0;
diff --git a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C 
b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C
index d32955551b5..5f0e90f6eb2 100644
--- a/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C
+++ b/gcc/testsuite/g++.dg/cpp23/feat-cxx2b.C
@@ -481,8 +481,8 @@
 
 #ifndef __cpp_consteval
 #  error "__cpp_consteval"
-#elif __cpp_consteval != 202211L
-#  error "__cpp_consteval != 202211L"
+#elif __cpp_consteval != 202606L
+#  error "__cpp_consteval != 202606L"
 #endif
 
 #ifndef __cpp_concepts
diff --git a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C 
b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
index 8925c656d24..1a9a939ddb3 100644
--- a/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
+++ b/gcc/testsuite/g++.dg/cpp26/feat-cxx26.C
@@ -481,8 +481,8 @@
 
 #ifndef __cpp_consteval
 #  error "__cpp_consteval"
-#elif __cpp_consteval != 202211L
-#  error "__cpp_consteval != 202211L"
+#elif __cpp_consteval != 202606L
+#  error "__cpp_consteval != 202606L"
 #endif
 
 #ifndef __cpp_concepts
diff --git a/gcc/testsuite/g++.dg/cpp29/feat-cxx29.C 
b/gcc/testsuite/g++.dg/cpp29/feat-cxx29.C
index cb20e0488b4..fef159ccf7b 100644
--- a/gcc/testsuite/g++.dg/cpp29/feat-cxx29.C
+++ b/gcc/testsuite/g++.dg/cpp29/feat-cxx29.C
@@ -481,8 +481,8 @@
 
 #ifndef __cpp_consteval
 #  error "__cpp_consteval"
-#elif __cpp_consteval != 202211L
-#  error "__cpp_consteval != 202211L"
+#elif __cpp_consteval != 202606L
+#  error "__cpp_consteval != 202606L"
 #endif
 
 #ifndef __cpp_concepts
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C
index 5e7b208113f..ee3edf56cc0 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop1.C
@@ -16,7 +16,8 @@ constexpr auto a0 = f0 (3);
 
 // As a consequence of f0<int> being promoted to an immediate function, we
 // can't take its address.
-auto p0 = &f0<int>; // { dg-error "taking address of an immediate function" }
+auto p0 = &f0<int>; // { dg-error ".p0. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 
 template <typename T>
 constexpr int
@@ -30,7 +31,8 @@ constexpr auto a1 = f1 (3);
 
 // As a consequence of f1<int> being promoted to an immediate function, we
 // can't take its address.
-auto p1 = &f1<int>; // { dg-error "taking address of an immediate function" }
+auto p1 = &f1<int>; // { dg-error ".p1. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 
 template <typename T>
 constexpr int
@@ -61,7 +63,7 @@ f4 (T t)
   return t;
 }
 
-auto p6 = &f4<int>; // { dg-error "taking address of an immediate function" }
+auto p6 = &f4<int>; // { dg-error ".p6. uses a consteval-only value" }
 
 static_assert (f4 (42) == 42);
 
@@ -146,14 +148,16 @@ auto l1 = [](int i) constexpr {
   return id (0);
 };
 
-int (*pl1)(int) = l1; // { dg-error "call to consteval function|returns 
address of immediate function" }
+int (*pl1)(int) = l1; // { dg-error ".pl1. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 
 auto l2 = [](int i) {
   int t = id (i);
   return id (0);
 };
 
-int (*pl2)(int) = l2; // { dg-error "call to consteval function|returns 
address of immediate function" }
+int (*pl2)(int) = l2; // { dg-error ".pl2. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 
 // Not defined = won't produce a constant expression.
 consteval int undef (); // { dg-warning "used but never defined" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C
index 4e33e6e3d0e..d7c570a9b8d 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop10.C
@@ -26,7 +26,8 @@ f3 (auto)
   return f2<int>(); // { dg-message "contains an immediate-escalating 
expression .id\\(non_const\\)." }
 }
 
-auto a = &f3<int>; // { dg-error "taking address of an immediate function" }
+auto a = &f3<int>; // { dg-error ".a. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 
 void
 g (int i)
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C
index 3ceb05e41f4..32dc7c405e9 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop19.C
@@ -4,4 +4,5 @@
 consteval int g(int p) { return p; }
 template<typename T> constexpr auto f(T) { return g; }
 int r = f(1)(2);      // proposed ok
-int s = f(1)(2) + r;  // { dg-error "call to consteval function|returns 
address of immediate function" }
+int s = f(1)(2) + r;  // { dg-error ".s. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C
index 30129a4a266..91b55d2293f 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop2.C
@@ -11,7 +11,8 @@ constexpr int f(T t) {
 }
 
 auto a = &f<char>;              // OK, f<char> is not an immediate function
-auto b = &f<int>;               // { dg-error "taking address of an immediate 
function" }
+auto b = &f<int>;               // { dg-error "variable .b. uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 
 static_assert(f(3) == 6);       // OK
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C
index f1bb08e2dba..ff8f260a177 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop20.C
@@ -13,7 +13,8 @@ f (auto i)
 void
 g ()
 {
-  auto p = &f<int>; // { dg-error "taking address" }
+  auto p = &f<int>; // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
   decltype(&f<int>) x;
   if consteval {
     auto q = &f<int>;
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C
index 9c4a23389ce..4e6f1c87d31 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval-prop9.C
@@ -61,7 +61,8 @@ static auto p6 = &f7<int>;
 void
 g ()
 {
-  static auto q1 = &f4<int>; // { dg-error "taking address" }
+  static auto q1 = &f4<int>; // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
   static auto q2 = &f6<int>;
   static auto q3 = &f7<int>;
 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval20.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval20.C
index ba3613318e6..9c3540766cf 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval20.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval20.C
@@ -10,14 +10,18 @@ constexpr S s;
 int
 bar ()
 {
-  auto c = &S::foo;                    // { dg-error "taking address of an 
immediate function" }
-  constexpr auto d = &S::foo;          // { dg-error "constant evaluation 
returns address of immediate function" }
-  static auto e = &S::foo;             // { dg-error "taking address of an 
immediate function" }
-  return (s.*&S::foo) ();              // { dg-error "taking address of an 
immediate function" }
+  auto c = &S::foo;                    // { dg-error ".c. uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+  constexpr auto d = &S::foo;
+  static auto e = &S::foo;             // { dg-error ".e. uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+  return (s.*&S::foo) ();              // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 }
 
-constexpr auto a = &S::foo;            // { dg-error "constant evaluation 
returns address of immediate function" }
-auto b = &S::foo;                      // { dg-error "taking address of an 
immediate function" }
+constexpr auto a = &S::foo;
+auto b = &S::foo;                      // { dg-error ".b. uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 
 consteval int
 baz ()
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval22.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval22.C
index 5c3637189dc..49a6facdd41 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval22.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval22.C
@@ -30,5 +30,5 @@ baz ()
 
 static_assert (baz () == 3);
 
-constexpr P a = foo ();                // { dg-error "immediate evaluation 
returns address of immediate function" }
-constexpr P b = bar ();                // { dg-error "immediate evaluation 
returns address of immediate function" }
+constexpr P a = foo ();
+constexpr P b = bar ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval24.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval24.C
index 22a9657e4a1..51e142fe074 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval24.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval24.C
@@ -17,14 +17,14 @@ consteval int
 bar ()
 {
   S s;
-  constexpr auto fn1 = foo;            // { dg-error "constant evaluation 
returns address of immediate function" }
-  constexpr auto fn2 = &foo;           // { dg-error "constant evaluation 
returns address of immediate function" }
-  constexpr auto fn3 = &S::foo;                // { dg-error "constant 
evaluation returns address of immediate function" }
-  constexpr auto fn4 = &S::bar;                // { dg-error "constant 
evaluation returns address of immediate function" }
-  constexpr auto fn5 = baz ();         // { dg-error "immediate evaluation 
returns address of immediate function" }
-  constexpr auto fn6 = qux ();         // { dg-error "immediate evaluation 
returns address of immediate function" }
-  constexpr auto fn7 = corge ();       // { dg-error "immediate evaluation 
returns address of immediate function" }
+  constexpr auto fn1 = foo;
+  constexpr auto fn2 = &foo;
+  constexpr auto fn3 = &S::foo;
+  constexpr auto fn4 = &S::bar;
+  constexpr auto fn5 = baz ();
+  constexpr auto fn6 = qux ();
+  constexpr auto fn7 = corge ();
   return fn1 () + fn2 () + (s.*fn3) () + (s.*fn4) () + fn5 () + (s.*fn6) () + 
(s.*fn7) ();
 }
 
-auto a = bar ();               // { dg-error "bar" }
+auto a = bar ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval3.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval3.C
index 1199e9db623..d144c662488 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval3.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval3.C
@@ -20,9 +20,11 @@ int e = f6 (d);              // { dg-error "the value of 'd' 
is not usable in a constant exp
 constexpr int f7 (int x) { return f6 (x); }    // { dg-error "'x' is not a 
constant expression|call to consteval function" }
 constexpr int f = f7 (5);
 using fnptr = int (int);
-fnptr *g = f6;         // { dg-error "taking address of an immediate function 
'consteval int f6\\(int\\)'" }
+fnptr *g = f6;         // { dg-error ".g. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function 'consteval int 
f6\\(int\\)'" "" { target *-*-* } .-1 }
 int f8 (fnptr *);
-int h = f8 (f6);       // { dg-error "taking address of an immediate function 
'consteval int f6\\(int\\)'" }
+int h = f8 (f6);       // { dg-error ".h. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function 'consteval int 
f6\\(int\\)'" "" { target *-*-* } .-1 }
 consteval constexpr int f9 () { return 0; }    // { dg-error "both 'constexpr' 
and 'consteval' specified" }
 constexpr consteval int f10 () { return 0; }   // { dg-error "both 'constexpr' 
and 'consteval' specified" }
 consteval consteval int f11 () { return 0; }   // { dg-error "duplicate 
'consteval'" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval32.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval32.C
index f1de63e41b9..5d512d0abfe 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval32.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval32.C
@@ -1,4 +1,5 @@
 // { dg-do compile { target c++20 } }
 
 consteval int foo ()  { return 42; }
-int bar () { return (*(&foo)) (); } // { dg-error "taking address" }
+int bar () { return (*(&foo)) (); } // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
diff --git a/gcc/testsuite/g++.dg/cpp2a/consteval7.C 
b/gcc/testsuite/g++.dg/cpp2a/consteval7.C
index 74996d31a82..62926264d9f 100644
--- a/gcc/testsuite/g++.dg/cpp2a/consteval7.C
+++ b/gcc/testsuite/g++.dg/cpp2a/consteval7.C
@@ -3,11 +3,11 @@
 
 consteval int foo () { return 42; }
 consteval auto bar () { return foo; }
-constexpr auto a = bar ();     // { dg-error "immediate evaluation returns 
address of immediate function 'consteval int foo\\(\\)'" }
+constexpr auto a = bar ();
 struct S { int b; int (*c) (); };
 consteval S baz () { return { 5, foo }; }
 consteval int qux () { S s = baz (); return s.b + s.c (); }
-consteval int quux () { constexpr S s = baz (); return s.b + s.c (); } // { 
dg-error "immediate evaluation returns address of immediate function 'consteval 
int foo\\(\\)'" }
-constexpr auto d = baz ();     // { dg-error "immediate evaluation returns 
address of immediate function 'consteval int foo\\(\\)'" }
+consteval int quux () { constexpr S s = baz (); return s.b + s.c (); }
+constexpr auto d = baz ();
 constexpr auto e = qux ();
-constexpr auto f = quux ();    // { dg-error "quux" }
+constexpr auto f = quux ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C 
b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
index 3c43e9dae46..3498981098e 100644
--- a/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
+++ b/gcc/testsuite/g++.dg/cpp2a/feat-cxx2a.C
@@ -481,8 +481,8 @@
 
 #ifndef __cpp_consteval
 #  error "__cpp_consteval"
-#elif __cpp_consteval != 202211L
-#  error "__cpp_consteval != 202211L"
+#elif __cpp_consteval != 202606L
+#  error "__cpp_consteval != 202606L"
 #endif
 
 #ifndef __cpp_concepts
diff --git a/gcc/testsuite/g++.dg/cpp2a/srcloc20.C 
b/gcc/testsuite/g++.dg/cpp2a/srcloc20.C
index e99f1dcf7c4..aa6ab6fd9f7 100644
--- a/gcc/testsuite/g++.dg/cpp2a/srcloc20.C
+++ b/gcc/testsuite/g++.dg/cpp2a/srcloc20.C
@@ -32,13 +32,16 @@ namespace std {
 
 using namespace std;
 
-auto a = source_location::current;             // { dg-error "taking address 
of an immediate function" }
-constexpr auto b = &source_location::current;  // { dg-error "constant 
evaluation returns address of immediate function" }
+auto a = source_location::current;             // { dg-error ".a. uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+constexpr auto b = &source_location::current;
 
 void
 foo ()
 {
-  auto c = &source_location::current;          // { dg-error "taking address 
of an immediate function" }
-  constexpr auto d = source_location::current; // { dg-error "constant 
evaluation returns address of immediate function" }
-  static auto e = source_location::current;    // { dg-error "taking address 
of an immediate function" }
+  auto c = &source_location::current;          // { dg-error ".c. uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+  constexpr auto d = source_location::current;
+  static auto e = source_location::current;    // { dg-error ".e. uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
 }
diff --git a/gcc/testsuite/g++.dg/reflect/consteval-prop1.C 
b/gcc/testsuite/g++.dg/reflect/consteval-prop1.C
new file mode 100644
index 00000000000..a5a68143424
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/consteval-prop1.C
@@ -0,0 +1,20 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+// Like consteval-prop20.C but using Reflection.
+
+consteval auto id(int i) { return ^^int; }
+
+constexpr auto
+f (auto i)
+{
+  return id (i);
+}
+
+void
+g ()
+{
+  auto p = &f<int>; // { dg-error ".p. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/diag3.C 
b/gcc/testsuite/g++.dg/reflect/diag3.C
index 2be45cb962f..ad17e077950 100644
--- a/gcc/testsuite/g++.dg/reflect/diag3.C
+++ b/gcc/testsuite/g++.dg/reflect/diag3.C
@@ -2,31 +2,31 @@
 // { dg-additional-options "-freflection" }
 // Test that we suggest adding "constexpr" (where allowed).
 
-auto foo = ^^int;  // { dg-error ".foo. is initialized with a consteval-only 
value" }
+auto foo = ^^int;  // { dg-error ".foo. uses a consteval-only value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
-constinit auto foo_ = ^^int; // { dg-error ".foo_. is initialized with a 
consteval-only value" }
+constinit auto foo_ = ^^int; // { dg-error ".foo_. uses a consteval-only 
value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
 constexpr auto foo__ = ^^int;
-thread_local auto tfoo = ^^int;  // { dg-error ".tfoo. is initialized with a 
consteval-only value" }
+thread_local auto tfoo = ^^int;  // { dg-error ".tfoo. uses a consteval-only 
value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
-thread_local constinit auto tfoo_ = ^^int; // { dg-error ".tfoo_. is 
initialized with a consteval-only value" }
+thread_local constinit auto tfoo_ = ^^int; // { dg-error ".tfoo_. uses a 
consteval-only value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
 thread_local constexpr auto tfoo__ = ^^int;
 
 void
 f ()
 {
-  auto ref = ^^int;  // { dg-error ".ref. is initialized with a consteval-only 
value" }
+  auto ref = ^^int;  // { dg-error ".ref. uses a consteval-only value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
   constexpr auto ref_ = ^^int;
-  static auto sref = ^^int;  // { dg-error ".sref. is initialized with a 
consteval-only value" }
+  static auto sref = ^^int;  // { dg-error ".sref. uses a consteval-only 
value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
-  static auto constinit sref_ = ^^int; // { dg-error ".sref_. is initialized 
with a consteval-only value" }
+  static auto constinit sref_ = ^^int; // { dg-error ".sref_. uses a 
consteval-only value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
   static auto constexpr sref__ = ^^int;
-  thread_local auto tref = ^^int; // { dg-error ".tref. is initialized with a 
consteval-only value" }
+  thread_local auto tref = ^^int; // { dg-error ".tref. uses a consteval-only 
value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
-  thread_local constinit auto tref_ = ^^int; // { dg-error ".tref_. is 
initialized with a consteval-only value" }
+  thread_local constinit auto tref_ = ^^int; // { dg-error ".tref_. uses a 
consteval-only value" }
 // { dg-message "add .constexpr." "" { target *-*-* } .-1 }
   thread_local constexpr auto tref__ = ^^int;
 }
diff --git a/gcc/testsuite/g++.dg/reflect/init4.C 
b/gcc/testsuite/g++.dg/reflect/init4.C
index f337def032c..eafb5ef7a72 100644
--- a/gcc/testsuite/g++.dg/reflect/init4.C
+++ b/gcc/testsuite/g++.dg/reflect/init4.C
@@ -49,7 +49,7 @@ constexpr G g;
 struct H {
   info (*fp)();
 };
-constexpr H h{foo};    // { dg-bogus "returns address" "" { xfail *-*-* } }
+constexpr H h{foo};    // { dg-bogus "returns address" }
 
 union U {
   int n;
diff --git a/gcc/testsuite/g++.dg/reflect/init7.C 
b/gcc/testsuite/g++.dg/reflect/init7.C
index c9155e2d434..cf243c4eaa2 100644
--- a/gcc/testsuite/g++.dg/reflect/init7.C
+++ b/gcc/testsuite/g++.dg/reflect/init7.C
@@ -5,25 +5,25 @@
 
 using info = decltype(^^int);
 
-info r1 = ^^int;  // { dg-error ".r1. is initialized with a consteval-only 
value but is not declared .constexpr." }
-const info r2 = ^^int;  // { dg-error ".r2. is initialized with a 
consteval-only value but is not declared .constexpr." }
+info r1 = ^^int;  // { dg-error ".r1. uses a consteval-only value" }
+const info r2 = ^^int;  // { dg-error ".r2. uses a consteval-only value" }
 
 constexpr info r3 = ^^int;
-constinit info r4 = ^^int;  // { dg-error ".r4. is initialized with a 
consteval-only value but is not declared .constexpr." }
-const info *const p1 = &r3;  // { dg-error ".p1. is initialized with a 
consteval-only value but is not declared .constexpr." }
+constinit info r4 = ^^int;  // { dg-error ".r4. uses a consteval-only value" }
+const info *const p1 = &r3;  // { dg-error ".p1. uses a consteval-only value" }
 info *p2;
-const info &q = r3;  // { dg-error ".q. is initialized with a consteval-only 
value but is not declared .constexpr." }
+const info &q = r3;  // { dg-error ".q. uses a consteval-only value" }
 
 void
 g ()
 {
-  info l1 = ^^int;  // { dg-error ".l1. is initialized with a consteval-only 
value but is not declared .constexpr." }
-  const info l2 = ^^int;  // { dg-error ".l2. is initialized with a 
consteval-only value but is not declared .constexpr." }
+  info l1 = ^^int;  // { dg-error ".l1. uses a consteval-only value" }
+  const info l2 = ^^int;  // { dg-error ".l2. uses a consteval-only value" }
   constexpr info l3 = ^^int;
-  static info l4 = ^^int;  // { dg-error ".l4. is initialized with a 
consteval-only value but is not declared .constexpr." }
-  static const info l5 = ^^int;  // { dg-error ".l5. is initialized with a 
consteval-only value but is not declared .constexpr." }
+  static info l4 = ^^int;  // { dg-error ".l4. uses a consteval-only value" }
+  static const info l5 = ^^int;  // { dg-error ".l5. uses a consteval-only 
value" }
   static constexpr info l6 = ^^int;
-  static constinit info l7 = ^^int;  // { dg-error ".l7. is initialized with a 
consteval-only value but is not declared .constexpr." }
+  static constinit info l7 = ^^int;  // { dg-error ".l7. uses a consteval-only 
value" }
 }
 
 consteval void
diff --git a/gcc/testsuite/g++.dg/reflect/parm4.C 
b/gcc/testsuite/g++.dg/reflect/parm4.C
index bb733f17233..ef55e473a06 100644
--- a/gcc/testsuite/g++.dg/reflect/parm4.C
+++ b/gcc/testsuite/g++.dg/reflect/parm4.C
@@ -19,7 +19,7 @@ g (S s)
   constexpr int i1 = s.mfn1 (^^int);
   constexpr int i2 = s.mfn2 (^^int);
   int i3 = s.mfn3 (42, ^^int);  // { dg-error "consteval-only value" }
-  info i4 = s.mfn4 ();
+  info i4 = s.mfn4 ();         // { dg-error ".i4. uses a consteval-only 
value" "" { target { implicit_constexpr } } }
 }
 
 template<typename T>
diff --git a/gcc/testsuite/g++.dg/reflect/value1.C 
b/gcc/testsuite/g++.dg/reflect/value1.C
index 1d6d7d59098..40614c77cdd 100644
--- a/gcc/testsuite/g++.dg/reflect/value1.C
+++ b/gcc/testsuite/g++.dg/reflect/value1.C
@@ -16,13 +16,13 @@ struct S { info r; };
 struct DS : S { int i; };
 constexpr DS cds{ { ^^int }, 0 };
 DS dsn{ { info{} }, 0 };
-DS ds{ { ^^int }, 0 }; // { dg-error "initialized with a consteval-only value" 
}
-auto basep1 = (S *) &cds; // { dg-error "initialized with a consteval-only 
value" }
+DS ds{ { ^^int }, 0 }; // { dg-error "uses a consteval-only value" }
+auto basep1 = (S *) &cds; // { dg-error "uses a consteval-only value" }
 constexpr auto basep2 = (S *) &cds;
 
 struct O { consteval int f() const { return 1; } };
-auto pm1 = &O::f;            // { dg-error "address of an immediate function" }
-constexpr auto pm2 = &O::f;   // { dg-bogus "returns address" "" { xfail *-*-* 
} }
+auto pm1 = &O::f;            // { dg-error "uses a consteval-only value" }
+constexpr auto pm2 = &O::f;
 
 struct C {
   info r;
@@ -30,14 +30,14 @@ struct C {
 };
 constexpr C c1(^^int);
 C c2(info{});
-C c3(^^int);           // { dg-error "initialized with a consteval-only value" 
}
+C c3(^^int);           // { dg-error "uses a consteval-only value" }
 
 struct CB : C {
   constexpr CB(info x) : C(x) {}
 };
 constexpr CB cb1(^^int);
 CB cb2(info{});
-CB cb3(^^int);         // { dg-error "initialized with a consteval-only value" 
}
+CB cb3(^^int);         // { dg-error "uses a consteval-only value" }
 
 struct Deleg {
   info r;
@@ -71,13 +71,13 @@ struct N4 {
   constexpr N4(info x) : i(x) {}
 };
 constexpr N4 cn4a;
-N4 n4a;            // { dg-error "initialized with a consteval-only value" }
+N4 n4a;            // { dg-error "uses a consteval-only value" }
 
 struct N5 {
   static constexpr info si = ^^int;
   static info si2;
 };
-info N5::si2 = ^^int;  // { dg-error "initialized with a consteval-only value" 
}
+info N5::si2 = ^^int;  // { dg-error "uses a consteval-only value" }
 
 struct L {
   static constexpr info si = info{};
@@ -92,10 +92,10 @@ struct V {
 };
 auto v1 = V{info{}, 42};
 constexpr auto v2 = V{^^int, 42};
-auto v3 = V{^^int, 42};          // { dg-error "initialized with a 
consteval-only value" }
+auto v3 = V{^^int, 42};          // { dg-error "uses a consteval-only value" }
 
 struct Wrapper { const info &r; };
-Wrapper w1{ ^^int };       // { dg-error "initialized with a consteval-only 
value" }
+Wrapper w1{ ^^int };       // { dg-error "uses a consteval-only value" }
 constexpr Wrapper w2{ ^^int };
 
 info a;
@@ -113,16 +113,16 @@ auto normal() -> void {
 }
 
 constexpr auto r = ^^int;
-auto e1 = ^^int; // { dg-error "initialized with a consteval-only value" }
+auto e1 = ^^int; // { dg-error "uses a consteval-only value" }
 auto en = info{};
 
-const info &ref1 = r;      // { dg-error "initialized with a consteval-only 
value" }
+const info &ref1 = r;      // { dg-error "uses a consteval-only value" }
 constexpr const info &ref2 = r;
 
 constexpr info arr[] = { ^^int, ^^char };
 constexpr info e5 = arr[0];
-info e6 = arr[0];    // { dg-error "initialized with a consteval-only value" }
-auto epast1 = arr + 2; // { dg-error "initialized with a consteval-only value" 
}
+info e6 = arr[0];    // { dg-error "uses a consteval-only value" }
+auto epast1 = arr + 2; // { dg-error "uses a consteval-only value" }
 constexpr auto epast2 = arr + 2;
 info narr[] = { info{}, info{} };
 info narr2[3];
@@ -136,34 +136,34 @@ int i1 = (^^int, 42);
 int i2 = (r, 42);
 int i3 = (info{}, 42);
 // No constant initialization, so not MCE.
-int i4 = (r, fn());    // { dg-error "initialized with a consteval-only value" 
}
+int i4 = (r, fn());    // { dg-error "uses a consteval-only value" }
 
 const int &gref = (r, 42);
 
 constexpr N cng{};
-N ng;  // { dg-error "initialized with a consteval-only value" }
-static N nsg;  // { dg-error "initialized with a consteval-only value" }
+N ng;  // { dg-error "uses a consteval-only value" }
+static N nsg;  // { dg-error "uses a consteval-only value" }
 
 constexpr const info *p = &r;
-const info *q = &r;   // { dg-error "initialized with a consteval-only value" }
+const info *q = &r;   // { dg-error "uses a consteval-only value" }
 
 struct Ptr {
   const info *p;
 };
 auto ptr1 = Ptr{ .p = nullptr };
 constexpr auto ptr2 = Ptr{ .p = &r };
-auto ptr3 = Ptr{ .p = &r };    // { dg-error "initialized with a 
consteval-only value" }
+auto ptr3 = Ptr{ .p = &r };    // { dg-error "uses a consteval-only value" }
 
 struct Pair { info r; int i; };
 constexpr Pair p1 = { ^^int, 0 };
 Pair p2 = { info{}, 0 };
-Pair p3 = { ^^int, 0 };          // { dg-error "initialized with a 
consteval-only value" }
-auto [sb1, sb2] = Pair{^^int, 0}; // { dg-error "initialized with a 
consteval-only value" }
+Pair p3 = { ^^int, 0 };          // { dg-error "uses a consteval-only value" }
+auto [sb1, sb2] = Pair{^^int, 0}; // { dg-error "uses a consteval-only value" }
 constexpr auto [sb3, sb4] = Pair{^^int, 0};
 auto [sb5, sb6] = Pair{info{}, 0};
 
 struct Nested { Pair inner; int c; };
-auto ne = Nested{{^^int, 0}, 1};  // { dg-error "initialized with a 
consteval-only value" }
+auto ne = Nested{{^^int, 0}, 1};  // { dg-error "uses a consteval-only value" }
 constexpr auto cne = Nested{{^^int, 0}, 1};
 auto ne2 = Nested{{info{}, 0}, 1};
 constexpr auto cne2 = Nested{{info{}, 0}, 1};
@@ -174,22 +174,22 @@ constexpr auto r1 = getr ();
 auto r2 = getnr ();
 // r3 is an object with a constituent consteval-only value
 // but is not associated with a constexpr variable.
-auto r3 = getr ();       // { dg-error "initialized with a consteval-only 
value" }
+auto r3 = getr ();       // { dg-error "uses a consteval-only value" }
 
 union U { info r; int i; };
 // Only the active member counts here.
 constexpr U u1 = { .i = 0 };
 constexpr U u2 = { .r = ^^int };
 auto u3 = U{ .i = 0 };
-auto u4 = U{ .r = ^^int };     // { dg-error "initialized with a 
consteval-only value" }
+auto u4 = U{ .r = ^^int };     // { dg-error "uses a consteval-only value" }
 auto u5 = U{ .r = info{} };
 
 template<bool B>
 void
 tfn ()
 {
-  info rn = B ? info{} : ^^int;          // { dg-error "initialized with a 
consteval-only value" }
-  info ri = B ? ^^int : info{};          // { dg-error "initialized with a 
consteval-only value" }
+  info rn = B ? info{} : ^^int;          // { dg-error "uses a consteval-only 
value" }
+  info ri = B ? ^^int : info{};          // { dg-error "uses a consteval-only 
value" }
 }
 
 template<bool B>
@@ -245,48 +245,48 @@ g (bool b)
   null = info();
 
   constexpr auto lr = ^^int;
-  auto e2 = ^^int;       // { dg-error "initialized with a consteval-only 
value" }
+  auto e2 = ^^int;       // { dg-error "uses a consteval-only value" }
   auto en = info{};
   static constexpr info sg = ^^int;
-  static info sg2 = ^^int;  // { dg-error "initialized with a consteval-only 
value" }
-  const info &lref1 = r;    // { dg-error "initialized with a consteval-only 
value" }
+  static info sg2 = ^^int;  // { dg-error "uses a consteval-only value" }
+  const info &lref1 = r;    // { dg-error "uses a consteval-only value" }
   constexpr const info &lref2 = r;
 
   // Don't accept these: the "has constant initialization" rule applies to
   // variables at namespace scope only.
-  int e3 = (^^int, 42);            // { dg-error "initialized with a 
consteval-only value" }
-  int e4 = (r, 42);        // { dg-error "initialized with a consteval-only 
value" }
-  int e5 = (r, fn());      // { dg-error "initialized with a consteval-only 
value" }
+  int e3 = (^^int, 42);            // { dg-error "uses a consteval-only value" 
}
+  int e4 = (r, 42);        // { dg-error "uses a consteval-only value" }
+  int e5 = (r, fn());      // { dg-error "uses a consteval-only value" }
   // But these are static.
   static int e6 = (^^int, 42);
   static int e7 = (r, 42);
-  static int e8 = (r, fn());       // { dg-error "initialized with a 
consteval-only value" }
+  static int e8 = (r, fn());       // { dg-error "uses a consteval-only value" 
}
 
   // grok_reference_init turns the init into
   // (const int &) &D.2686 and so store_init_value won't see
   // any consteval-only value.
-  const int &ref = (r, 42);      // { dg-error "initialized with a 
consteval-only value" "" { xfail *-*-* } }
+  const int &ref = (r, 42);      // { dg-error "uses a consteval-only value" 
"" { xfail *-*-* } }
 
-  info rn = b ? info{} : ^^int;          // { dg-error "initialized with a 
consteval-only value" }
-  info ri = b ? ^^int : info{};          // { dg-error "initialized with a 
consteval-only value" }
+  info rn = b ? info{} : ^^int;          // { dg-error "uses a consteval-only 
value" }
+  info ri = b ? ^^int : info{};          // { dg-error "uses a consteval-only 
value" }
 
   constexpr info larr[] = { ^^int, ^^char };
   constexpr info le5 = arr[0];
-  info le6 = arr[0];    // { dg-error "initialized with a consteval-only 
value" }
+  info le6 = arr[0];    // { dg-error "uses a consteval-only value" }
   info lnarr[] = { info{}, info{} };
 
   constexpr const info *lp = &r;
-  const info *lq = &r;   // { dg-error "initialized with a consteval-only 
value" }
+  const info *lq = &r;   // { dg-error "uses a consteval-only value" }
 
   constexpr C lc1(^^int);
   C lc2(info{});
-  C lc3(^^int);                // { dg-error "initialized with a 
consteval-only value" }
+  C lc3(^^int);                // { dg-error "uses a consteval-only value" }
 
   constexpr CB lcb1(^^int);
   CB lcb2(info{});
-  CB lcb3(^^int);              // { dg-error "initialized with a 
consteval-only value" }
+  CB lcb3(^^int);              // { dg-error "uses a consteval-only value" }
 
-  Wrapper lw1{ ^^int };            // { dg-error "initialized with a 
consteval-only value" }
+  Wrapper lw1{ ^^int };            // { dg-error "uses a consteval-only value" 
}
   // w2 at block scope has this initializer:
   // {.r=(<<< Unknown tree: lang_type >>> &) &_ZGRL2w2_}
   // which is reduced_constant_expression_p but here we have
@@ -298,39 +298,39 @@ g (bool b)
   constexpr Wrapper lw2{ ^^int }; // { dg-error "not a constant expression" }
 
   constexpr N lcng{};
-  N lng;       // { dg-error "initialized with a consteval-only value" }
+  N lng;       // { dg-error "uses a consteval-only value" }
 
   constexpr Pair p4 = { ^^int, 0 };
   Pair p5 = { info{}, 0 };
-  Pair p6 = { ^^int, 0 };        // { dg-error "initialized with a 
consteval-only value" }
-  auto [lsb1, lsb2] = Pair{^^int, 0}; // { dg-error "initialized with a 
consteval-only value" }
+  Pair p6 = { ^^int, 0 };        // { dg-error "uses a consteval-only value" }
+  auto [lsb1, lsb2] = Pair{^^int, 0}; // { dg-error "uses a consteval-only 
value" }
   constexpr auto [lsb3, lsb4] = Pair{^^int, 0};
   auto [lsb5, lsb6] = Pair{info{}, 0};
 
   auto lptr1 = Ptr{ .p = nullptr };
   constexpr auto lptr2 = Ptr{ .p = &r };
-  auto lptr3 = Ptr{ .p = &r };    // { dg-error "initialized with a 
consteval-only value" }
+  auto lptr3 = Ptr{ .p = &r };    // { dg-error "uses a consteval-only value" }
 
-  auto lne = Nested{{^^int, 0}, 1};  // { dg-error "initialized with a 
consteval-only value" }
+  auto lne = Nested{{^^int, 0}, 1};  // { dg-error "uses a consteval-only 
value" }
   constexpr auto lcne = Nested{{^^int, 0}, 1};
   auto lne2 = Nested{{info{}, 0}, 1};
   constexpr auto lcne2 = Nested{{info{}, 0}, 1};
 
   constexpr DS lcds{ { ^^int }, 0 };
   DS ldsn{ { info{} }, 0 };
-  DS lds{ { ^^int }, 0 };      // { dg-error "initialized with a 
consteval-only value" }
-  auto lbasep1 = (S *) &cds; // { dg-error "initialized with a consteval-only 
value" }
+  DS lds{ { ^^int }, 0 };      // { dg-error "uses a consteval-only value" }
+  auto lbasep1 = (S *) &cds; // { dg-error "uses a consteval-only value" }
   constexpr auto lbasep2 = (S *) &cds;
 
   constexpr U lu1 = { .i = 0 };
   constexpr U lu2 = { .r = ^^int };
   auto lu3 = U{ .i = 0 };
-  auto lu4 = U{ .r = ^^int };  // { dg-error "initialized with a 
consteval-only value" }
+  auto lu4 = U{ .r = ^^int };  // { dg-error "uses a consteval-only value" }
   auto lu5 = U{ .r = info{} };
 
   constexpr auto lr1 = getr ();
   auto lr2 = getnr ();
-  auto lr3 = getr ();    // { dg-error "initialized with a consteval-only 
value" }
+  auto lr3 = getr ();    // { dg-error "uses a consteval-only value" }
 
   // We think that [expr.const.imm]/2 gives us the rationale for
   // rejecting this code, even though r isn't ODR-used here.
@@ -354,7 +354,7 @@ g (bool b)
   a == r; // { dg-error "consteval-only value outside an immediate function 
context" }
 
   constexpr N cln;
-  N ln;        // { dg-error "initialized with a consteval-only value" }
+  N ln;        // { dg-error "uses a consteval-only value" }
 
   new (&a) info();
   new (&a) info(^^int); // { dg-error "consteval-only value outside an 
immediate function context" }
@@ -369,11 +369,11 @@ g (bool b)
   lam ();
 
   auto lam2 = [] { return ^^int; };
-  auto e9 = lam2 ();   // { dg-error "initialized with a consteval-only value" 
}
+  auto e9 = lam2 ();   // { dg-error "uses a consteval-only value" }
   constexpr auto e10 = lam2 ();
   constexpr auto lam3 = [i = ^^int]{ return i; };
-  auto lam4 = [i = ^^int]{ return i; };        // { dg-error "initialized with 
a consteval-only value" }
-  auto lam5 = [lr]{ return lr; };      // { dg-error "initialized with a 
consteval-only value" }
+  auto lam4 = [i = ^^int]{ return i; };        // { dg-error "uses a 
consteval-only value" }
+  auto lam5 = [lr]{ return lr; };      // { dg-error "uses a consteval-only 
value" }
   constexpr auto lam6 = [lr]{ return lr; };
 
   if consteval {
@@ -381,7 +381,7 @@ g (bool b)
   }
 
   auto x1 = imm_fn ();
-  auto x2 = []() consteval { return ^^int; }();  // { dg-error "initialized 
with a consteval-only value" }
+  auto x2 = []() consteval { return ^^int; }();  // { dg-error "uses a 
consteval-only value" }
 
   id (null);
   id (^^int);  // { dg-error "consteval-only value outside an immediate 
function context" }
@@ -527,15 +527,15 @@ ceg (bool b)
 constexpr void
 cg (bool b)
 {
-  int e3 = (^^int, 42);            // { dg-error "initialized with a 
consteval-only value" }
-  int e4 = (r, 42);        // { dg-error "initialized with a consteval-only 
value" }
-  int e5 = (r, fn());      // { dg-error "initialized with a consteval-only 
value" }
+  int e3 = (^^int, 42);            // { dg-error "uses a consteval-only value" 
}
+  int e4 = (r, 42);        // { dg-error "uses a consteval-only value" }
+  int e5 = (r, fn());      // { dg-error "uses a consteval-only value" }
   static int e6 = (^^int, 42);
   static int e7 = (r, 42);
-  static int e8 = (r, fn());       // { dg-error "initialized with a 
consteval-only value" }
+  static int e8 = (r, fn());       // { dg-error "uses a consteval-only value" 
}
 
-  info rn = b ? info{} : ^^int;        // { dg-error "initialized with a 
consteval-only value" }
-  info ri = b ? ^^int : info{};        // { dg-error "initialized with a 
consteval-only value" }
+  info rn = b ? info{} : ^^int;        // { dg-error "uses a consteval-only 
value" }
+  info ri = b ? ^^int : info{};        // { dg-error "uses a consteval-only 
value" }
 
   constexpr auto lr1 = getr ();
   auto lr2 = getnr ();
diff --git a/gcc/testsuite/g++.dg/reflect/value10.C 
b/gcc/testsuite/g++.dg/reflect/value10.C
new file mode 100644
index 00000000000..51110e6de20
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/value10.C
@@ -0,0 +1,14 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++20 } }
+// Reflection not enabled: the consteval-only value model has to work for
+// pointers to immediate functions without any of the reflection machinery.
+
+struct O { consteval int mf () const { return 1; } };
+constexpr auto pm1 = &O::mf;   // { dg-message "taking address of an immediate 
function" }
+void sink (int (O::*) () const);
+int (O::*gp) () const;
+
+void f1 () { gp = pm1; }      // { dg-error "consteval-only value outside an 
immediate function context" }
+void f2 () { sink (pm1); }    // { dg-error "consteval-only value outside an 
immediate function context" }
+auto f3 () { return pm1; }    // { dg-error "consteval-only value outside an 
immediate function context" }
diff --git a/gcc/testsuite/g++.dg/reflect/value11.C 
b/gcc/testsuite/g++.dg/reflect/value11.C
new file mode 100644
index 00000000000..21f7e5333cc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/value11.C
@@ -0,0 +1,32 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+consteval int g () { return 1; }
+consteval auto h () { return &g; }
+
+struct O { consteval auto mf () const { return ^^int; } };
+constexpr auto pm = &O::mf;
+
+auto fn1 (O o) { return (o.*pm) (); }    // { dg-error "consteval-only value" }
+consteval auto fn2 (O o) { return (o.*pm) (); }
+
+consteval auto
+fn3 (O o)
+{
+  // All fine: immediate function context.
+  auto pm = &O::mf;
+  constexpr auto cpm = &O::mf;
+  constexpr auto cp = h ();
+  return ((o.*pm) (), (o.*cpm) (), (*cp) ());
+}
+
+void
+fn4 (O o)
+{
+  static constexpr auto spm = &O::mf;
+  constexpr auto lpm = &O::mf;
+  (o.*spm) (); // { dg-error "consteval-only value" }
+  (o.*lpm) (); // { dg-error "consteval-only value" }
+}
diff --git a/gcc/testsuite/g++.dg/reflect/value12.C 
b/gcc/testsuite/g++.dg/reflect/value12.C
new file mode 100644
index 00000000000..f0fd599f673
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/value12.C
@@ -0,0 +1,25 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++20 } }
+
+consteval int f () { return 1; }
+consteval auto g () { return &f; }
+consteval auto h () { return &g; }
+
+int
+fn ()
+{
+  int i = f ();
+  i += g () ();              // { dg-error "consteval-only value outside an 
immediate function context" }
+  i += h () () ();    // { dg-error "consteval-only value outside an immediate 
function context" }
+  return i;
+}
+
+constexpr int
+cfn ()
+{
+  int i = f ();
+  i += g () ();              // { dg-error "consteval-only value outside an 
immediate function context" }
+  i += h () () ();    // { dg-error "consteval-only value outside an immediate 
function context" }
+  return i;
+}
diff --git a/gcc/testsuite/g++.dg/reflect/value13.C 
b/gcc/testsuite/g++.dg/reflect/value13.C
new file mode 100644
index 00000000000..8d5edb9c63e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/value13.C
@@ -0,0 +1,40 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do run { target c++20 } }
+
+consteval int g () { return 1; }
+constexpr int f () { return 2; }
+
+template <typename T>
+constexpr int e (T) { return g (); }
+
+constexpr auto fp = f;
+
+template <typename T>
+constexpr int n (T) { return fp (); }
+int (*np) (int) = &n<int>;
+
+template <typename T>
+constexpr int e3 (T t)
+{
+  constexpr auto p = &e<T>;
+  return p (t);
+}
+
+consteval auto h2 () { return &e<int>; }
+
+int
+main ()
+{
+  if (fp () != 2)
+    __builtin_abort ();
+  if (np (0) != 2)
+    __builtin_abort ();
+  int (*rp) () = f;
+  if (rp () != 2)
+    __builtin_abort ();
+  if (e3 (0) != 1)
+    __builtin_abort ();
+  if (h2 () (0) != 1)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/value14.C 
b/gcc/testsuite/g++.dg/reflect/value14.C
new file mode 100644
index 00000000000..0126f04be7d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/value14.C
@@ -0,0 +1,19 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-fno-immediate-escalation" }
+// With escalation disabled, check_out_of_consteval_use has to diagnose where
+// it would otherwise promote.
+
+consteval int g () { return 1; }
+consteval auto h () { return &g; }
+
+template<auto>
+constexpr void
+ex ()
+{
+  auto x = h ();                 // { dg-error "consteval-only" }
+}
+template void ex<0> ();
+
+auto lam = [] { return h (); };          // { dg-error "consteval-only" }
diff --git a/gcc/testsuite/g++.dg/reflect/value15.C 
b/gcc/testsuite/g++.dg/reflect/value15.C
new file mode 100644
index 00000000000..324f622b82f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/value15.C
@@ -0,0 +1,71 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do run { target c++23 } }
+// A run-time test for pointers to consteval functions.
+
+consteval int g () { return 1; }
+consteval auto h () { return &g; }
+struct O {
+  consteval int mf () const { return 2; }
+  consteval int mf2 () const { return 3; }
+};
+
+constexpr auto fp = &g;
+constexpr auto pm = &O::mf;
+
+struct A { int (*fp) (); };
+constexpr A tbl[] = { { &g }, { &g } };
+struct A2 { int (O::*pm) () const; };
+constexpr A2 tbl2[] = { { &O::mf }, { &O::mf2 } };
+
+consteval int call (int (*p) ()) { return p (); }
+consteval int callm (O o, int (O::*p) () const) { return (o.*p) (); }
+consteval int
+sum (int i)
+{
+  return fp () + tbl[i].fp () + (O{}.*pm) () + (O{}.*tbl2[i].pm) ();
+}
+
+int x = call (&g);
+
+__attribute__((noipa)) int c1 () { return call (&g); }
+__attribute__((noipa)) int c2 () { return call (fp); }
+__attribute__((noipa)) int c3 () { return call (h ()); }
+__attribute__((noipa)) int c4 () { return call (tbl[1].fp); }
+__attribute__((noipa)) int c5 () { return callm (O{}, pm); }
+__attribute__((noipa)) int c6 () { return callm (O{}, tbl2[1].pm); }
+__attribute__((noipa)) int c7 () { return sum (1); }
+
+constexpr int
+c8 ()
+{
+  if consteval
+    { return fp () + (O{}.*pm) (); }
+  else
+    { return 9; }
+}
+static_assert (c8 () == 3);
+
+int
+main ()
+{
+  if (x != 1)
+    __builtin_abort ();
+  if (c1 () != 1)
+    __builtin_abort ();
+  if (c2 () != 1)
+    __builtin_abort ();
+  if (c3 () != 1)
+    __builtin_abort ();
+  if (c4 () != 1)
+    __builtin_abort ();
+  if (c5 () != 2)
+    __builtin_abort ();
+  if (c6 () != 3)
+    __builtin_abort ();
+  if (c7 () != 1 + 1 + 2 + 3)
+    __builtin_abort ();
+  int (*volatile p8) () = c8;
+  if (p8 () != 9)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/value2.C 
b/gcc/testsuite/g++.dg/reflect/value2.C
index 1c73055acf7..da70b02be0e 100644
--- a/gcc/testsuite/g++.dg/reflect/value2.C
+++ b/gcc/testsuite/g++.dg/reflect/value2.C
@@ -10,11 +10,11 @@ using info = decltype(^^::);
 consteval int plus1(int x) { return x + 1; }
 template <auto V> struct C { };
 
-auto a = plus1; // { dg-error "taking address of an immediate function" }
-constexpr auto b = plus1; // // { dg-bogus "returns address" "" { xfail *-*-* 
} } OK
+auto a = plus1; // { dg-error "uses a consteval-only value" }
+constexpr auto b = plus1; // OK
 auto c = C<plus1>(); // OK
 
-auto d = ^^int; // { dg-error "initialized with a consteval-only value" }
+auto d = ^^int; // { dg-error "uses a consteval-only value" }
 auto e = C<^^char>(); // OK
 
 // [expr.const.imm]
@@ -24,9 +24,9 @@ template <auto F>
 constexpr void ex() {
   auto x = F();
 }
-auto p = &ex<refl>; // { dg-error "taking address of an immediate function" }
+auto p = &ex<refl>; // { dg-error "uses a consteval-only value" }
 
 consteval int id(int x) { return x; }
 template <auto F>
 constexpr auto apply_to(int i) { return F(i); }
-auto q = &apply_to<id>; // { dg-error "taking address of an immediate 
function" }
+auto q = &apply_to<id>; // { dg-error "uses a consteval-only value" }
diff --git a/gcc/testsuite/g++.dg/reflect/value4.C 
b/gcc/testsuite/g++.dg/reflect/value4.C
index 26ba9a9d371..c55d9cdf0cb 100644
--- a/gcc/testsuite/g++.dg/reflect/value4.C
+++ b/gcc/testsuite/g++.dg/reflect/value4.C
@@ -14,11 +14,11 @@ static_assert (p[2] == ^^V::c);
 static_assert (varr[0] == ^^V::a);
 
 constexpr info arr[] = { ^^int, ^^double };
-auto q = &arr[0]; // { dg-error ".q. is initialized with a consteval-only 
value but is not declared .constexpr." }
+auto q = &arr[0]; // { dg-error ".q. uses a consteval-only value" }
 
 void
 fn ()
 {
-  auto r = arr; // { dg-error ".r. is initialized with a consteval-only value 
but is not declared .constexpr." }
+  auto r = arr; // { dg-error ".r. uses a consteval-only value" }
   (void) r;
 }
diff --git a/gcc/testsuite/g++.dg/reflect/value5.C 
b/gcc/testsuite/g++.dg/reflect/value5.C
index 9dec04e7247..e46821ee17b 100644
--- a/gcc/testsuite/g++.dg/reflect/value5.C
+++ b/gcc/testsuite/g++.dg/reflect/value5.C
@@ -19,22 +19,22 @@ constexpr const info *p = arr;
 // These check check_out_of_consteval_use which uses a tree walk
 // on its expr.  value6.C checks consteval_only_p not used in
 // a tree walk.
-const void *vp = &p;             // { dg-error "initialized with a 
consteval-only value" }
+const void *vp = &p;             // { dg-error "uses a consteval-only value" }
 
-const auto p1 = &arr[0];         // { dg-error "initialized with a 
consteval-only value" }
-const auto p2 = arr;     // { dg-error "initialized with a consteval-only 
value" }
-const auto p3 = arr + 1;         // { dg-error "initialized with a 
consteval-only value" }
-const auto p4 = arr + 3;         // { dg-error "initialized with a 
consteval-only value" }
-const auto p5 = &s;              // { dg-error "initialized with a 
consteval-only value" }
-const auto p6 = &s.i;    // { dg-error "initialized with a consteval-only 
value" }
-const auto p7 = &sarr[1];        // { dg-error "initialized with a 
consteval-only value" }
-const auto p8 = &sarr[1].i;      // { dg-error "initialized with a 
consteval-only value" }
+const auto p1 = &arr[0];         // { dg-error "uses a consteval-only value" }
+const auto p2 = arr;     // { dg-error "uses a consteval-only value" }
+const auto p3 = arr + 1;         // { dg-error "uses a consteval-only value" }
+const auto p4 = arr + 3;         // { dg-error "uses a consteval-only value" }
+const auto p5 = &s;              // { dg-error "uses a consteval-only value" }
+const auto p6 = &s.i;    // { dg-error "uses a consteval-only value" }
+const auto p7 = &sarr[1];        // { dg-error "uses a consteval-only value" }
+const auto p8 = &sarr[1].i;      // { dg-error "uses a consteval-only value" }
 
 struct Holder { const info *p; int n; };
-auto h = Holder{ &arr[0], 1 };   // { dg-error "initialized with a 
consteval-only value" }
+auto h = Holder{ &arr[0], 1 };   // { dg-error "uses a consteval-only value" }
 
 constexpr bool cond = true;
-const auto p_cond = cond ? &arr[0] : &arr[1];    // { dg-error "initialized 
with a consteval-only value" }
+const auto p_cond = cond ? &arr[0] : &arr[1];    // { dg-error "uses a 
consteval-only value" }
 
 // Not an error.
 auto pdm = &S::i;
diff --git a/gcc/testsuite/g++.dg/reflect/value9.C 
b/gcc/testsuite/g++.dg/reflect/value9.C
new file mode 100644
index 00000000000..2bef561dea9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/value9.C
@@ -0,0 +1,261 @@
+// PR c++/125820
+// P4101R1, Consteval-only Values for C++26
+// { dg-do compile { target c++20 } }
+// Reflection not enabled; P4101 is a DR so this has to work without any of the
+// C++26 reflection machinery.
+
+consteval int g () { return 1; }
+consteval auto h () { return &g; }
+
+constexpr auto a1 = h ();
+auto a2 = h ();                          // { dg-error "uses a consteval-only 
value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+constinit auto a3 = h ();        // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+constexpr auto a4 = &g;
+auto a5 = &g;                    // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+constexpr auto &r1 = g;
+auto &r2 = g;                    // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+struct O { consteval int mf () const { return 1; } };
+constexpr auto pm1 = &O::mf;
+auto pm2 = &O::mf;               // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+consteval int f () { return 1; }
+constexpr auto fp = &f;
+
+static_assert (h () != nullptr);
+static_assert (&O::mf != nullptr);
+constexpr bool b1 = h () == &g;
+int arr[h () == &g ? 2 : 1];
+
+int u1 () { return f (); }
+int u2 () { return (*f) (); }  // { dg-error "consteval-only value outside" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// We fold fp to g and don't detect the error.
+int u3 () { return (*fp) (); } // { dg-error "taking address of an immediate 
function" "" { xfail *-*-* } }
+// And this should probably be rejected as well.
+int u4 () { return fp (); }
+
+consteval int fv (int i) { return i; }
+constexpr auto fvp = &fv;
+int u5 (int i) { return (*fvp) (i); }  // { dg-error "not a constant 
expression" }
+
+void
+fn ()
+{
+  auto p = h ();  // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+  auto p2 = &g;        // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+  int i = (&g, 42);   // { dg-error "initializer of non-.constexpr. variable 
.i. uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+}
+
+constexpr void
+cfn ()
+{
+  auto p = h ();  // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+  auto p2 = &g;        // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+}
+
+void
+fn2 ()
+{
+  auto pm = &O::mf;              // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+  (void) pm;
+}
+
+consteval int
+fn3 (O o)
+{
+  // All fine: immediate function context.
+  auto pm = &O::mf;
+  constexpr auto cpm = &O::mf;
+  constexpr auto cp = h ();
+  return (o.*pm) () + (o.*cpm) () + (*cp) ();
+}
+
+// This may be invalid and only accepted due to extra folding we perform?
+int use1 (O o) { return (o.*pm1) (); }
+consteval int use2 (O o) { return (o.*pm1) (); }
+
+void
+fn4 (O o)
+{
+  static constexpr auto spm = &O::mf;
+  constexpr auto lpm = &O::mf;
+  // These are probably only accepted due to overzealous folding too.
+  (o.*spm) ();
+  (o.*lpm) ();
+}
+
+void
+fn5 ()
+{
+  (void) sizeof (h ());
+  using T = decltype (&g);
+  using U = decltype (&O::mf);
+  static_assert (sizeof (T) == sizeof (T));
+  static_assert (sizeof (U) == sizeof (U));
+}
+
+#if __cpp_if_consteval >= 202106L
+constexpr int
+fn6 ()
+{
+  if consteval
+    {
+      auto p = h ();
+      return (*p) ();
+    }
+  else
+    {
+      return 0;
+    }
+}
+static_assert (fn6 () == 1);
+#endif
+
+void fn7 () { h (); }            // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn8 () { if (h () != nullptr); } // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn9 () { auto p = h (); }   // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+void fn10 () { (void) h (); }    // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn11 () { h (), 0; }        // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn12 () { bool b = h () == &g; }  // { dg-error "uses a consteval-only 
value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+struct S { int (*p)(); };
+consteval S k () { return { &g }; }
+void fn13 () { k (); }           // { dg-error "consteval-only value" }
+void fn14 () { if (k ().p) ; }   // { dg-error "consteval-only value" }
+void fn15 () { bool b = &g == nullptr; }       // { dg-error "uses a 
consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+void fn16 () { if (h () == &g) ; }       // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn17 () { bool b = h () == h (); }            // { dg-error 
"consteval-only value" "PR127478" { xfail *-*-* } }
+void fn18 () { bool b = h () != nullptr; }    // { dg-error "consteval-only 
value" "PR127478" { xfail *-*-* } }
+void fn19 () { bool b; b = h () == &g; }  // { dg-error "consteval-only value" 
}
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+
+void
+fn20 ()
+{
+  k ();          // { dg-error "consteval-only value" }
+  k ();          // { dg-error "consteval-only value" }
+  k ();          // { dg-error "consteval-only value" }
+  k ();          // { dg-error "consteval-only value" }
+}
+
+void fn21 () { if (k ().p != nullptr) ; } // { dg-error "consteval-only value" 
}
+void fn22 () { bool b = k ().p; }        // { dg-error "consteval-only value" 
"PR127478" { xfail *-*-* } }
+void fn23 () { int i = k ().p (); }      // { dg-error "consteval-only value" 
"PR127478" { xfail *-*-* } }
+struct T { int i; int (*p)(); };
+consteval T t () { return { 42, &g }; }
+void fn24 () { int i = t ().i; }         // { dg-error "consteval-only value" 
"PR127478" { xfail *-*-* } }
+void fn25 () { bool b; b = k ().p; }     // { dg-error "consteval-only value" }
+void fn26 () { while (k ().p) break; }   // { dg-error "consteval-only value" }
+bool fn27 () { return k ().p != nullptr; }  // { dg-error "consteval-only 
value" }
+void fn28 (bool x) { if (k ().p && x) ; }   // { dg-error "consteval-only 
value" }
+void fn29 (bool x) { if (x && k ().p) ; }   // { dg-error "consteval-only 
value" }
+int (*q) ();
+void fn30 () { if (!h ()) ; }      // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn31 () { if (h ()) ; }       // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn32 () { if (h () == q) ; }   // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// This is not expected to work before P3496.
+void fn33 () { int i; i = h () (); }  // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn34 () { if (h () () == 1) ; }  // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+void fn35 () { int i = h () (); }     // { dg-error "consteval-only value" 
"PR127478" { xfail *-*-* } }
+void fn36 () { &g; }             // { dg-error "taking address of an immediate 
function" }
+void fn37 () { &O::mf; }         // { dg-error "taking address of an immediate 
function" }
+
+void (*fnp) ();
+consteval void cf () { }
+void nf () { }
+
+void
+fn38 ()
+{
+  (void) (fnp == fnp);
+  (void) (fnp == &cf);           // { dg-error "taking address of an immediate 
function" }
+  fnp = &nf;
+  fnp = &cf;                     // { dg-error "consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+}
+struct A { int (*fp) (); };
+constexpr A tbl[] = { { &g }, { &g } };
+struct A2 { int (O::*fp) () const; };
+constexpr A2 tbl2[] = { { &O::mf }, { &O::mf } };
+
+constexpr const A *pp = &tbl[0];
+const A *fpp () { return pp; }   // { dg-error "consteval-only value" }
+
+constexpr const A2 *pp2 = &tbl2[0];
+const A2 *fpp2 () { return pp2; }  // { dg-error "consteval-only value" }
+
+consteval int use3 () { return tbl[0].fp (); }
+// These are probably only accepted due to overzealous folding too.
+int use4 () { return tbl[1].fp (); }
+constexpr int use5 () { return tbl[0].fp (); }
+
+template <auto>
+constexpr void
+ex ()
+{
+  auto x = h ();
+}
+auto pex = &ex<0>;               // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+auto lam = [] { return h (); };
+constexpr auto lv1 = lam ();
+auto lv2 = lam ();               // { dg-error "uses a consteval-only value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+auto lv3 = &decltype (lam)::operator ();  // { dg-error "uses a consteval-only 
value" }
+// { dg-message "taking address of an immediate function" "" { target *-*-* } 
.-1 }
+// { dg-message "add .constexpr." "" { target *-*-* } .-2 }
+
+template <auto V> struct C { };
+auto c1 = C<&g> ();
+auto c2 = C<&O::mf> ();
+auto c3 = C<h ()> ();
+
+// Subexpressions of an immediate invocation.
+consteval int call (int (*p) ()) { return p (); }
+int x = call (&g);
+void fn39 () { int y = call (h ()); }

base-commit: b651c9d3f37d989e4f381880238cc1a1b872e3f1
-- 
2.55.0

Reply via email to