This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]