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.

Reply via email to