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

--- Comment #35 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jakub Jelinek <ja...@gcc.gnu.org>:

https://gcc.gnu.org/g:7738c6286fba7ec2112823f53cc2cefac2c8d007

commit r15-7506-g7738c6286fba7ec2112823f53cc2cefac2c8d007
Author: Jakub Jelinek <ja...@redhat.com>
Date:   Thu Feb 13 14:14:50 2025 +0100

    tree, gengtype: Fix up GC issue with DECL_VALUE_EXPR [PR118790]

    The following testcase ICEs, because we have multiple levels of
    DECL_VALUE_EXPR VAR_DECLs:
      character(kind=1) id_string[1:.id_string] [value-expr: *id_string.55];
      character(kind=1)[1:.id_string] * id_string.55 [value-expr:
FRAME.107.id_string.55];
      integer(kind=8) .id_string [value-expr: FRAME.107..id_string];
    id_string is the user variable mentioned in BLOCK_VARS, it has
    DECL_VALUE_EXPR because it is a VLA, id_string.55 is a temporary created by
    gimplify_vla_decl as the address that points to the start of the VLA, what
    is normally used in the IL to access it.  But as this artificial var is
then
    used inside of a nested function, tree-nested.cc adds DECL_VALUE_EXPR to it
    too and moves the actual value into the FRAME.107 object's member.
    Now, remove_unused_locals removes id_string.55 (and various other
VAR_DECLs)
    from cfun->local_decls, simply because it is not mentioned in the IL at all
    (neither is id_string itself, but that is kept in BLOCK_VARS as it has
    DECL_VALUE_EXPR).  So, after this point, id_string.55 tree isn't referenced
from
    anywhere but id_string's DECL_VALUE_EXPR.  Next GC collection is triggered,
    and we are unlucky enough that in the value_expr_for_decl hash table
    (underlying hash map for DECL_VALUE_EXPR) the id_string.55 entry comes
    before the id_string entry.  id_string is ggc_marked_p because it is
    referenced from BLOCK_VARS, but id_string.55 is not, as we don't mark
    DECL_VALUE_EXPR anywhere but by gt_cleare_cache on value_expr_for_decl.
    But gt_cleare_cache does two things, it calls clear_slots on entries
    where the key is not ggc_marked_p (so the id_string.55 mapping to
    FRAME.107.id_string.55 is lost and DECL_VALUE_EXPR (id_string.55) becomes
    NULL) but then later we see id_string entry, which is ggc_marked_p, so mark
    the whole hash table entry, which sets ggc_set_mark on id_string.55.  But
    at this point its DECL_VALUE_EXPR is lost.
    Later during dwarf2out.cc we want to emit DW_AT_location for id_string, see
    it has DECL_VALUE_EXPR, so emit it as indirection of id_string.55 for which
    we again lookup DECL_VALUE_EXPR as it has DECL_HAS_VALUE_EXPR_P, but as it
    is NULL, we ICE, instead of finding it is a subobject of FRAME.107 for
which
    we can find its stack location.

    Now, as can be seen in the PR, I've tried to tweak tree-ssa-live.cc so that
    it would keep id_string.55 in cfun->local_decls; that prohibits it from
    the DECL_VALUE_EXPR of it being GC until expansion, but then we shrink and
    free cfun->local_decls completely and so GC at that point still can throw
    it away.

    The following patch adds an extension to the GTY ((cache)) option, before
    calling the gt_cleare_cache on some hash table by specifying
    GTY ((cache ("somefn"))) it calls somefn on that hash table as well.
    And this extra hook can do any additional ggc_set_mark needed so that
    gt_cleare_cache preserves everything that is actually needed and throws
    away the rest.

    In order to make it just 2 pass rather than up to n passes - (if we had
    say
    id1 -> something, id2 -> x(id1), id3 -> x(id2), id4 -> x(id3), id5 ->
x(id4)
    in the value_expr_for_decl hash table in that order (where idN are
VAR_DECLs
    with DECL_HAS_VALUE_EXPR_P, id5 is the only one mentioned from outside and
    idN -> X stands for idN having DECL_VALUE_EXPR X, something for some
    arbitrary tree and x(idN) for some arbitrary tree which mentions idN
    variable) and in each pass just marked the to part of entries with
    ggc_marked_p base.from we'd need to repeat until we don't mark anything)
    the patch calls walk_tree on DECL_VALUE_EXPR of the marked trees and if it
    finds yet unmarked tree, it marks it and walks its DECL_VALUE_EXPR as well
    the same way.

    2025-02-13  Jakub Jelinek  <ja...@redhat.com>

            PR debug/118790
            * gengtype.cc (write_roots): Remove cache variable, instead break
from
            the loop on match and test o for NULL.  If the cache option has
            non-empty string argument, call the specified function with v->name
            as argument before calling gt_cleare_cache on it.
            * tree.cc (gt_value_expr_mark_2, gt_value_expr_mark_1,
            gt_value_expr_mark): New functions.
            (value_expr_for_decl): Use GTY ((cache ("gt_value_expr_mark")))
rather
            than just GTY ((cache)).
            * doc/gty.texi (cache): Document optional argument of cache option.

            * gfortran.dg/gomp/pr118790.f90: New test.

Reply via email to