This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: C++ PATCH for c++/84684, wrong caching when evaluating a constexpr function
- From: Jason Merrill <jason at redhat dot com>
- To: Marek Polacek <polacek at redhat dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>, Jakub Jelinek <jakub at redhat dot com>
- Date: Tue, 6 Mar 2018 15:39:36 -0500
- Subject: Re: C++ PATCH for c++/84684, wrong caching when evaluating a constexpr function
- Authentication-results: sourceware.org; auth=none
- References: <20180306181342.GE7043@redhat.com>
On Tue, Mar 6, 2018 at 1:13 PM, Marek Polacek <polacek@redhat.com> wrote:
> In this testcase we have a constexpr function, value_to_char_helper. Its body
> is
> for (size_t i = 0u; i < alphabet_t::value_size; ++i)
> value_to_char[i] = to_char(alphabet.assign_rank(i));
>
> which is genericized to a LOOP_EXPR looking roughly like this:
>
> while (1)
> {
> if (i > 3)
> goto out;
> value_to_char[i] = to_char (..., i, ...);
> i++;
> }
>
> Then this is what happens when evaluating the above:
>
> 1) cxx_eval_call_expression evaluates the first call to to_char
> it's not in the hash table -> copy the body and the bindings and
> then evaluate the body
> the result is 65
> bindings: alph -> {._value=0} (correct)
> save all this to the table
> 2) cxx_eval_store_expression evaluates i++
> then it replaces the value in the hash map:
> *valp = init;
> which is generally what we want, but that also overwrites {._value=0} from
> above to {._value=1} which causes problem in 3)
> 3) cxx_eval_call_expression tries to evaluate the second call to to_char
> bindings: alph -> {._value=1} (correct)
> here if the hashes match (use [1] hunk for better testing) then
> we find to_char call in the table. Then we invoke
> constexpr_call_hasher::equal() to compare the two calls: fundefs
> match, and because 2) has overwritten bindings of the previous
> to_char call, they match too, both are {._value=1}.
> That means we don't evaluate this second call and just use the cached
> result (65), and that is wrong.
>
> I think the fix is to avoid sharing the constructor in the bindings which
> is what the patch does and what we do in several places already. I think
> Jakub's patch <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84684#c13>
> wouldn't work if the bindings had more constructors.
>
> But I'm also wondering about massage_init_elt. It has
> tree t = fold_non_dependent_expr (init);
> t = maybe_constant_init (t);
> but given that fold_non_dependent_expr now calls maybe_constant_value, which
> then causes that we try to cache the calls above, this seems excessive,
> wouldn't we be better off with just calling fold_non_dependent_init as
> discussed recently?
Probably.
> I bootstrapped/regtested this patch with this hunk, too, for better testing:
>
> [1]
> @@ -1598,8 +1598,12 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
> constexpr_call *entry = NULL;
> if (depth_ok && !non_constant_args && ctx->strict)
> {
> +#if 0
> new_call.hash = iterative_hash_template_arg
> (new_call.bindings, constexpr_fundef_hasher::hash (new_call.fundef));
> +#else
> + new_call.hash = 0;
> +#endif
>
> /* If we have seen this call before, we are done. */
> maybe_initialize_constexpr_call_table ();
>
> Bootstrapped/regtested on x86_64-linux, ok for trunk? And likely 7.
OK.
Jason