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