]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Record aliased constructors and destructors.
authorKeith Seitz <keiths@redhat.com>
Tue, 21 Feb 2017 21:32:54 +0000 (13:32 -0800)
committerKeith Seitz <keiths@redhat.com>
Tue, 21 Feb 2017 21:32:54 +0000 (13:32 -0800)
gdb/c-typeprint.c
gdb/dwarf2read.c
gdb/gdbtypes.h
gdb/valops.c

index 75f6d61e907c38ef9986b4c00921b32eb2bc715c..5c8e0a024ef69c99eddc7140c9114f42eea98914 100644 (file)
@@ -1164,8 +1164,9 @@ c_type_print_base (struct type *type, struct ui_file *stream,
                    || is_destructor_name (physname)
                    || method_name[0] == '~';
 
-                 /* Do not print out artificial methods.  */
-                 if (TYPE_FN_FIELD_ARTIFICIAL (f, j))
+                 /* Do not print out artificial or alias methods.  */
+                 if (TYPE_FN_FIELD_ARTIFICIAL (f, j)
+                     || TYPE_FN_FIELD_ALIAS (f, j))
                    continue;
 
                  inner_cleanup = make_cleanup (null_cleanup, NULL);
index b697b3f17efa5ea722be979961fb1ea7ec085af0..4b8fdb93a2d836dcb838eb2634fd17bb2085f868 100644 (file)
@@ -1345,6 +1345,11 @@ struct fnfieldlist
 {
   const char *name;
   int length;
+
+  /* Number of additional fnfield slots to allocate for ctor/dtor
+     aliases.  */
+  int addl_fnfields;
+
   struct nextfnfield *head;
 };
 
@@ -1697,7 +1702,7 @@ static struct using_direct **using_directives (enum language);
 
 static void read_import_statement (struct die_info *die, struct dwarf2_cu *);
 
-static int read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu);
+static int read_imported_decl (struct die_info *die, struct dwarf2_cu *cu);
 
 static struct type *read_module_type (struct die_info *die,
                                      struct dwarf2_cu *cu);
@@ -8424,7 +8429,7 @@ process_die (struct die_info *die, struct dwarf2_cu *cu)
       break;
     case DW_TAG_imported_declaration:
       cu->processing_has_namespace_info = 1;
-      if (read_namespace_alias (die, cu))
+      if (read_imported_decl (die, cu))
        break;
       /* The declaration is not a global namespace alias: fall through.  */
     case DW_TAG_imported_module:
@@ -8893,24 +8898,64 @@ dwarf2_physname (const char *name, struct die_info *die, struct dwarf2_cu *cu)
   return retval;
 }
 
-/* Inspect DIE in CU for a namespace alias.  If one exists, record
+/* Add a ctor or dtor method or alias to PARENT_TYPE.
+
+   NAME_DIE/NAME_CU is the DIE/CU that contains the name of this xtor.
+   TYPE_DIE/TYPE_CU is the DIE/CU that contains the method to which the
+   name is aliased and may (both) be NULL to indicate
+   that it is the same as NAME_DIE/CU, i.e., not aliased.  */
+
+static void
+add_xtor_field (struct type *parent_type,
+               struct die_info *name_die, struct dwarf2_cu *name_cu,
+               struct die_info *type_die, struct dwarf2_cu *type_cu,
+               const char *name)
+{
+  int i;
+
+  for (i = 0; i < TYPE_NFN_FIELDS (parent_type); ++i)
+    {
+      struct fn_field *methods = TYPE_FN_FIELDLIST1 (parent_type, i);
+
+      if (streq (TYPE_FN_FIELDLIST_NAME (parent_type, i), name))
+       {
+         short idx;
+
+         /* Add a new fnfield.  Memory for this was pre-allocated
+            when we saw the constructor definition in the parent
+            type.  See struct fnfieldlist.addl_fnfields.  */
+         idx = (TYPE_FN_FIELDLIST_LENGTH (parent_type, i))++;
+         methods[idx] = new_fn_field (name_die, name_cu, type_die, type_cu,
+                                      parent_type, name, idx, i);
+
+         /* If this is an aliased xtor, mark it as an alias so that
+            it will be ignored during symbol searches and type printing.  */
+         if (name_die != type_die)
+           TYPE_FN_FIELD_ALIAS (methods, idx) = 1;
+
+         return;
+       }
+    }
+}
+
+/* Inspect DIE in CU for a namespace or symbol  alias.  If one exists, record
    a new symbol for it.
 
-   Returns 1 if a namespace alias was recorded, 0 otherwise.  */
+   Returns 1 if an alias was recorded, 0 otherwise.  */
 
 static int
