https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87295
--- Comment #4 from Richard Biener <rguenth at gcc dot gnu.org> --- The odd thing I see is that we have two type DIEs with the same signature (but different members). DIE 0: DW_TAG_compile_unit (0x7ffff68960a0) abbrev id: 0 offset: 0 mark: 0 DW_AT_producer: "GNU C++17 9.0.1 20190125 (experimental) [trunk revision 268137] -flto -ffat-lto-objects -fdebug-types-section -g -std=gnu++17" DW_AT_language: 4 DW_AT_name: "t.ii" DW_AT_comp_dir: "/abuild/rguenther/trunk2-g/gcc" DIE 0: DW_TAG_structure_type (0x7ffff6896820) abbrev id: 0 offset: 0 mark: 0 signature: 2e365acce74a6a1f DW_AT_name: "integral_constant<bool, false>" DW_AT_signature: die -> signature: 2e365acce74a6a1f (0x7ffff68962d0) DW_AT_declaration: 1 DIE 0: DW_TAG_member (0x7ffff6896320) abbrev id: 0 offset: 0 mark: 0 DW_AT_name: "value" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 4 DW_AT_decl_column: 24 DW_AT_type: die -> 0 (0x7ffff68963c0) DW_AT_external: 1 DW_AT_declaration: 1 DW_AT_const_expr: 1 DW_AT_inline: 1 DIE 0: DW_TAG_subprogram (0x7ffff68964b0) abbrev id: 0 offset: 0 mark: 0 DW_AT_external: 1 DW_AT_name: "operator integral_constant<bool, false>::value_type" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 6 DW_AT_decl_column: 13 DW_AT_linkage_name: "_ZNK17integral_constantIbLb0EEcvbEv" DW_AT_type: die -> 0 (0x7ffff6896a00) DW_AT_declaration: 1 ... DIE 0: DW_TAG_structure_type (0x7ffff6896a50) abbrev id: 0 offset: 0 mark: 0 DW_AT_name: "integral_constant<bool, false>" DW_AT_signature: die -> signature: 2e365acce74a6a1f (0x7ffff68962d0) DW_AT_declaration: 1 DIE 0: DW_TAG_typedef (0x7ffff6896a00) abbrev id: 0 offset: 0 mark: 0 DW_AT_name: "value_type" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 5 DW_AT_decl_column: 15 DW_AT_type: die -> 0 (0x7ffff6896aa0) but the DW_AT_signature of the first one gets somehow mangled. So the "duplicate" is because originally it looks like DIE 0: DW_TAG_structure_type (0x7ffff68962d0) abbrev id: 0 offset: 0 mark: 0 DW_AT_name: "integral_constant<bool, false>" DW_AT_byte_size: 1 DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 2 DW_AT_decl_column: 8 DIE 0: DW_TAG_member (0x7ffff6896320) abbrev id: 0 offset: 0 mark: 0 DW_AT_name: "value" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 4 DW_AT_decl_column: 24 DW_AT_type: die -> 0 (0x7ffff68963c0) DW_AT_external: 1 DW_AT_declaration: 1 DW_AT_const_expr: 1 DW_AT_inline: 1 DIE 0: DW_TAG_typedef (0x7ffff6896460) abbrev id: 0 offset: 0 mark: 0 DW_AT_name: "value_type" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 5 DW_AT_decl_column: 15 DW_AT_type: die -> 0 (0x7ffff6896370) DIE 0: DW_TAG_subprogram (0x7ffff68964b0) abbrev id: 0 offset: 0 mark: 0 DW_AT_external: 1 DW_AT_name: "operator integral_constant<bool, false>::value_type" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 6 DW_AT_decl_column: 13 DW_AT_type: die -> 0 (0x7ffff6896460) DW_AT_declaration: 1 DW_AT_object_pointer: die -> 0 (0x7ffff6896500) DIE 0: DW_TAG_formal_parameter (0x7ffff6896500) abbrev id: 0 offset: 0 mark: 0 DW_AT_type: die -> 0 (0x7ffff6896550) DW_AT_artificial: 1 and we duplicate this out to DIE 0: DW_TAG_structure_type (0x7ffff6896820) abbrev id: 0 offset: 0 mark: 1 signature: 2e365acce74a6a1f DW_AT_name: "integral_constant<bool, false>" DW_AT_signature: die -> signature: 2e365acce74a6a1f (0x7ffff68962d0) DW_AT_declaration: 1 DIE 0: DW_TAG_member (0x7ffff6896320) abbrev id: 0 offset: 0 mark: 1 DW_AT_name: "value" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 4 DW_AT_decl_column: 24 DW_AT_type: die -> 0 (0x7ffff68963c0) DW_AT_external: 1 DW_AT_declaration: 1 DW_AT_const_expr: 1 DW_AT_inline: 1 DIE 0: DW_TAG_subprogram (0x7ffff68964b0) abbrev id: 0 offset: 0 mark: 1 DW_AT_external: 1 DW_AT_name: "operator integral_constant<bool, false>::value_type" DW_AT_decl_file: "t.ii" (0) DW_AT_decl_line: 6 DW_AT_decl_column: 13 DW_AT_linkage_name: "_ZNK17integral_constantIbLb0EEcvbEv" DW_AT_type: die -> 0 (0x7ffff6896460) DW_AT_declaration: 1 but now we have a reference in the DW_TAG_subprogram DIE to the (non-copied, original DIE for the typedef). The early output makes the first DW_AT_signature ref refer to the second internal one which looks weird and is what output_external_refs barfs on. This happens via #0 change_AT_die_ref (ref=0x7ffff69f14c8, new_die=<dw_die_ref 0x7ffff6896a50 DW_TAG_structure_type <parent=0x7ffff68960a0 DW_TAG_compile_unit>>) at /space/rguenther/src/svn/trunk2/gcc/dwarf2out.c:4794 #1 0x0000000000e1e5a3 in build_abbrev_table ( die=<dw_die_ref 0x7ffff6896820 DW_TAG_structure_type <parent=0x7ffff68960a0 DW_TAG_compile_unit>>, extern_map=0x3373980) at /space/rguenther/src/svn/trunk2/gcc/dwarf2out.c:9032 #2 0x0000000000e1e7e4 in build_abbrev_table ( die=<dw_die_ref 0x7ffff68960a0 DW_TAG_compile_unit>, extern_map=0x3373980) at /space/rguenther/src/svn/trunk2/gcc/dwarf2out.c:9081 #3 0x0000000000e22ea9 in output_comp_unit ( die=<dw_die_ref 0x7ffff68960a0 DW_TAG_compile_unit>, output_if_empty=1, dwo_id=0x0) at /space/rguenther/src/svn/trunk2/gcc/dwarf2out.c:10998 #4 0x0000000000e5d52b in dwarf2out_early_finish ( filename=0x7fffffffe28b "t.ii") at /space/rguenther/src/svn/trunk2/gcc/dwarf2out.c:32167 it's an odd place to do this "optimization", it also leaves DIEs in broken state. We can either change DW_AT_signature to DW_AT_specification (well, not really - both DIEs are DW_AT_declaration DIEs...) or fixup the second round of optimize_external_refs to not see "local" DW_AT_signature as external. Thus, Index: dwarf2out.c =================================================================== --- dwarf2out.c (revision 268260) +++ dwarf2out.c (working copy) @@ -8911,7 +8911,11 @@ optimize_external_refs_1 (dw_die_ref die struct external_ref *ref_p; if (is_type_die (die) - && (c = get_AT_ref (die, DW_AT_signature))) + && (c = get_AT_ref (die, DW_AT_signature)) + /* Make sure to not pick up optimized local refs from the + early LTO run of build_abbrev_table which performs the + actual redirection. */ + && c->comdat_type_p) { /* This is a local skeleton; use it for local references. */ ref_p = lookup_external_ref (map, c); ideally we'd run local ref optimization on _types_ just once... When I compare the FAT debug info part with non-LTO debug info I see the single type unit of the testcase output twice here (because we lack LTO copies of .debug_types, similar to PR88878).