If a CodeView struct, class, or union has as a member an anonymous
struct, class, or union, this gets flattened. The sub-struct's members
will appear as if they were part of their parent.

For this, we move part of get_type_num_struct into a new function
add_to_fieldlist, which also handles creating an LF_INDEX overflow item
if an LF_FIELDLIST grows too large. This is because add_struct_member
now calls itself recursively, and so needs to handle overflows itself.

gcc/
        * dwarf2codeview.cc (add_to_fieldlist): New function.
        (add_struct_member): Call recursively to flatten structs, and call
        add_to_fieldlist.
        (add_struct_static_member): Call add_to_fieldlist.
        (add_struct_function): Call add_to_fieldlist.
        (add_struct_inheritance): Call add_to_fieldlist.
        (add_struct_nested_type): Call add_to_fieldlist.
        (get_type_num_struct): Move code to add_to_fieldlist, and move
        responsibility for this to subfunctions.
---
 gcc/dwarf2codeview.cc | 280 +++++++++++++++++++++++++-----------------
 1 file changed, 167 insertions(+), 113 deletions(-)

diff --git a/gcc/dwarf2codeview.cc b/gcc/dwarf2codeview.cc
index 261fcea6a97..59380335991 100644
--- a/gcc/dwarf2codeview.cc
+++ b/gcc/dwarf2codeview.cc
@@ -5901,6 +5901,52 @@ add_struct_forward_def (dw_die_ref type)
   return ct->num;
 }
 
+/* Add a new subtype to an LF_FIELDLIST type, and handle overflows if
+   necessary.  */
+
+static void
+add_to_fieldlist (codeview_custom_type **ct, uint16_t *num_members,
+                 codeview_subtype *el, size_t el_len)
+{
+  /* Add an LF_INDEX subtype if everything's too big for one
+     LF_FIELDLIST.  */
+
+  if ((*ct)->lf_fieldlist.length + el_len > MAX_FIELDLIST_SIZE)
+    {
+      codeview_subtype *idx;
+      codeview_custom_type *ct2;
+
+      idx = (codeview_subtype *) xmalloc (sizeof (*idx));
+      idx->next = NULL;
+      idx->kind = LF_INDEX;
+      idx->lf_index.type_num = 0;
+
+      (*ct)->lf_fieldlist.last_subtype->next = idx;
+      (*ct)->lf_fieldlist.last_subtype = idx;
+
+      ct2 = (codeview_custom_type *)
+       xmalloc (sizeof (codeview_custom_type));
+
+      ct2->next = *ct;
+      ct2->kind = LF_FIELDLIST;
+      ct2->lf_fieldlist.length = 0;
+      ct2->lf_fieldlist.subtypes = NULL;
+      ct2->lf_fieldlist.last_subtype = NULL;
+
+      *ct = ct2;
+    }
+
+  (*ct)->lf_fieldlist.length += el_len;
+
+  if ((*ct)->lf_fieldlist.last_subtype)
+    (*ct)->lf_fieldlist.last_subtype->next = el;
+  else
+    (*ct)->lf_fieldlist.subtypes = el;
+
+  (*ct)->lf_fieldlist.last_subtype = el;
+  (*num_members)++;
+}
+
 /* Add an LF_BITFIELD type, returning its number.  DWARF represents bitfields
    as members in a struct with a DW_AT_data_bit_offset attribute, whereas in
    CodeView they're a distinct type.  */
