The comment for pointer_map_traverse says:

/* Pass each pointer in PMAP to the function in FN, together with the pointer
    to the value and the fixed parameter DATA.  If FN returns false, the
    iteration stops.  */

However, the code in tree-cfg:edge_to_cases_cleanup does:

static bool
edge_to_cases_cleanup (const void *key ATTRIBUTE_UNUSED, void **value,
                       void *data ATTRIBUTE_UNUSED)
{
   tree t, next;

   for (t = (tree) *value; t; t = next)
     {
       next = CASE_CHAIN (t);
       CASE_CHAIN (t) = NULL;
     }

   *value = NULL;
   return false;
}

...
   pointer_map_traverse (edge_to_cases, edge_to_cases_cleanup, NULL);

which means that we're only cleaning up one of the case chains stored in
EDGE_TO_CASES.  Since it's a pointer_map, we can potentially get
different chains selected each time.  Under -fcompare-debug, this leads
to problems later on when we walk the function body and collect all the
DECLs referenced therein; we might walk non-NULL CASE_CHAINs and reach
more DECLs, depending on the memory layout.

This wouldn't have shown up previously, since TREE_CHAIN was used, and
we wouldn't walk TREE_CHAIN of expressions to find DECLs.

The fix is simple: return true from the above function!  I've added
logic to verify_expr to catch this sort of thing.

Tested on x86_64-unknown-linux-gnu.  OK to commit?

-Nathan

gcc/
        PR middle-end/48965
        * tree-cfg.c (edge_to_cases_cleanup): Return true.
        (verify_expr) [CASE_LABEL_EXPR]: Add checking.

diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index e1f8707..e2e84a2 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -843,7 +843,7 @@ edge_to_cases_cleanup (const void *key
ATTRIBUTE_UNUSED, void **value,
      }

    *value = NULL;
-  return false;
+  return true;
  }

  /* Start recording information mapping edges to case labels.  */
@@ -2830,6 +2830,14 @@ verify_expr (tree *tp, int *walk_subtrees, void
*data ATTRIBUTE_UNUSED)
        *walk_subtrees = 0;
        break;

+    case CASE_LABEL_EXPR:
+      if (CASE_CHAIN (t))
+       {
+         error ("invalid CASE_CHAIN");
+         return t;
+       }
+      break;
+
      default:
        break;
      }

Reply via email to