Hi! As detailed in the PR, when copy_decls_walk uses clone_tree, it enters just the clone node of tag into the hash table and not any children. On the testcase in that PR this DIE (DW_TAG_subroutine_type) contains DW_AT_object_pointer attribute which refers to its child node (DW_TAG_formal_parameter). As the child has been just cloned, but not added to the hash table, when copy_decls_walk adjusts attributes of the DW_TAG_subroutine_type clone, it doesn't find that the child DW_TAG_formal_parameter has been cloned and creates a new clone and adjusts DW_AT_object_pointer to point to that. It then goes on to attempt to clone its ancestors, but the parent is already in the hash table, so just adds this second DW_TAG_formal_parameter as another child of that.
Fixed by adding all the children DIE clones to the hash table. IMHO they can't appear in the hash table before (checked now with an assert), because otherwise we'd have cloned the ancestors too. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2012-01-25 Jakub Jelinek <ja...@redhat.com> PR debug/51950 * dwarf2out.c (clone_tree_hash): New function. (copy_decls_walk): Use it instead of clone_tree. --- gcc/dwarf2out.c.jj 2012-01-23 18:23:45.000000000 +0100 +++ gcc/dwarf2out.c 2012-01-25 18:32:24.026350399 +0100 @@ -7406,6 +7406,32 @@ copy_ancestor_tree (dw_die_ref unit, dw_ return copy; } +/* Like clone_tree, but additionally enter all the children into + the hash table decl_table. */ + +static dw_die_ref +clone_tree_hash (dw_die_ref die, htab_t decl_table) +{ + dw_die_ref c; + dw_die_ref clone = clone_die (die); + struct decl_table_entry *entry; + void **slot = htab_find_slot_with_hash (decl_table, die, + htab_hash_pointer (die), INSERT); + /* Assert that DIE isn't in the hash table yet. If it would be there + before, the ancestors would be necessarily there as well, therefore + clone_tree_hash wouldn't be called. */ + gcc_assert (*slot == HTAB_EMPTY_ENTRY); + entry = XCNEW (struct decl_table_entry); + entry->orig = die; + entry->copy = clone; + *slot = entry; + + FOR_EACH_CHILD (die, c, + add_child_die (clone, clone_tree_hash (c, decl_table))); + + return clone; +} + /* Walk the DIE and its children, looking for references to incomplete or trivial types that are unmarked (i.e., that are not in the current type_unit). */ @@ -7442,7 +7468,11 @@ copy_decls_walk (dw_die_ref unit, dw_die else { dw_die_ref parent = unit; - dw_die_ref copy = clone_tree (targ); + dw_die_ref copy = clone_die (targ); + + FOR_EACH_CHILD (targ, c, + add_child_die (copy, + clone_tree_hash (c, decl_table))); /* Make sure the cloned tree is marked as part of the type unit. */ Jakub