@@ -5933,36 +5979,69 @@ create_bitfield (dw_die_ref c)
 
 static void
 add_struct_member (dw_die_ref c, uint16_t accessibility,
-                  codeview_subtype **el, size_t *el_len)
+                  codeview_custom_type **ct, uint16_t *num_members,
+                  unsigned int base_offset)
 {
-  *el = (codeview_subtype *) xmalloc (sizeof (**el));
-  (*el)->next = NULL;
-  (*el)->kind = LF_MEMBER;
-  (*el)->lf_member.attributes = accessibility;
+  codeview_subtype *el;
+  size_t el_len;
+  dw_die_ref type = get_AT_ref (c, DW_AT_type);
+  unsigned int offset;
+
+  offset = base_offset + get_AT_unsigned (c, DW_AT_data_member_location);
+
+  /* If the data member is actually an anonymous struct, class, or union,
+     follow MSVC by flattening this into its parent.  */
+  if (!get_AT_string (c, DW_AT_name) && type
+      && (dw_get_die_tag (type) == DW_TAG_structure_type
+      || dw_get_die_tag (type) == DW_TAG_class_type
+      || dw_get_die_tag (type) == DW_TAG_union_type))
+    {
+      dw_die_ref c2, first_child;
+
+      first_child = dw_get_die_child (type);
+      c2 = first_child;
+
+      do
+       {
+         c2 = dw_get_die_sib (c2);
+
+         if (dw_get_die_tag (c2) == DW_TAG_member)
+             add_struct_member (c2, accessibility, ct, num_members, offset);
+       }
+      while (c2 != first_child);
+
+      return;
+    }
+
+  el = (codeview_subtype *) xmalloc (sizeof (*el));
+  el->next = NULL;
+  el->kind = LF_MEMBER;
+  el->lf_member.attributes = accessibility;
 
   if (get_AT (c, DW_AT_data_bit_offset))
-    (*el)->lf_member.type = create_bitfield (c);
+    el->lf_member.type = create_bitfield (c);
   else
-    (*el)->lf_member.type = get_type_num (get_AT_ref (c, DW_AT_type),
-                                         true, false);
+    el->lf_member.type = get_type_num (type, true, false);
 
-  (*el)->lf_member.offset.neg = false;
-  (*el)->lf_member.offset.num = get_AT_unsigned (c, 
DW_AT_data_member_location);
+  el->lf_member.offset.neg = false;
+  el->lf_member.offset.num = offset;
 
-  *el_len = 11 + cv_integer_len (&(*el)->lf_member.offset);
+  el_len = 11 + cv_integer_len (&el->lf_member.offset);
 
   if (get_AT_string (c, DW_AT_name))
     {
-      (*el)->lf_member.name = xstrdup (get_AT_string (c, DW_AT_name));
-      *el_len += strlen ((*el)->lf_member.name);
+      el->lf_member.name = xstrdup (get_AT_string (c, DW_AT_name));
+      el_len += strlen (el->lf_member.name);
     }
   else
     {
-      (*el)->lf_member.name = NULL;
+      el->lf_member.name = NULL;
     }
 
-  if (*el_len % 4)
-    *el_len += 4 - (*el_len % 4);
+  if (el_len % 4)
+    el_len += 4 - (el_len % 4);
+
+  add_to_fieldlist (ct, num_members, el, el_len);
 }
 
 /* Create an LF_STMEMBER field list subtype for a static struct member,
@@ -5970,20 +6049,25 @@ add_struct_member (dw_die_ref c, uint16_t accessibility,
 
 static void
 add_struct_static_member (dw_die_ref c, uint16_t accessibility,
-                         codeview_subtype **el, size_t *el_len)
+                         codeview_custom_type **ct, uint16_t *num_members)
 {
-  *el = (codeview_subtype *) xmalloc (sizeof (**el));
-  (*el)->next = NULL;
-  (*el)->kind = LF_STMEMBER;
-  (*el)->lf_static_member.attributes = accessibility;
-  (*el)->lf_static_member.type = get_type_num (get_AT_ref (c, DW_AT_type),
-                                              true, false);
-  (*el)->lf_static_member.name = xstrdup (get_AT_string (c, DW_AT_name));
-
-  *el_len = 9 + strlen ((*el)->lf_static_member.name);
-
-  if (*el_len % 4)
-    *el_len += 4 - (*el_len % 4);
+  codeview_subtype *el;
+  size_t el_len;
+
+  el = (codeview_subtype *) xmalloc (sizeof (*el));
+  el->next = NULL;
+  el->kind = LF_STMEMBER;
+  el->lf_static_member.attributes = accessibility;
+  el->lf_static_member.type = get_type_num (get_AT_ref (c, DW_AT_type),
+                                           true, false);
+  el->lf_static_member.name = xstrdup (get_AT_string (c, DW_AT_name));
+
+  el_len = 9 + strlen (el->lf_static_member.name);
+
+  if (el_len % 4)
+    el_len += 4 - (el_len % 4);
+
+  add_to_fieldlist (ct, num_members, el, el_len);
 }
 
 /* Create a field list subtype for a struct function, returning its pointer in
@@ -5994,10 +6078,12 @@ add_struct_static_member (dw_die_ref c, uint16_t 
accessibility,
 
 static void
 add_struct_function (dw_die_ref c, hash_table<method_hasher> *method_htab,
-                    codeview_subtype **el, size_t *el_len)
+                    codeview_custom_type **ct, uint16_t *num_members)
 {
   const char *name = get_AT_string (c, DW_AT_name);
   codeview_method **slot, *meth;
+  codeview_subtype *el;
+  size_t el_len;
 
   slot = method_htab->find_slot_with_hash (name, htab_hash_string (name),
                                           NO_INSERT);
@@ -6006,17 +6092,17 @@ add_struct_function (dw_die_ref c, 
hash_table<method_hasher> *method_htab,
 
   meth = *slot;
 
-  *el = (codeview_subtype *) xmalloc (sizeof (**el));
-  (*el)->next = NULL;
+  el = (codeview_subtype *) xmalloc (sizeof (*el));
+  el->next = NULL;
 
   if (meth->count == 1)
     {
-      (*el)->kind = LF_ONEMETHOD;
-      (*el)->lf_onemethod.method_attribute = meth->attribute;
-      (*el)->lf_onemethod.method_type = meth->type;
-      (*el)->lf_onemethod.name = xstrdup (name);
+      el->kind = LF_ONEMETHOD;
+      el->lf_onemethod.method_attribute = meth->attribute;
+      el->lf_onemethod.method_type = meth->type;
+      el->lf_onemethod.name = xstrdup (name);
 
-      *el_len = 9 + strlen ((*el)->lf_onemethod.name);
+      el_len = 9 + strlen (el->lf_onemethod.name);
     }
   else
     {
@@ -6041,16 +6127,18 @@ add_struct_function (dw_die_ref c, 
hash_table<method_hasher> *method_htab,
 
       add_custom_type (ct);
 
-      (*el)->kind = LF_METHOD;
-      (*el)->lf_method.count = meth->count;
-      (*el)->lf_method.method_list = ct->num;
-      (*el)->lf_method.name = xstrdup (name);
+      el->kind = LF_METHOD;
+      el->lf_method.count = meth->count;
+      el->lf_method.method_list = ct->num;
+      el->lf_method.name = xstrdup (name);
 
-      *el_len = 9 + strlen ((*el)->lf_method.name);
+      el_len = 9 + strlen (el->lf_method.name);
     }
 
-  if (*el_len % 4)
-    *el_len += 4 - (*el_len % 4);
+  if (el_len % 4)
+    el_len += 4 - (el_len % 4);
+
+  add_to_fieldlist (ct, num_members, el, el_len);
 
   method_htab->remove_elt_with_hash (name, htab_hash_string (name));
 
@@ -6069,27 +6157,32 @@ add_struct_function (dw_die_ref c, 
hash_table<method_hasher> *method_htab,
 
 static void
 add_struct_inheritance (dw_die_ref c, uint16_t accessibility,
-                       codeview_subtype **el, size_t *el_len)
+                       codeview_custom_type **ct, uint16_t *num_members)
 {
+  codeview_subtype *el;
+  size_t el_len;
+
   /* FIXME: if DW_AT_virtuality is DW_VIRTUALITY_virtual this is a virtual
            base class, and we should be issuing an LF_VBCLASS record
            instead.  */
   if (get_AT_unsigned (c, DW_AT_virtuality) == DW_VIRTUALITY_virtual)
     return;
 
