This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 1/2] Partial fix for PR 14160
- From: Tom Tromey <tromey at redhat dot com>
- To: gdb-patches at sourceware dot org
- Date: Tue, 03 Jul 2012 14:56:54 -0600
- Subject: [PATCH 1/2] Partial fix for PR 14160
I'm going to commit this in a couple of days.
This is a partial fix for PR 14160.
The bug here is that there is some fundamental confusion in gdb about
what the physname is, so things like is_constructor_name are
unreliable.
This patch works around the immediate bug by noting constructors when
reading the DWARF and marking the function fields appropriately. I
think this is a better approach than checking physnames anyhow.
Partial fix for PR c++/14160:
* c-typeprint.c (c_type_print_base): Use TYPE_FN_FIELD_CONSTRUCTOR.
* dwarf2read.c (dwarf2_is_constructor): New function.
(dwarf2_add_member_fn): Use it.
* gnu-v3-abi.c (gnuv3_pass_by_reference): Use
TYPE_FN_FIELD_CONSTRUCTOR.
* jv-typeprint.c (java_type_print_base): Use
TYPE_FN_FIELD_CONSTRUCTOR.
* gdbtypes.h (struct fn_field) <is_constructor>: New field.
<dummy>: Shrink.
(TYPE_FN_FIELD_CONSTRUCTOR): New macro.
* gdb.cp/templates.exp (test_ptype_of_templates): Update kfails.
---
gdb/c-typeprint.c | 3 +-
gdb/dwarf2read.c | 30 ++++
gdb/gdbtypes.h | 7 +-
gdb/gnu-v3-abi.c | 3 +-
gdb/jv-typeprint.c | 3 +-
gdb/testsuite/gdb.cp/templates.exp | 16 ++
gdb/valarith.c | 324 ++++++++++++++++++++++++++++++++++++
gdb/value.h | 10 +
8 files changed, 392 insertions(+), 4 deletions(-)
diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c
index a5892b5..099d99c 100644
--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -1001,7 +1001,8 @@ c_type_print_base (struct type *type, struct ui_file *stream,
struct cleanup *inner_cleanup;
const char *physname = TYPE_FN_FIELD_PHYSNAME (f, j);
int is_full_physname_constructor =
- is_constructor_name (physname)
+ TYPE_FN_FIELD_CONSTRUCTOR (f, j)
+ || is_constructor_name (physname)
|| is_destructor_name (physname)
|| method_name[0] == '~';
diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c
index 52288e8..050d09a 100644
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -9067,6 +9067,34 @@ dwarf2_attach_fields_to_type (struct field_info *fip, struct type *type,
}
}
+/* Return true if this member function is a constructor, false
+ otherwise. */
+
+static int
+dwarf2_is_constructor (struct die_info *die, struct dwarf2_cu *cu)
+{
+ const char *fieldname;
+ const char *typename;
+ int len;
+
+ 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;
+
+ fieldname = dwarf2_name (die, cu);
+ typename = dwarf2_name (die->parent, cu);
+ if (fieldname == NULL || typename == NULL)
+ return 0;
+
+ len = strlen (fieldname);
+ return (strncmp (fieldname, typename, len) == 0
+ && (typename[len] == '\0' || typename[len] == '<'));
+}
+
/* Add a member function to the proper fieldlist. */
static void
@@ -9198,6 +9226,8 @@ dwarf2_add_member_fn (struct field_info *fip, struct die_info *die,
if (attr && DW_UNSND (attr) != 0)
fnp->is_artificial = 1;
+ fnp->is_constructor = dwarf2_is_constructor (die, cu);
+
/* Get index in virtual function table if it is a virtual member
function. For older versions of GCC, this is an offset in the
appropriate virtual table, as specified by DW_AT_containing_type.
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index cf7d398..94ae05b 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -826,8 +826,12 @@ struct cplus_struct_type
to reconstruct the rest of the fields). */
unsigned int is_stub:1;
+ /* True if this function is a constructor, false
+ otherwise. */
+ unsigned int is_constructor : 1;
+
/* Unused. */
- unsigned int dummy:4;
+ unsigned int dummy:3;
/* Index into that baseclass's virtual function table,
minus 2; else if static: VOFFSET_STATIC; else: 0. */
@@ -1210,6 +1214,7 @@ extern void allocate_gnat_aux_type (struct type *);
#define TYPE_FN_FIELD_ARTIFICIAL(thisfn, n) ((thisfn)[n].is_artificial)
#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_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)
diff --git a/gdb/gnu-v3-abi.c b/gdb/gnu-v3-abi.c
index 3a83e2d..5eadb3c 100644
--- a/gdb/gnu-v3-abi.c
+++ b/gdb/gnu-v3-abi.c
@@ -1070,7 +1070,8 @@ gnuv3_pass_by_reference (struct type *type)
with the mangled name. We don't have a convenient function
to strip off both leading scope qualifiers and trailing
template arguments yet. */
- if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem)))
+ if (!is_constructor_name (TYPE_FN_FIELD_PHYSNAME (fn, fieldelem))
+ && !TYPE_FN_FIELD_CONSTRUCTOR (fn, fieldelem))
continue;
/* If this method takes two arguments, and the second argument is
diff --git a/gdb/jv-typeprint.c b/gdb/jv-typeprint.c
index cc3bb15..53d5b22 100644
--- a/gdb/jv-typeprint.c
+++ b/gdb/jv-typeprint.c
@@ -237,7 +237,8 @@ java_type_print_base (struct type *type, struct ui_file *stream, int show,
physname[p - real_physname] = '\0';
is_full_physname_constructor
- = (is_constructor_name (physname)
+ = (TYPE_FN_FIELD_CONSTRUCTOR (f, j)
+ || is_constructor_name (physname)
|| is_destructor_name (physname));
QUIT;
diff --git a/gdb/testsuite/gdb.cp/templates.exp b/gdb/testsuite/gdb.cp/templates.exp
index 1eb82eb..9cb4a39 100644
--- a/gdb/testsuite/gdb.cp/templates.exp
+++ b/gdb/testsuite/gdb.cp/templates.exp
@@ -63,6 +63,14 @@ proc test_ptype_of_templates {} {
# This also triggers gdb/1113...
kfail "gdb/1111" "ptype T5<int>"
# Add here a PASS case when PR gdb/1111 gets fixed.
+ # These are really:
+ # http://sourceware.org/bugzilla/show_bug.cgi?id=8216
+ # http://sourceware.org/bugzilla/show_bug.cgi?id=8218
+ }
+ -re "type = class T5<int> \{${ws}public:${ws}static int X;${ws}int x;${ws}int val;${ws}T5\\(int\\);${ws}T5\\((T5<int> const|const T5<int>) ?&\\);${ws}~T5\\(int\\);${ws}static void \\* operator new\\((size_t|unsigned( int| long|))\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\}\r\n$gdb_prompt $" {
+ # http://sourceware.org/bugzilla/show_bug.cgi?id=8218
+ # The destructor has an argument type.
+ kfail "gdb/8218" "ptype T5<int>"
}
}
@@ -92,6 +100,14 @@ proc test_ptype_of_templates {} {
# This also triggers gdb/1113...
kfail "gdb/1111" "ptype T5<int>"
# Add here a PASS case when PR gdb/1111 gets fixed.
+ # These are really:
+ # http://sourceware.org/bugzilla/show_bug.cgi?id=8216
+ # http://sourceware.org/bugzilla/show_bug.cgi?id=8218
+ }
+ -re "type = class T5<int> \{${ws}public:${ws}static int X;${ws}int x;${ws}int val;${ws}T5\\(int\\);${ws}T5\\((T5<int> const|const T5<int>) ?&\\);${ws}~T5\\(int\\);${ws}static void \\* operator new\\((size_t|unsigned( int| long|))\\);${ws}static void operator delete\\(void ?\\*\\);${ws}int value\\((void|)\\);${ws}\}\r\n$gdb_prompt $" {
+ # http://sourceware.org/bugzilla/show_bug.cgi?id=8218
+ # The destructor has an argument type.
+ kfail "gdb/8218" "ptype T5<int>"
}
}
}
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 96d5411..d626cff 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -31,6 +31,7 @@
#include <math.h>
#include "infcall.h"
#include "exceptions.h"
+#include "cp-abi.h"
/* Define whether or not the C operator '/' truncates towards zero for
differently signed operands (truncation direction is undefined in C). */
@@ -643,6 +644,329 @@ value_x_unop (struct value *arg1, enum exp_opcode op, enum noside noside)
return 0; /* For lint -- never reached */
}
+
+/* Call the appropriate 'operator new' to allocate memory.
+
+ GLOBAL_NEW is true if the global ::operator new should be used.
+
+ TYPE is the type being allocated. If it is an array type,
+ 'operator new[]' is used.
+
+ ARGV are the arguments to the operator. The calling convention
+ here is a little funny in that ARGV[0] must be NULL -- it may be
+ filled in during overload searching. ARGV[1] should be the size of
+ the allocation.
+
+ ARGC is the number of arguments in ARGV, including the initial
+ empty slot.
+
+ Returns a newly-allocated object; or throws an exception on error. */
+
+struct value *
+value_operator_new (int global_new, struct type *type,
+ int argc, struct value **argv)
+{
+ enum oload_search_type method = BOTH;
+ struct value *function = NULL;
+ struct symbol *sym = NULL;
+ const char *opname = "operator new";
+ int static_memfunp;
+
+ gdb_assert (argv[0] == NULL);
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ opname = "operator new[]";
+ while (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ }
+ if (!global_new && TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ volatile struct gdb_exception except;
+ struct value *arg;
+
+ argv[0] = value_zero (type, lval_memory);
+ arg = argv[0];
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ find_overload_match (argv, argc, opname, METHOD,
+ 0 /* strict match */, &arg, NULL,
+ &function, &sym, &static_memfunp, 1);
+ }
+ if (except.reason < 0)
+ {
+ sym = NULL;
+ function = NULL;
+ }
+ }
+
+ if (sym == NULL && function == NULL)
+ find_overload_match (argv + 1, argc - 1, opname, NON_METHOD,
+ 0 /* strict match */, NULL, NULL,
+ NULL, &sym, NULL, 1);
+
+ if (sym != NULL)
+ function = value_of_variable (sym, 0);
+
+ if (function == NULL)
+ throw_error (NOT_FOUND_ERROR,
+ _("could not find appropriate '%s'"), opname);
+
+ return call_function_by_hand (function, argc - 1, argv + 1);
+}
+
+/* Call a constructor for a new object.
+
+ TYPE is the type whose constructor is to be called.
+ ARGC and ARGV are the arguments to pass to the constructor. At
+ least one argument is required -- the object itself.
+
+ Ordinarily TYPE must refer to a type that can have a constructor,
+ like a class. However, it can also refer to a scalar type if there
+ are one or two arguments. In the one-argument case, nothing is
+ done. In the two-argument case, the argument is treated as an
+ initializer.
+
+ This performs an inferior function call and throws an exception on
+ any error. */
+
+void
+value_construct (struct type *type, int argc, struct value **argv)
+{
+ struct symbol *sym = NULL;
+ struct value *function = NULL;
+ int i;
+ const char *constr_name;
+
+ gdb_assert (argc >= 1);
+
+ if (TYPE_CODE (type) == TYPE_CODE_PTR
+ || TYPE_CODE (type) == TYPE_CODE_ENUM
+ || TYPE_CODE (type) == TYPE_CODE_INT
+ || TYPE_CODE (type) == TYPE_CODE_FLT
+ || TYPE_CODE (type) == TYPE_CODE_BOOL
+ || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)
+ {
+ struct value *mem, *val;
+
+ if (argc == 1)
+ return;
+
+ if (argc != 2)
+ error (_("too many arguments to construct for '%s'"),
+ TYPE_SAFE_NAME (type));
+
+ mem = value_ind (argv[0]);
+ val = value_cast (value_type (mem), argv[1]);
+ value_assign (mem, val);
+ return;
+ }
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
+ {
+ if (argc == 1)
+ return;
+ error (_("cannot pass arguments to 'new' of '%s'"),
+ TYPE_SAFE_NAME (type));
+ }
+
+ /* Find the constructor name, if we can. */
+ constr_name = NULL;
+ for (i = 0; constr_name == NULL && i < TYPE_NFN_FIELDS (type); ++i)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ int j;
+
+ for (j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+ {
+ if (TYPE_FN_FIELD_CONSTRUCTOR (f, j)
+ || is_constructor_name (TYPE_FN_FIELD_PHYSNAME (f, j)))
+ {
+ constr_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ break;
+ }
+ }
+ }
+
+ if (constr_name != NULL)
+ {
+ struct value *obj = value_ind (argv[0]);
+
+ find_overload_match (argv, argc, constr_name, METHOD, 0,
+ &obj, NULL, &function, &sym, NULL, 1);
+ }
+
+ if (sym != NULL)
+ function = value_of_variable (sym, 0);
+
+ if (function == NULL)
+ {
+ /* No construct is fine for a POD. */
+ if (argc == 1)
+ return;
+
+ throw_error (NOT_FOUND_ERROR,
+ _("no matching constructor found for '%s'"),
+ TYPE_SAFE_NAME (type));
+ }
+
+ call_function_by_hand (function, argc, argv);
+}
+
+/* Call the appropriate 'operator delete' to deallocate memory.
+
+ GLOBAL_DEL is true if the global ::operator delete should be
+ called.
+
+ IS_ARRAY is true if operator delete[] should be called.
+
+ OBJECT is the object to delete.
+
+ Throws an exception on error. */
+
+void
+value_operator_delete (int global_del, int is_array, struct value *object)
+{
+ enum oload_search_type method = BOTH;
+ struct value *function = NULL;
+ struct symbol *sym = NULL;
+ const char *opname = "operator delete";
+ int static_memfunp;
+ struct type *type;
+ struct value *argv[2];
+ struct gdbarch *arch;
+
+ type = check_typedef (value_type (object));
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_PTR);
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+ while (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+
+ if (is_array)
+ opname = "operator delete[]";
+
+ arch = get_type_arch (type);
+ argv[1] = value_cast (lookup_pointer_type (builtin_type (arch)->builtin_void),
+ object);
+
+ if (!global_del && TYPE_CODE (type) == TYPE_CODE_STRUCT)
+ {
+ volatile struct gdb_exception except;
+ struct value *arg;
+
+ argv[0] = value_zero (type, lval_memory);
+ arg = argv[0];
+ TRY_CATCH (except, RETURN_MASK_ERROR)
+ {
+ find_overload_match (argv, 2, opname, METHOD,
+ 0 /* strict match */, &arg, NULL,
+ &function, &sym, &static_memfunp, 1);
+ }
+ if (except.reason < 0)
+ {
+ sym = NULL;
+ function = NULL;
+ }
+ }
+
+ if (sym == NULL && function == NULL)
+ find_overload_match (argv + 1, 1, opname, NON_METHOD,
+ 0 /* strict match */, NULL, NULL,
+ NULL, &sym, NULL, 1);
+
+ if (sym != NULL)
+ function = value_of_variable (sym, 0);
+
+ if (function == NULL)
+ throw_error (NOT_FOUND_ERROR,
+ _("could not find appropriate '%s'"), opname);
+
+ call_function_by_hand (function, 1, argv + 1);
+}
+
+/* Call a destructor for an object.
+
+ OBJECT is the object to destroy.
+
+ IS_ARRAY is true if this object represents an array.
+
+ If IS_ARRAY is true and the base type of OBJECT has a destructor,
+ then this function will return a new value which is the memory that
+ was actually allocated by new[]. This will differ from OBJECT by
+ some padding. In other cases, this function returns NULL.
+
+ This performs an inferior function call and throws an exception on
+ any error. */
+
+struct value *
+value_destruct (struct value *object, int is_array)
+{
+ const char *destr_name;
+ struct type *type;
+ int i;
+ struct symbol *sym;
+ struct value *function;
+
+ type = check_typedef (value_type (object));
+ gdb_assert (TYPE_CODE (type) == TYPE_CODE_PTR);
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+
+ while (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ type = check_typedef (TYPE_TARGET_TYPE (type));
+
+ if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
+ return NULL;
+
+ /* Find the destructor name, if we can. */
+ destr_name = NULL;
+ for (i = 0; destr_name == NULL && i < TYPE_NFN_FIELDS (type); ++i)
+ {
+ struct fn_field *f = TYPE_FN_FIELDLIST1 (type, i);
+ int j;
+
+ for (j = 0; j < TYPE_FN_FIELDLIST_LENGTH (type, i); ++j)
+ {
+ if (TYPE_FN_FIELDLIST_NAME (type, i)[0] == '~'
+ || is_destructor_name (TYPE_FN_FIELD_PHYSNAME (f, j)))
+ {
+ destr_name = TYPE_FN_FIELDLIST_NAME (type, i);
+ break;
+ }
+ }
+ }
+
+ /* No destructor is fine for a POD. */
+ if (destr_name == NULL)
+ return NULL;
+
+ sym = lookup_symbol (destr_name, NULL, VAR_DOMAIN, NULL);
+ if (sym == NULL)
+ return NULL;
+
+ function = value_of_variable (sym, 0);
+
+ if (is_array)
+ {
+ struct value *new_vec;
+ struct value *elt_count_v = cp_get_vec_elts (object, &new_vec);
+ LONGEST iter, elt_count = value_as_long (elt_count_v);
+ struct value *ptr = value_cast (lookup_pointer_type (type), object);
+
+ for (iter = 0; iter < elt_count; ++iter)
+ {
+ struct value *one_elt = ptr;
+
+ call_function_by_hand (function, 1, &one_elt);
+ ptr = value_ptradd (ptr, 1);
+ }
+
+ return new_vec;
+ }
+
+ call_function_by_hand (function, 1, &object);
+ return NULL;
+}
+
/* Concatenate two values with the following conditions:
diff --git a/gdb/value.h b/gdb/value.h
index d8b157f..32f88ed 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -833,6 +833,16 @@ extern struct value *value_x_binop (struct value *arg1, struct value *arg2,
extern struct value *value_x_unop (struct value *arg1, enum exp_opcode op,
enum noside noside);
+extern struct value *value_operator_new (int global_new, struct type *type,
+ int argc, struct value **argv);
+
+extern void value_construct (struct type *type, int argc, struct value **argv);
+
+extern void value_operator_delete (int global_del, int is_array,
+ struct value *object);
+
+extern struct value *value_destruct (struct value *object, int is_array);
+
extern struct value *value_fn_field (struct value **arg1p, struct fn_field *f,
int j, struct type *type, int offset);
--
1.7.7.6