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.)

Reply via email to