[Bug c/95857] [8/9/10 Regression] Silencing an unused label warning with (void)&&label; can make gcc segfault

cvs-commit at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Wed Sep 16 19:22:33 GMT 2020


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

--- Comment #7 from CVS Commits <cvs-commit at gcc dot gnu.org> ---
The releases/gcc-9 branch has been updated by Jakub Jelinek
<jakub@gcc.gnu.org>:

https://gcc.gnu.org/g:62714a106493d0f1f22ff98c2dff2204f09cfcc0

commit r9-8903-g62714a106493d0f1f22ff98c2dff2204f09cfcc0
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Thu Jul 2 11:38:20 2020 +0200

    tree-cfg: Fix ICE with switch stmt to unreachable opt and forced labels
[PR95857]

    The following testcase ICEs, because during the cfg cleanup, we see:
      switch (i$e_11) <default: <L12> [33.33%], case -3: <lab2> [33.33%], case
0: <L10> [33.33%], case 2: <lab2> [33.33%]>
    ...
    lab2:
      __builtin_unreachable ();
    where lab2 is FORCED_LABEL.  The way it works, we go through the case
labels
    and when we reach the first one that points to gimple_seq_unreachable*
    basic block, we remove the edge (if any) from the switch bb to the bb
    containing the label and bbs reachable only through that edge we've just
    removed.  Once we do that, we must throw away all other cases that use
    the same label (or some other labels from the same bb we've removed the
edge
    to and the bb).  To avoid quadratic behavior, this is not done by walking
    all remaining cases immediately before removing, but only when processing
    them later.
    For normal labels this works, fine, if the label is in a deleted bb, it
will
    have NULL label_to_block and we handle that case, or, if the unreachable bb
    has some other edge to it, only the edge will be removed and not the bb,
    and again, find_edge will not find the edge and we only remove the case.
    And if a label would be to some other block, that other block wouldn't have
    been removed earlier because there would be still an edge from the switch
    block.
    Now, FORCED_LABEL (and I think DECL_NONLOCAL too) break this, because
    those labels aren't removed, but instead moved to some surrounding basic
    block.  So, when we later process those, when their gimple_seq_unreachable*
    basic block is removed, label_to_block will return some unrelated block
    (in the testcase the switch bb), so we decide to keep the case which
doesn't
    seem to be unreachable, but we don't really have an edge from the switch
    block to the block the label got moved to.

    I thought first about punting in gimple_seq_unreachable* on
    FORCED_LABEL/DECL_NONLOCAL labels, but that might penalize even code that
    doesn't care, so this instead just makes sure that for
    FORCED_LABEL/DECL_NONLOCAL labels that are being removed (and thus moved
    randomly) we remember in a hash_set the fact that those labels should be
    treated as removed for the purpose of the optimization, and later on
    handle those labels that way.

    2020-07-02  Jakub Jelinek  <jakub@redhat.com>

            PR tree-optimization/95857
            * tree-cfg.c (group_case_labels_stmt): When removing an unreachable
            base_bb, remember all forced and non-local labels on it and later
            treat those as if they have NULL label_to_block.  Formatting fix.
            Fix a comment typo.

            * gcc.dg/pr95857.c: New test.

    (cherry picked from commit 00f24f56732861d09a9716fa5b6b8a96c2289143)


More information about the Gcc-bugs mailing list