-read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu)
+read_imported_decl (struct die_info *die, struct dwarf2_cu *cu)
 {
   struct attribute *attr;
 
-  /* If the die does not have a name, this is not a namespace
-     alias.  */
+  /* If the die does not have a name, this is not an alias.  */
   attr = dwarf2_attr (die, DW_AT_name, cu);
   if (attr != NULL)
     {
       int num;
       struct die_info *d = die;
       struct dwarf2_cu *imported_cu = cu;
+      const char *name = dwarf2_name (die, cu);
 
       /* If the compiler has nested DW_AT_imported_declaration DIEs,
         keep inspecting DIEs until we hit the underlying import.  */
@@ -8947,6 +8992,68 @@ read_namespace_alias (struct die_info *die, struct dwarf2_cu *cu)
              new_symbol (die, type, cu);
              return 1;
            }
+         else
+           {
+             const char *linkage_name = dw2_linkage_name (die, cu);
+
+             /* Handle imported (aka "aliased") constructors and
+                destructors.  */
+             if (linkage_name != NULL)
+               {
+                 enum ctor_kinds ctor_kind;
+                 enum dtor_kinds dtor_kind = not_dtor;
+
+                 ctor_kind = is_constructor_name (linkage_name);
+                 if (ctor_kind == not_ctor)
+                   dtor_kind = is_destructor_name (linkage_name);
+
+                 /* GCC outputs imported_declaration for C1 constructors
+                    and D1 destructors which alias to the C4/D4/unified
+                    ctor/dtor listed in the parent class's DIE tree.
+                    Deal with those here.  */
+                 if (ctor_kind !=  not_ctor || dtor_kind != not_dtor)
+                   {
+                     struct die_info *imported_die, *spec_die, *parent_die;
+                     struct die_info *type_die;
+                     struct dwarf2_cu *imported_cu, *spec_cu, *parent_cu;
+                     struct dwarf2_cu *type_cu;
+                     struct type *parent_type;
+
+                     /* If there is a specification DIE, use that as the
+                        parent DIE.  */
+                     imported_cu = cu;
+                     imported_die = follow_die_ref (die, attr, &imported_cu);
+                     if (imported_die == NULL)
+                       return 0;
+
+                     spec_cu = imported_cu;
+                     spec_die = die_specification (imported_die, &spec_cu);
+                     if (spec_die != NULL)
+                       {
+                         parent_die = spec_die->parent;
+                         parent_cu = spec_cu;
+                         type_die = spec_die;
+                         type_cu = spec_cu;
+                       }
+                     else
+                       {
+                         parent_die = imported_die->parent;
+                         parent_cu = imported_cu;
+                         type_die = imported_die;
+                         type_cu = imported_cu;
+                       }
+                     parent_type
+                       = get_die_type_at_offset (parent_die->offset,
+                                                 parent_cu->per_cu);
+                     if (parent_type != NULL)
+                       {
+                         add_xtor_field (parent_type, die, cu,
+                                         type_die, type_cu, name);
+                         return 1;
+                       }
+                   }
+               }
+           }
        }
     }
 
@@ -11422,6 +11529,51 @@ inherit_abstract_dies (struct die_info *die, struct dwarf2_cu *cu)
   do_cleanups (cleanups);
 }
 
+/* If DIE represents a constructor or destructor, add an alias
+   to the parent type's fieldlist.  */
+
+static void
+possibly_add_new_xtor_method (const char *name, struct die_info *die,
+                             struct dwarf2_cu *cu)
+{
+  const char *linkage_name = dw2_linkage_name (die, cu);
+
+  if (linkage_name == NULL || cu->language != language_cplus)
+    return;
+
+  enum ctor_kinds ctor_kind = is_constructor_name (linkage_name);
+
+  if (ctor_kind == not_ctor)
+    {
+      enum dtor_kinds dtor_kind = is_destructor_name (linkage_name);
+
+      if (dtor_kind == not_dtor)
+       return;
+    }
+
+  if (dwarf2_attr (die, DW_AT_specification, cu))
+    {
+      struct dwarf2_cu *spec_cu = cu;
+      struct die_info *spec_die = die_specification (die, &spec_cu);
+      const char *spec_linkage_name
+       = dw2_linkage_name (spec_die, spec_cu);
+
+      if (streq (linkage_name, spec_linkage_name))
+       return;
+
+      if (spec_die->parent != NULL)
+       {
+         int i;
+         struct type *parent_type;
+
+         parent_type
+           = get_die_type_at_offset (spec_die->parent->offset, cu->per_cu);
+
+         add_xtor_field (parent_type, die, cu, NULL, NULL, name);
+       }
+    }
+}
+
 static void
 read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
 {
@@ -11616,6 +11768,8 @@ read_func_scope (struct die_info *die, struct dwarf2_cu *cu)
        }
     }
 
+  possibly_add_new_xtor_method (name, die, cu);
+
   /* In C++, we can have functions nested inside functions (e.g., when
      a function declares a class that has methods).  This means that
      when we finish processing a function scope, we may need to go
@@ -13394,6 +13548,7 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
       flp->name = fieldname;
       flp->length = 0;
       flp->head = NULL;
+      flp->addl_fnfields = 0;
       i = fip->nfnfields++;
     }
 
@@ -13409,6 +13564,19 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
   /* Fill in the member function field info.  */
   new_fnfield->fnfield = new_fn_field (die, cu, NULL, NULL, type, fieldname,
                                       flp->length - 1, i);
