https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120775
--- Comment #15 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Had a quick look at g++.dg/reflect/p2996-17.C (the commented out stuff in
there).
The reason it doesn't work is that the reflect_constant and latest calls in
static consteval void increment ()
{
define_aggregate (substitute (^^Helper,
{ std::meta::reflect_constant (latest ()) }),
{});
}
aren't evaluated when evaluating the increment call at all, instead they are
evaluated
when we finish_compound_literal when parsing that function when trying to
convert the initializer_list to some reflection_range usable in substitute.
std::meta::reflect_constant (latest ()) is a constant expression and
finish_compound_literal -> digest_init_flags -> digest_init_r ->
process_init_constructor -> process_init_constructor_array -> massage_init_elt
-> fold_non_dependent_init folds it to a reflection of constant 0.
Now, this is mce_unknown evaluation. Shall all metafunctions be only handled
if mce_true or mce_false (and define_aggregate/access_context::current only if
mce_true as already done?)?
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index d6fe01ead1f..7ddb4b652cc 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -3845,6 +3845,13 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree
t,
*non_constant_p = true;
return t;
}
+ /* Don't evaluate metafunctions at all when mce_unknown, otherwise we
+ might fold those prematurely. See g++.dg/reflect/p2996-17.C. */
+ if (ctx->manifestly_const_eval == mce_unknown)
+ {
+ *non_constant_p = true;
+ return t;
+ }
ctx->global->metafns_called = true;
tree e = process_metafunction (ctx, fun, t, non_constant_p, overflow_p,
jump_target);
diff --git a/gcc/testsuite/g++.dg/reflect/p2996-17.C
b/gcc/testsuite/g++.dg/reflect/p2996-17.C
index 6c2c6e31996..e9dabb0d799 100644
--- a/gcc/testsuite/g++.dg/reflect/p2996-17.C
+++ b/gcc/testsuite/g++.dg/reflect/p2996-17.C
@@ -25,10 +25,8 @@ struct TU_Ticket {
constexpr int x = TU_Ticket::latest (); // x initialized to 0.
consteval { TU_Ticket::increment (); }
constexpr int y = TU_Ticket::latest (); // y initialized to 1.
-// TODO: This one still doesn't work, doesn't call latest () again
-// but uses cached 0 value.
-//consteval { TU_Ticket::increment (); }
-//constexpr int z = TU_Ticket::latest (); // z initialized to 2.
+consteval { TU_Ticket::increment (); }
+constexpr int z = TU_Ticket::latest (); // z initialized to 2.
static_assert (x == 0);
static_assert (y == 1);
-//static_assert (z == 2);
+static_assert (z == 2);
fixes it. Do we want to do that? Doesn't regress anything else in the
testsuite.
https://forge.sourceware.org/marek/gcc/pulls/81 has it but haven't merged this
yet.