OK.
On Fri, Mar 9, 2018 at 1:15 PM, Jakub Jelinek <ja...@redhat.com> wrote: > Hi! > > As the following testcase shows, we emit bad debug info if a scoped > enum is used before the enumerators are defined. > gen_enumeration_type_die has support for enum forward declarations that > have NULL TYPE_SIZE (i.e. incomplete), but in this case it is complete, > just is ENUM_IS_OPAQUE and the enumerators aren't there. We still set > TREE_ASM_WRITTEN on it and therefore don't do anything when it actually is > completed. > > The following patch does change/fix a bunch of things: > 1) I don't see the point of guarding the addition of DW_AT_declaration > to just -gdwarf-4 or -gno-strict-dwarf, that is already DWARF2 attribute and > we are emitting it for the forward declarations already > 2) we don't set TREE_ASM_WRITTEN if ENUM_IS_OPAQUE > 3) we don't try to do anything if it is ENUM_IS_OPAQUE that hasn't been > newly created; similarly to incomplete forward redeclarations, we should > have provided all that is needed on the first declaration > 4) the addition of most attributes guarded with TYPE_SIZE is guarded by > (!original_type_die || !get_AT (type_die, DW_AT_...)); the > !original_type_die || part is just an optimization, so we don't try to query > it in the common cases where we are creating a fresh type die; anyway, the > reason for the guards is that we can now do the code twice for the same > type_die (on declaration and definition), and don't want to add the attributes > twice > 5) not sure if ENUM_IS_OPAQUE must always imply non-NULL TYPE_SIZE, if not, > in that case we'd add the DW_AT_deprecated attribute twice > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? > > 2018-03-09 Jakub Jelinek <ja...@redhat.com> > > PR debug/58150 > * dwarf2out.c (gen_enumeration_type_die): Don't guard adding > DW_AT_declaration for ENUM_IS_OPAQUE on -gdwarf-4 or > -gno-strict-dwarf, > but on TYPE_SIZE. Don't do anything for ENUM_IS_OPAQUE if not > creating > a new die. Don't set TREE_ASM_WRITTEN if ENUM_IS_OPAQUE. Guard > addition of most attributes on !orig_type_die or the attribute not > being present already. Assert TYPE_VALUES is NULL for ENUM_IS_OPAQUE. > > * g++.dg/debug/dwarf2/enum2.C: New test. > > --- gcc/dwarf2out.c.jj 2018-03-08 22:49:41.965225512 +0100 > +++ gcc/dwarf2out.c 2018-03-09 14:53:15.596115625 +0100 > @@ -21839,6 +21839,7 @@ static dw_die_ref > gen_enumeration_type_die (tree type, dw_die_ref context_die) > { > dw_die_ref type_die = lookup_type_die (type); > + dw_die_ref orig_type_die = type_die; > > if (type_die == NULL) > { > @@ -21846,20 +21847,18 @@ gen_enumeration_type_die (tree type, dw_ > scope_die_for (type, context_die), type); > equate_type_number_to_die (type, type_die); > add_name_attribute (type_die, type_tag (type)); > - if (dwarf_version >= 4 || !dwarf_strict) > - { > - if (ENUM_IS_SCOPED (type)) > - add_AT_flag (type_die, DW_AT_enum_class, 1); > - if (ENUM_IS_OPAQUE (type)) > - add_AT_flag (type_die, DW_AT_declaration, 1); > - } > + if ((dwarf_version >= 4 || !dwarf_strict) > + && ENUM_IS_SCOPED (type)) > + add_AT_flag (type_die, DW_AT_enum_class, 1); > + if (ENUM_IS_OPAQUE (type) && TYPE_SIZE (type)) > + add_AT_flag (type_die, DW_AT_declaration, 1); > if (!dwarf_strict) > add_AT_unsigned (type_die, DW_AT_encoding, > TYPE_UNSIGNED (type) > ? DW_ATE_unsigned > : DW_ATE_signed); > } > - else if (! TYPE_SIZE (type)) > + else if (! TYPE_SIZE (type) || ENUM_IS_OPAQUE (type)) > return type_die; > else > remove_AT (type_die, DW_AT_declaration); > @@ -21871,10 +21870,14 @@ gen_enumeration_type_die (tree type, dw_ > { > tree link; > > - TREE_ASM_WRITTEN (type) = 1; > - add_byte_size_attribute (type_die, type); > - add_alignment_attribute (type_die, type); > - if (dwarf_version >= 3 || !dwarf_strict) > + if (!ENUM_IS_OPAQUE (type)) > + TREE_ASM_WRITTEN (type) = 1; > + if (!orig_type_die || !get_AT (type_die, DW_AT_byte_size)) > + add_byte_size_attribute (type_die, type); > + if (!orig_type_die || !get_AT (type_die, DW_AT_alignment)) > + add_alignment_attribute (type_die, type); > + if ((dwarf_version >= 3 || !dwarf_strict) > + && (!orig_type_die || !get_AT (type_die, DW_AT_type))) > { > tree underlying = lang_hooks.types.enum_underlying_base_type (type); > add_type_attribute (type_die, underlying, TYPE_UNQUALIFIED, false, > @@ -21882,8 +21885,10 @@ gen_enumeration_type_die (tree type, dw_ > } > if (TYPE_STUB_DECL (type) != NULL_TREE) > { > - add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); > - add_accessibility_attribute (type_die, TYPE_STUB_DECL (type)); > + if (!orig_type_die || !get_AT (type_die, DW_AT_decl_file)) > + add_src_coords_attributes (type_die, TYPE_STUB_DECL (type)); > + if (!orig_type_die || !get_AT (type_die, DW_AT_accessibility)) > + add_accessibility_attribute (type_die, TYPE_STUB_DECL (type)); > } > > /* If the first reference to this type was as the return type of an > @@ -21897,6 +21902,7 @@ gen_enumeration_type_die (tree type, dw_ > dw_die_ref enum_die = new_die (DW_TAG_enumerator, type_die, link); > tree value = TREE_VALUE (link); > > + gcc_assert (!ENUM_IS_OPAQUE (type)); > add_name_attribute (enum_die, > IDENTIFIER_POINTER (TREE_PURPOSE (link))); > > @@ -21926,7 +21932,8 @@ gen_enumeration_type_die (tree type, dw_ > } > > add_gnat_descriptive_type_attribute (type_die, type, context_die); > - if (TYPE_ARTIFICIAL (type)) > + if (TYPE_ARTIFICIAL (type) > + && (!orig_type_die || !get_AT (type_die, DW_AT_artificial))) > add_AT_flag (type_die, DW_AT_artificial, 1); > } > else > --- gcc/testsuite/g++.dg/debug/dwarf2/enum2.C.jj 2018-03-09 > 15:14:44.982388983 +0100 > +++ gcc/testsuite/g++.dg/debug/dwarf2/enum2.C 2018-03-09 15:14:28.449385285 > +0100 > @@ -0,0 +1,30 @@ > +// PR debug/58150 > +// { dg-do compile } > +// { dg-options "-std=c++11 -gdwarf-4 -dA -fno-merge-debug-strings" } > +// { dg-final { scan-assembler-times "DIE\[^\n\r\]*DW_TAG_enumeration_type" > 3 } } > +// { dg-final { scan-assembler-times " DW_AT_enum_class" 3 } } > +// { dg-final { scan-assembler-times " DW_AT_declaration" 1 } } > +// { dg-final { scan-assembler-times "\"E1..\"\[^\n\]*DW_AT_name" 1 } } > +// { dg-final { scan-assembler-times "\"E2..\"\[^\n\]*DW_AT_name" 1 } } > +// { dg-final { scan-assembler-times "\"F1..\"\[^\n\]*DW_AT_name" 1 } } > +// { dg-final { scan-assembler-times "\"F2..\"\[^\n\]*DW_AT_name" 1 } } > + > +enum class E : int; > +enum class F : int; > +enum class G : int; > +struct S { E s; }; > +struct T { G t; }; > +enum class E : int > +{ > + E1, E2 > +}; > +enum class F : int > +{ > + F1, F2 > +}; > + > +bool > +foo (E e, F f, G g) > +{ > + return e == E::E1 && f == F::F1 && (int) g == 0; > +} > > Jakub