The following fixes a GC issue I run into when doing prune_unused_types_prune early. The issue is that the DIE struct has a chain_circular marked field (die_sib) which cannot tolerate spurious extra entries from old removed entries into the circular chain. Otherwise we fail to properly mark parts of the chain. Those stray entries are kept live referenced from TYPE_SYMTAB_DIE.
So the following patch that makes sure to clear ->die_sib for nodes we remove. (these DIEs remaining in TYPE_SYMTAB_DIE also means we may end up re-using them which is probably not what we want ... in the original LTO experiment I had a ->removed flag in the DIE struct and removed DIEs from the cache at cache lookup time if I hit a removed DIE) Bootstrapped and tested on x86_64-unknown-linux-gnu, gdb tested there as well. Ok for trunk? Thanks, Richard. 2015-08-26 Richard Biener <rguent...@suse.de> * dwarf2out.c (remove_child_with_prev): Clear child->die_sib. (replace_child): Likewise. (remove_child_TAG): Adjust. (move_marked_base_types): Likewise. (prune_unused_types_prune): Clear die_sib of removed children. Index: trunk/gcc/dwarf2out.c =================================================================== --- trunk.orig/gcc/dwarf2out.c 2015-08-26 09:30:54.679185817 +0200 +++ trunk/gcc/dwarf2out.c 2015-08-25 16:54:09.150506037 +0200 @@ -4827,6 +4827,7 @@ remove_child_with_prev (dw_die_ref child prev->die_sib = child->die_sib; if (child->die_parent->die_child == child) child->die_parent->die_child = prev; + child->die_sib = NULL; } /* Replace OLD_CHILD with NEW_CHILD. PREV must have the property that @@ -4853,6 +4854,7 @@ replace_child (dw_die_ref old_child, dw_ } if (old_child->die_parent->die_child == old_child) old_child->die_parent->die_child = new_child; + old_child->die_sib = NULL; } /* Move all children from OLD_PARENT to NEW_PARENT. */ @@ -4883,9 +4885,9 @@ remove_child_TAG (dw_die_ref die, enum d remove_child_with_prev (c, prev); c->die_parent = NULL; /* Might have removed every child. */ - if (c == c->die_sib) + if (die->die_child == NULL) return; - c = c->die_sib; + c = prev->die_sib; } } while (c != die->die_child); } @@ -24565,8 +24590,8 @@ prune_unused_types_prune (dw_die_ref die c = die->die_child; do { - dw_die_ref prev = c; - for (c = c->die_sib; ! c->die_mark; c = c->die_sib) + dw_die_ref prev = c, next; + for (c = c->die_sib; ! c->die_mark; c = next) if (c == die->die_child) { /* No marked children between 'prev' and the end of the list. */ @@ -24578,8 +24603,14 @@ prune_unused_types_prune (dw_die_ref die prev->die_sib = c->die_sib; die->die_child = prev; } + c->die_sib = NULL; return; } + else + { + next = c->die_sib; + c->die_sib = NULL; + } if (c != prev->die_sib) prev->die_sib = c; @@ -24824,8 +24855,8 @@ move_marked_base_types (void) remove_child_with_prev (c, prev); /* As base types got marked, there must be at least one node other than DW_TAG_base_type. */ - gcc_assert (c != c->die_sib); - c = c->die_sib; + gcc_assert (die->die_child != NULL); + c = prev->die_sib; } } while (c != die->die_child);