+  /* Reserve additional fnfields for aliased constructors and destructors.  */
+  if (new_fnfield->fnfield.is_constructor)
+    {
+      /* Reserve two additional fields for C1 and C2 aliases.  */
+      /* [We could do this only when we see the C4/unified ctor,
+        but it is safest to always do this.]  */
+      flp->addl_fnfields += 2;
+    }
+  else if (new_fnfield->fnfield.is_destructor)
+    {
+      /* Reserve three additional fields for D0, D1, and D2 aliases.  */
+      flp->addl_fnfields += 3;
+    }
 }
 
 /* Create the vector of member function fields, and attach it to the type.  */
@@ -13431,12 +13599,13 @@ dwarf2_attach_fn_fields_to_type (struct field_info *fip, struct type *type,
     {
       struct nextfnfield *nfp = flp->head;
       struct fn_fieldlist *fn_flp = &TYPE_FN_FIELDLIST (type, i);
-      int k;
+      int k, num;
 
       TYPE_FN_FIELDLIST_NAME (type, i) = flp->name;
       TYPE_FN_FIELDLIST_LENGTH (type, i) = flp->length;
+      num = flp->length + flp->addl_fnfields;
       fn_flp->fn_fields = (struct fn_field *)
-       TYPE_ALLOC (type, sizeof (struct fn_field) * flp->length);
+       TYPE_ALLOC (type, sizeof (struct fn_field) * num);
       for (k = flp->length; (k--, nfp); nfp = nfp->next)
        fn_flp->fn_fields[k] = nfp->fnfield;
     }
index 12e3841ca99756fef7145b8a02bc92e72998db4c..f5a1a4d62196c3fc3132df6281a2b9cb623d6307 100644 (file)
@@ -876,7 +876,7 @@ struct fn_field
   /* * True if this function is aliased to an existing fn_field,
      false otherwise.  These functions should be skipped during symbol
      lookups or type printing.  */
-  unsigned int is_duplicate : 1;
+  unsigned int is_alias : 1;
 
   /* * Unused.  */
 
@@ -1450,6 +1450,7 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
 #define TYPE_FN_FIELD_STUB(thisfn, n) ((thisfn)[n].is_stub)
 #define TYPE_FN_FIELD_CONSTRUCTOR(thisfn, n) ((thisfn)[n].is_constructor)
 #define TYPE_FN_FIELD_DESTRUCTOR(thisfn, n) ((thisfn)[n].is_destructor)
+#define TYPE_FN_FIELD_ALIAS(thisfn, n) ((thisfn)[n].is_alias)
 #define TYPE_FN_FIELD_FCONTEXT(thisfn, n) ((thisfn)[n].fcontext)
 #define TYPE_FN_FIELD_VOFFSET(thisfn, n) ((thisfn)[n].voffset-2)
 #define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1)
index fa25ff97382c99d92a12e3293be2faefedcd7bfe..fcd3cfbfca119fe33381cf1142939e57e8e81f3c 100644 (file)
@@ -2017,11 +2017,19 @@ search_struct_method (const char *name, struct value **arg1p,
        }
       if (t_field_name && (strcmp_iw (t_field_name, name) == 0))
        {
-         int j = TYPE_FN_FIELDLIST_LENGTH (type, i) - 1;
+         int j = 0, k;
          struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
 
          name_matched = 1;
          check_stub_method_group (type, i);
+
+         /* Count the number of non-aliased/duplicated methods.  */
+         for (k = 0; k < TYPE_FN_FIELDLIST_LENGTH (type, i); ++k)
+           {
+             if (!TYPE_FN_FIELD_ALIAS (f, k))
+               ++j;
+           }
+         --j;
          if (j > 0 && args == 0)
            error (_("cannot resolve overloaded method "
                     "`%s': no arguments supplied"), name);
@@ -3434,13 +3442,14 @@ value_struct_elt_for_reference (struct type *domain, int offset,
              j = -1;
              for (ii = 0; ii < len; ++ii)
                {
-                 /* Skip artificial methods.  This is necessary if,
-                    for example, the user wants to "print
+                 /* Skip artificial and aliased methods.  This is necessary
+                    if, for example, the user wants to "print
                     subclass::subclass" with only one user-defined
                     constructor.  There is no ambiguity in this case.
                     We are careful here to allow artificial methods
                     if they are the unique result.  */
-                 if (TYPE_FN_FIELD_ARTIFICIAL (f, ii))
+                 if (TYPE_FN_FIELD_ARTIFICIAL (f, ii)
+                     || TYPE_FN_FIELD_ALIAS (f, ii))
                    {
                      if (j == -1)
                        j = ii;
@@ -3449,7 +3458,8 @@ value_struct_elt_for_reference (struct type *domain, int offset,
 
                  /* Desired method is ambiguous if more than one
                     method is defined.  */
-                 if (j != -1 && !TYPE_FN_FIELD_ARTIFICIAL (f, j))
+                 if (j != -1 && !TYPE_FN_FIELD_ARTIFICIAL (f, j)
+                     && !TYPE_FN_FIELD_ALIAS (f, j))
                    error (_("non-unique member `%s' requires "
                             "type instantiation"), name);