-  *el = (codeview_subtype *) xmalloc (sizeof (**el));
-  (*el)->next = NULL;
-  (*el)->kind = LF_BCLASS;
-  (*el)->lf_bclass.attributes = accessibility;
-  (*el)->lf_bclass.base_class_type = get_type_num (get_AT_ref (c, DW_AT_type),
+  el = (codeview_subtype *) xmalloc (sizeof (*el));
+  el->next = NULL;
+  el->kind = LF_BCLASS;
+  el->lf_bclass.attributes = accessibility;
+  el->lf_bclass.base_class_type = get_type_num (get_AT_ref (c, DW_AT_type),
                                                   true, false);
-  (*el)->lf_bclass.offset.neg = false;
-  (*el)->lf_bclass.offset.num = get_AT_unsigned (c, 
DW_AT_data_member_location);
+  el->lf_bclass.offset.neg = false;
+  el->lf_bclass.offset.num = get_AT_unsigned (c, DW_AT_data_member_location);
 
-  *el_len = 10 + cv_integer_len (&(*el)->lf_bclass.offset);
+  el_len = 10 + cv_integer_len (&el->lf_bclass.offset);
 
-  if (*el_len % 4)
-    *el_len += 4 - (*el_len % 4);
+  if (el_len % 4)
+    el_len += 4 - (el_len % 4);
+
+  add_to_fieldlist (ct, num_members, el, el_len);
 }
 
 /* Create a new LF_MFUNCTION type for a struct function, add it to the
@@ -6186,26 +6279,30 @@ is_templated_func (dw_die_ref die)
    contained within it.  */
 
 static void
