https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120775
--- Comment #19 from Marek Polacek <mpolacek at gcc dot gnu.org> ---
(In reply to Jakub Jelinek from comment #15)
> 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.
Yeah, it may be the right thing. Please go ahead; if anything crops up, we'll
address it.
(You could merge it with the uid_sensitive_constexpr_evaluation_p case above.)