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.
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.)
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.
(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 | 101 ++++++-
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, 878 insertions(+), 283 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 e90ca1018a7..66ed7eced93 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -11422,22 +11422,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. */
@@ -11541,7 +11525,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)
@@ -11558,8 +11541,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)
@@ -11577,8 +11558,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
@@ -11773,28 +11752,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 154755fce82..27f73ce0d6a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -9258,7 +9258,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);
@@ -9275,6 +9275,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);
@@ -9547,7 +9549,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, bool = true);
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 51f0885436e..0f5acb0399a 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -8841,14 +8841,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)
@@ -8858,6 +8875,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:
@@ -8877,15 +8897,20 @@ consteval_only_value_p (tree t, hash_set<tree> &seen)
-- 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 (INTEGRAL_OR_ENUMERATION_TYPE_P (type) || SCALAR_FLOAT_TYPE_P (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);
@@ -8906,7 +8931,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);
@@ -8927,6 +8968,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);
}
@@ -9093,13 +9137,15 @@ 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. If COMPLAIN,
+ emit an error. 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*/,
+ bool complain/*=true*/)
{
- 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,9 +9155,34 @@ check_out_of_consteval_use (tree expr, bool
complain/*=true*/)
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: 775c869f70344091bee687df99bad668eaa38f6d
--
2.55.0