Hi!

pop_labels adds LABEL_DECLs into BLOCK_VARS by traversing a hash table
indexed by DECL_UID.  This is something that is undesirable, if -g vs. -g0
has different DECL_UID values (but still the same order of them), which can
happen even without the deletable constexpr tables, then the exact values
of the uids affect the order of BLOCK_VARS, which e.g. affects the inliner
and other places.

Fixed in similar way how other spots handle this case, by pushing the
slots into a vector, sorting the vector and then traversing the vector
instead of the hash table.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2016-04-13  Jakub Jelinek  <ja...@redhat.com>

        PR c++/70594
        * decl.c (pop_labels_1): Removed.
        (note_label, sort_labels): New functions.
        (pop_labels): During named_labels traversal, just push the slot
        pointers into a vector, then qsort it by DECL_UID and only then
        call pop_label and chain it into BLOCK_VARS.

--- gcc/cp/decl.c.jj    2016-04-01 17:21:30.000000000 +0200
+++ gcc/cp/decl.c       2016-04-13 11:59:04.604105861 +0200
@@ -368,33 +368,61 @@ pop_label (tree label, tree old_value)
   SET_IDENTIFIER_LABEL_VALUE (DECL_NAME (label), old_value);
 }
 
-/* At the end of a function, all labels declared within the function
-   go out of scope.  BLOCK is the top-level block for the
-   function.  */
+/* Push all named labels into a vector, so that we can sort it on DECL_UID
+   to avoid code generation differences.  */
 
 int
-pop_labels_1 (named_label_entry **slot, tree block)
+note_label (named_label_entry **slot, vec<named_label_entry **> &labels)
 {
-  struct named_label_entry *ent = *slot;
-
-  pop_label (ent->label_decl, NULL_TREE);
-
-  /* Put the labels into the "variables" of the top-level block,
-     so debugger can see them.  */
-  DECL_CHAIN (ent->label_decl) = BLOCK_VARS (block);
-  BLOCK_VARS (block) = ent->label_decl;
+  labels.quick_push (slot);
+  return 1;
+}
 
-  named_labels->clear_slot (slot);
+/* Helper function to sort named label entries in a vector by DECL_UID.  */
 
-  return 1;
+static int
+sort_labels (const void *a, const void *b)
+{
+  named_label_entry **slot1 = *(named_label_entry **const *) a;
+  named_label_entry **slot2 = *(named_label_entry **const *) b;
+  if (DECL_UID ((*slot1)->label_decl) < DECL_UID ((*slot2)->label_decl))
+    return -1;
+  if (DECL_UID ((*slot1)->label_decl) > DECL_UID ((*slot2)->label_decl))
+    return 1;
+  return 0;
 }
 
+/* At the end of a function, all labels declared within the function
+   go out of scope.  BLOCK is the top-level block for the
+   function.  */
+
 static void
 pop_labels (tree block)
 {
   if (named_labels)
     {
-      named_labels->traverse<tree, pop_labels_1> (block);
+      auto_vec<named_label_entry **, 32> labels;
+      named_label_entry **slot;
+      unsigned int i;
+
+      /* Push all the labels into a vector and sort them by DECL_UID,
+        so that gaps between DECL_UIDs don't affect code generation.  */
+      labels.reserve_exact (named_labels->elements ());
+      named_labels->traverse<vec<named_label_entry **> &, note_label> (labels);
+      labels.qsort (sort_labels);
+      FOR_EACH_VEC_ELT (labels, i, slot)
+       {
+         struct named_label_entry *ent = *slot;
+
+         pop_label (ent->label_decl, NULL_TREE);
+
+         /* Put the labels into the "variables" of the top-level block,
+            so debugger can see them.  */
+         DECL_CHAIN (ent->label_decl) = BLOCK_VARS (block);
+         BLOCK_VARS (block) = ent->label_decl;
+
+         named_labels->clear_slot (slot);
+       }
       named_labels = NULL;
     }
 }

        Jakub

Reply via email to