-add_struct_nested_type (dw_die_ref c, codeview_subtype **el, size_t *el_len)
+add_struct_nested_type (dw_die_ref c, codeview_custom_type **ct,
+                       uint16_t *num_members)
 {
   const char *name = get_AT_string (c, DW_AT_name);
-  size_t name_len;
+  codeview_subtype *el;
+  size_t name_len, el_len;
 
   if (!name)
     return;
 
   name_len = strlen (name);
 
-  *el = (codeview_subtype *) xmalloc (sizeof (**el));
-  (*el)->next = NULL;
-  (*el)->kind = LF_NESTTYPE;
-  (*el)->lf_nesttype.type = get_type_num (c, true, false);
-  (*el)->lf_nesttype.name = xstrdup (name);
+  el = (codeview_subtype *) xmalloc (sizeof (*el));
+  el->next = NULL;
+  el->kind = LF_NESTTYPE;
+  el->lf_nesttype.type = get_type_num (c, true, false);
+  el->lf_nesttype.name = xstrdup (name);
 
-  *el_len = 9 + name_len;
+  el_len = 9 + name_len;
 
-  if (*el_len % 4)
-    *el_len += 4 - (*el_len % 4);
+  if (el_len % 4)
+    el_len += 4 - (el_len % 4);
+
+  add_to_fieldlist (ct, num_members, el, el_len);
 }
 
 /* Process a DW_TAG_structure_type, DW_TAG_class_type, or DW_TAG_union_type
@@ -6319,8 +6416,6 @@ get_type_num_struct (dw_die_ref type, bool in_struct, 
bool *is_fwd_ref)
       c = first_child;
       do
        {
-         codeview_subtype *el;
-         size_t el_len = 0;
          uint16_t accessibility;
 
          c = dw_get_die_sib (c);
@@ -6330,73 +6425,32 @@ get_type_num_struct (dw_die_ref type, bool in_struct, 
bool *is_fwd_ref)
          switch (dw_get_die_tag (c))
            {
            case DW_TAG_member:
-             add_struct_member (c, accessibility, &el, &el_len);
+             add_struct_member (c, accessibility, &ct, &num_members, 0);
              break;
 
            case DW_TAG_variable:
-             add_struct_static_member (c, accessibility, &el, &el_len);
+             add_struct_static_member (c, accessibility, &ct, &num_members);
              break;
 
            case DW_TAG_subprogram:
              if (!is_templated_func (c))
-               add_struct_function (c, method_htab, &el, &el_len);
+               add_struct_function (c, method_htab, &ct, &num_members);
              break;
 
            case DW_TAG_inheritance:
-             add_struct_inheritance (c, accessibility, &el, &el_len);
+             add_struct_inheritance (c, accessibility, &ct, &num_members);
              break;
 
            case DW_TAG_structure_type:
            case DW_TAG_class_type:
            case DW_TAG_union_type:
            case DW_TAG_enumeration_type:
-             add_struct_nested_type (c, &el, &el_len);
+             add_struct_nested_type (c, &ct, &num_members);
              break;
 
            default:
              break;
            }
-
-         if (el_len == 0)
-           continue;
-
-         /* Add an LF_INDEX subtype if everything's too big for one
-            LF_FIELDLIST.  */
-
-         if (ct->lf_fieldlist.length + el_len > MAX_FIELDLIST_SIZE)
-           {
-             codeview_subtype *idx;
-             codeview_custom_type *ct2;
-
-             idx = (codeview_subtype *) xmalloc (sizeof (*idx));
-             idx->next = NULL;
-             idx->kind = LF_INDEX;
-             idx->lf_index.type_num = 0;
-
-             ct->lf_fieldlist.last_subtype->next = idx;
-             ct->lf_fieldlist.last_subtype = idx;
-
-             ct2 = (codeview_custom_type *)
-               xmalloc (sizeof (codeview_custom_type));
-
-             ct2->next = ct;
-             ct2->kind = LF_FIELDLIST;
-             ct2->lf_fieldlist.length = 0;
-             ct2->lf_fieldlist.subtypes = NULL;
-             ct2->lf_fieldlist.last_subtype = NULL;
-
-             ct = ct2;
-           }
-
-         ct->lf_fieldlist.length += el_len;
-
-         if (ct->lf_fieldlist.last_subtype)
-           ct->lf_fieldlist.last_subtype->next = el;
-         else
-           ct->lf_fieldlist.subtypes = el;
-
-         ct->lf_fieldlist.last_subtype = el;
-         num_members++;
        }
       while (c != first_child);
 
-- 
2.45.2

Reply via email to