non-zero. */
enum ctor_kinds {
+ /* Unrecognized or not a constructor. */
+ not_ctor = 0,
+
/* Initialize a complete object, including virtual bases, using
memory provided by caller. */
- complete_object_ctor = 1,
+ complete_object_ctor,
/* Initialize a base object of some larger object. */
base_object_ctor,
/* An allocating complete-object constructor. */
- complete_object_allocating_ctor
+ complete_object_allocating_ctor,
+
+ /* GCC's "unified" constructor. */
+ unified_ctor,
+
+ /* Deprecated? */
+ object_ctor_group
};
/* Return non-zero iff NAME is the mangled name of a constructor.
non-zero. */
enum dtor_kinds {
+ /* Unrecognized or not a destructor. */
+ not_dtor = 0,
+
/* A destructor which finalizes the entire object, and then calls
`delete' on its storage. */
- deleting_dtor = 1,
+ deleting_dtor,
/* A destructor which finalizes the entire object, but does not call
`delete'. */
/* A destructor which finalizes a subobject of some larger
object. */
- base_object_dtor
+ base_object_dtor,
+
+ /* GCC's "unified" destructor. */
+ unified_dtor,
+
+ /* Deprecated? */
+ object_dtor_group
};
/* Return non-zero iff NAME is the mangled name of a destructor.
const char *type_name;
int len;
+ /* If there is a linkage name, use it to determine if this DIE represents
+ a constructor. */
+ const char *linkage_name = dw2_linkage_name (die, cu);
+
+ if (linkage_name != NULL)
+ return is_constructor_name (linkage_name) != not_ctor;
+
+ /* Many older versions of GCC do not output DW_AT_linkage_name for
+ constructors. In that case, fallback to a heuristic test. */
if (die->parent == NULL)
return 0;
&& (type_name[len] == '\0' || type_name[len] == '<'));
}
+/* Return true if this member function is a destructor, false
+ otherwise. */
+
+static int
+dwarf2_is_destructor (struct die_info *die, struct dwarf2_cu *cu)
+{
+ /* If there is a linkage name, use it to determine if this DIE represents
+ a destructor. */
+ const char *linkage_name = dw2_linkage_name (die, cu);
+
+ if (linkage_name != NULL)
+ return is_destructor_name (linkage_name) != not_dtor;
+
+ if (die->parent == NULL)
+ return 0;
+
+ if (die->parent->tag != DW_TAG_structure_type
+ && die->parent->tag != DW_TAG_union_type
+ && die->parent->tag != DW_TAG_class_type)
+ return 0;
+
+ const char *fieldname = dwarf2_name (die, cu);
+
+ return (fieldname != NULL && *fieldname == '~');
+}
+
/* Create a new fn_field which may represent an alias to an existing
field (if a constructor or destructor). TYPE_DIE and TYPE_CU
may be NULL, in which case they default to NAME_DIE and NAME_CU,
fnfield.is_artificial = 1;
fnfield.is_constructor = dwarf2_is_constructor (name_die, type_cu);
+ if (fnfield.is_constructor)
+ {
+ const char *linkage_name = dw2_linkage_name (name_die, name_cu);
+
+ if (linkage_name != NULL)
+ {
+ fnfield.cdtor_type.ctor_kind = is_constructor_name (linkage_name);
+ gdb_assert (fnfield.cdtor_type.ctor_kind != not_ctor);
+ }
+ }
+ else
+ {
+ fnfield.is_destructor = dwarf2_is_destructor (name_die, name_cu);
+ if (fnfield.is_destructor)
+ {
+ const char *linkage_name = dw2_linkage_name (name_die, name_cu);
+
+ if (linkage_name != NULL)
+ {
+ fnfield.cdtor_type.dtor_kind = is_destructor_name (linkage_name);
+ gdb_assert (fnfield.cdtor_type.dtor_kind != not_dtor);
+ }
+ }
+ }
/* Get index in virtual function table if it is a virtual member
function. For older versions of GCC, this is an offset in the
*/
#include "hashtab.h"
+#include "cp-abi.h"
/* Forward declarations for prototypes. */
struct field;
struct type *fcontext;
+ /* If this method is a constructor or destructor, this field will describe
+ what kind of constructor or destructor it is. */
+
+ union
+ {
+ /* The type of this constructor if IS_CONSTRUCTOR. */
+ enum ctor_kinds ctor_kind;
+
+ /* The type of this destructor if IS_DESTRUCTOR. */
+ enum dtor_kinds dtor_kind;
+ } cdtor_type;
+
/* Attributes. */
unsigned int is_const:1;
unsigned int is_constructor : 1;
+ /* * True if this function is a destructor, false otherwise. */
+
+ unsigned int is_destructor : 1;
+
+ /* * 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;
+
/* * Unused. */
- unsigned int dummy:3;
+ unsigned int dummy:1;
/* * Index into that baseclass's virtual function table, minus 2;
else if static: VOFFSET_STATIC; else: 0. */
#define TYPE_FN_FIELD_ABSTRACT(thisfn, n) ((thisfn)[n].is_abstract)
#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_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)
|| startswith (name, "__dt__"))
return complete_object_dtor;
else
- return (enum dtor_kinds) 0;
+ return not_dtor;
}
static enum ctor_kinds
|| startswith (name, "__ct__"))
return complete_object_ctor;
else
- return (enum ctor_kinds) 0;
+ return not_ctor;
}
static int
return 0;
}
+/* Wrapper for libiberty's is_gnu_v3_mangled_ctor function which
+ maps libiberty's values onto our own set of return values. */
+
+static enum ctor_kinds
+gnuv3_is_constructor_name (const char *mangled_name)
+{
+ enum gnu_v3_ctor_kinds libiberty_kind;
+ enum ctor_kinds kind;
+
+ libiberty_kind = is_gnu_v3_mangled_ctor (mangled_name);
+
+ switch (libiberty_kind)
+ {
+ case 0:
+ kind = not_ctor;
+ break;
+ case gnu_v3_complete_object_ctor:
+ kind = complete_object_ctor;
+ break;
+ case gnu_v3_base_object_ctor:
+ kind = base_object_ctor;
+ break;
+ case gnu_v3_complete_object_allocating_ctor:
+ kind = complete_object_allocating_ctor;
+ break;
+ case gnu_v3_unified_ctor:
+ kind = unified_ctor;
+ break;
+ case gnu_v3_object_ctor_group:
+ kind = object_ctor_group;
+ break;
+ default:
+ gdb_assert_not_reached ("unhandled libiberty constructor kind");
+ }
+
+ return kind;
+}
+
+/* Wrapper for libiberty's is_gnu_v3_mangled_dtor function which
+ maps libiberty's values onto our own set of return values. */
+
+static enum dtor_kinds
+gnuv3_is_destructor_name (const char *mangled_name)
+{
+ enum gnu_v3_dtor_kinds libiberty_kind;
+ enum dtor_kinds kind;
+
+ libiberty_kind = is_gnu_v3_mangled_dtor (mangled_name);
+ switch (libiberty_kind)
+ {
+ case 0:
+ kind = not_dtor;
+ break;
+ case gnu_v3_deleting_dtor:
+ kind = deleting_dtor;
+ break;
+ case gnu_v3_complete_object_dtor:
+ kind = complete_object_dtor;
+ break;
+ case gnu_v3_base_object_dtor:
+ kind = base_object_dtor;
+ break;
+ case gnu_v3_unified_dtor:
+ kind = unified_dtor;
+ break;
+ case gnu_v3_object_dtor_group:
+ kind = object_dtor_group;
+ break;
+ default:
+ gdb_assert_not_reached ("unhandled libiberty destructor kind");
+ }
+
+ return kind;
+}
+
static void
init_gnuv3_ops (void)
{
gnu_v3_abi_ops.shortname = "gnu-v3";
gnu_v3_abi_ops.longname = "GNU G++ Version 3 ABI";
gnu_v3_abi_ops.doc = "G++ Version 3 ABI";
- gnu_v3_abi_ops.is_destructor_name =
- (enum dtor_kinds (*) (const char *))is_gnu_v3_mangled_dtor;
- gnu_v3_abi_ops.is_constructor_name =
- (enum ctor_kinds (*) (const char *))is_gnu_v3_mangled_ctor;
+ gnu_v3_abi_ops.is_destructor_name = gnuv3_is_destructor_name;
+ gnu_v3_abi_ops.is_constructor_name = gnuv3_is_constructor_name;
gnu_v3_abi_ops.is_vtable_name = gnuv3_is_vtable_name;
gnu_v3_abi_ops.is_operator_name = gnuv3_is_operator_name;
gnu_v3_abi_ops.rtti_type = gnuv3_rtti_type;