https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124632

--- Comment #10 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The releases/gcc-15 branch has been updated by Jason Merrill
<[email protected]>:

https://gcc.gnu.org/g:b758c7f531cbffb73ffda663fd84fe7643cf959e

commit r15-11167-gb758c7f531cbffb73ffda663fd84fe7643cf959e
Author: Jason Merrill <[email protected]>
Date:   Thu May 14 12:19:55 2026 -0400

    c++: constexpr call hashing and gc [PR124632]

    In cxx_eval_call_expression, we unshare an argument that goes into
    constexpr_call::bindings so it's independent, and then if it's a
CONSTRUCTOR
    we unshare it again before putting it in the constexpr value hashtable so
    any modifications within the function don't affect the bindings.  And then
    we free these latter CONSTRUCTOR if they aren't part of the return value.

    In explicit-obj-lambda2.C, cl5 is a recursive constexpr lambda that takes a
    class (the closure) by value.  If -Wtautological-compare is enabled, we try
    to constant-fold cl5(5) to see if has a constant value.  In evaluating the
    outer call we have an empty CONSTRUCTOR argument {} that we unshare twice.

    When we try to evaluate the recursive call, the second unshare from the
    first call initially goes into bindings.  But since this is a recursive
call
    get_fundef_copy needs need to make a copy of the FUNCTION_DECL, and since
    this evaluation is for a warning uid_sensitive_constexpr_evaluation_p is
    true, so we can't make a copy, so evaluating the recursive copy fails
    without ever unsharing the argument.

    Then when we get back to finishing up the outer call we ggc_free the
    unshared CONSTRUCTOR that we don't need anymore.  But the recursive call
    already added it to the constexpr_call_table, so now the entry there is
    referring to freed memory.

    The solution is doing the first unshare immediately when we create the
entry
    in the constexpr_call_table, not later after get_fundef_copy.  This should
    also mean less unsharing, as we now only do the first unshare when creating
    the constexpr_call_table entry, not on subsequent evaluations.  This only
    affects uncacheable calls, but that's a significant subset.

            PR c++/124632

    gcc/cp/ChangeLog:

            * constexpr.cc (cxx_eval_call_expression): Unshare bindings
            sooner.

    gcc/testsuite/ChangeLog:

            * g++.dg/cpp23/explicit-obj-lambda2.C: Do strict GC and -Wall.

    (cherry picked from commit 219d9f4b006e19ea49b0e1ca6706fc1204211eff)

Reply via email to