On Wed, Jul 26, 2017 at 9:35 PM, Peter Bergner <[email protected]> wrote:
> The test case for PR81564 exposes an issue where the case labels for a
> switch statement point to blocks that have already been removed by an
> earlier call to cleanup_tree_cfg(). In that case, the code in
> group_case_labels_stmt() that does:
>
> base_bb = label_to_block (CASE_LABEL (base_case));
>
> ...returns a NULL base_bb and we SEGV later on when we dereference it:
>
> if (EDGE_COUNT (base_bb->succs) == 0
> ...
>
> The fix here is to just treat case labels that point to blocks that have
> already been deleted similarly to case labels that point to the default
> case statement, by removing them.
>
> This passed bootstrap and regtesting on powerpc64le-linux with no regressions.
> Ok for trunk?
Ok.
Thanks,
Richard.
> Peter
>
> gcc/
> PR middle-end/81564
> * tree-cfg.c (group_case_labels_stmt): Handle already deleted blocks.
>
> gcc/testsuite/
> PR middle-end/81564
> * gcc.dg/pr81564.c: New test.
>
> Index: gcc/tree-cfg.c
> ===================================================================
> --- gcc/tree-cfg.c (revision 250581)
> +++ gcc/tree-cfg.c (working copy)
> @@ -1701,8 +1701,9 @@ group_case_labels_stmt (gswitch *stmt)
> gcc_assert (base_case);
> base_bb = label_to_block (CASE_LABEL (base_case));
>
> - /* Discard cases that have the same destination as the default case.
> */
> - if (base_bb == default_bb)
> + /* Discard cases that have the same destination as the default case or
> + whose destination blocks have already been removed as unreachable.
> */
> + if (base_bb == NULL || base_bb == default_bb)
> {
> i++;
> continue;
> Index: gcc/testsuite/gcc.dg/pr81564.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/pr81564.c (nonexistent)
> +++ gcc/testsuite/gcc.dg/pr81564.c (working copy)
> @@ -0,0 +1,21 @@
> +/* PR middle-end/81564 ICE in group_case_labels_stmt(). */
> +/* { dg-do compile } */
> +/* { dg-options "-O2" } */
> +
> +struct a {
> + int b;
> + int c;
> +};
> +
> +void
> +foo (void)
> +{
> + struct a *e;
> + switch (e->c)
> + {
> + case 7:
> + case 3:
> + if (__builtin_expect(!0, 0))
> + __builtin_unreachable();
> + }
> +}
>