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]

Re: [patch 2/2] ptype should list also class's typedefs


On Thu, 17 Jun 2010 04:31:57 +0200, Tom Tromey wrote:
> >>>>> "Jan" == Jan Kratochvil <jan.kratochvil@redhat.com> writes:
> It is customary to make new wrapper macros for new fields here.
> I'm not sure that adds much benefit, but maybe just consistency is a
> good enough reason.

Asked about, no response so I have implemented it as you say, not agreed upon.
	gdbtypes.h #defined field accessors
	http://sourceware.org/ml/gdb/2010-06/msg00121.html


> Access permissions are also dropped, that seems maybe a little more useful.

I was not aware they apply.  Filed GCC PR debug/44668 and GDB PR c++/11757.


> Jan> +  gdb_assert (die->tag == DW_TAG_typedef);
> Jan> +
> Jan> +  fp = &new_field->field;
> Jan> +
> Jan> +  /* Get name of field.  */
> Jan> +  fp->name = dwarf2_name (die, cu);
> Jan> +  if (fp->name == NULL)
> Jan> +    return;
> Jan> +
> Jan> +  fp->type = die_type (die, cu);
> 
> This seems a little odd.  Why not just make a new typedef type, and
> store that directly in the outer type?

I just made s/die_type/read_type_die/.  The new typedef symbol is created in
process_structure_scope->process_die->read_type_die+new_symbol.  While we
could move this new_symbol call into this dwarf2_add_typedef I do not see the
point.  Currently the symbol is global (fully qualified) anyway so it fits IMO
more into the general loop of process_structure_scope.


> It seems like that would save a little space,

There is no memory difference as read_type_die is used by both and the same
TYPE_CODE_TYPEDEF type gets shared by get_die_type->htab_find_with_hash.


> but more importantly give "C::t" the correct type -- the typedef and not the
> underlying type.  (We aren't typedef-correct right now, but want to be...)

The global fully qualified type symbol's type is unrelated to this piece of
code.  And it was already TYPE_CODE_TYPEDEF (=typedef-correct) before.

In fact this s/die_type/read_type_die/ change has only brought in a need of
one TYPE_TARGET_TYPE dereference in c_type_print_base (for `ptype'), this
field has currently no other use.  I followed your recommendation as the data
structure now holds more valuable information - one can easily
TYPE_TARGET_TYPE dereference it but one could not do the opposite before.


> Jan> +	/* Unqualified name to be prefixed by owning class qualified name.  */
> Jan> +	const char *name;
> 
> I guess with the above approach you'd have to strip the qualifiers
> before printing the typedef name.  But, it seems like that should be
> simple, since the qualifier is just the enclosing class' name.

I do not see any change with the TYPE_CODE_TYPEDEF dereference.  And I do not
believe GDB should strip anything.

For source:
	typedef long t;
	class C
	  {
	    typedef int t;
	    t g (t i) {}
	  } c;
GDB now displays:
	(gdb) ptype C
	type = class C {
	  private:
	    C::t g(C::t);

	    typedef int t;
	}

As `g' is printed without `C::' I believe even ` t;' should not be ` C::t;'.

GDB currently does not try to shorten some common namespaces and it always
uses fully qualified names.  It could probably shorten at least `std::':
(gdb) ptype cout
type = struct std::basic_ostream<char, std::char_traits<char> > 
    : public virtual std::basic_ios<char, std::char_traits<char> > {
[...]
    std::basic_ostream<char, std::char_traits<char> > & seekp(long, std::_Ios_Seekdir);

Do you suggest to already implement some form of such namespaces shortening?
I have no clue how it fits into some general GDB namespaces shortening plan.

I find it less clear for debugging purposes to display just "t" there due to
the possible confusion of correct `int' with incorrect global `long'.


Thanks,
Jan


gdb/
2010-06-25  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* c-typeprint.c (c_type_print_base): For no fields check include also
	TYPE_TYPEDEF_FIELD_COUNT.  Print new typedefs section.
	* dwarf2read.c (struct typedef_field_list)
	(struct field_info) <typedef_field_list, typedef_field_list_count>: New.
	(dwarf2_add_typedef): New.
	(read_structure_type): Call dwarf2_add_typedef for DW_TAG_typedef.
	Copy also FI.TYPEDEF_FIELD_LIST.
	* gdbtypes.h (struct typedef_field)
	(struct cplus_struct_type) <typedef_field, typedef_field_count>
	(TYPE_TYPEDEF_FIELD_ARRAY, TYPE_TYPEDEF_FIELD, TYPE_TYPEDEF_FIELD_NAME)
	(TYPE_TYPEDEF_FIELD_TYPE, TYPE_TYPEDEF_FIELD_COUNT): New.

gdb/testsuite/
2010-06-25  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.cp/namespace.exp (ptype OtherFileClass typedefs)
	(ptype ::C::OtherFileClass typedefs): New.
	* gdb.cp/namespace1.cc (C::OtherFileClass::cOtherFileClassType2)
	(C::OtherFileClass::cOtherFileClassVar2): New.
	(C::OtherFileClass::cOtherFileClassVar_use): Use also
	cOtherFileClassVar2.
	(C::cOtherFileType2, C::cOtherFileVar2): New.
	(C::cOtherFileVar_use): use also cOtherFileVar2.
	* gdb.cp/userdef.exp (ptype &*c): Permit arbitrary trailing text.

--- a/gdb/c-typeprint.c
+++ b/gdb/c-typeprint.c
@@ -768,7 +768,8 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
 	  cp_type_print_derivation_info (stream, type);
 
 	  fprintf_filtered (stream, "{\n");
-	  if ((TYPE_NFIELDS (type) == 0) && (TYPE_NFN_FIELDS (type) == 0))
+	  if (TYPE_NFIELDS (type) == 0 && TYPE_NFN_FIELDS (type) == 0
+	      && TYPE_TYPEDEF_FIELD_COUNT (type) == 0)
 	    {
 	      if (TYPE_STUB (type))
 		fprintfi_filtered (level + 4, stream, _("<incomplete type>\n"));
@@ -1058,6 +1059,29 @@ c_type_print_base (struct type *type, struct ui_file *stream, int show,
 		}
 	    }
 
+	  /* Print typedefs defined in this class.  */
+
+	  if (TYPE_TYPEDEF_FIELD_COUNT (type) != 0)
+	    {
+	      if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0)
+		fprintf_filtered (stream, "\n");
+
+	      for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
+		{
+		  struct type *target = TYPE_TYPEDEF_FIELD_TYPE (type, i);
+
+		  /* Dereference the typedef declaration itself.  */
+		  gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
+		  target = TYPE_TARGET_TYPE (target);
+
+		  print_spaces_filtered (level + 4, stream);
+		  fprintf_filtered (stream, "typedef ");
+		  c_print_type (target, TYPE_TYPEDEF_FIELD_NAME (type, i),
+				stream, show - 1, level + 4);
+		  fprintf_filtered (stream, ";\n");
+		}
+	    }
+
 	  fprintfi_filtered (level, stream, "}");
 
 	  if (TYPE_LOCALTYPE_PTR (type) && show >= 0)
--- a/gdb/dwarf2read.c
+++ b/gdb/dwarf2read.c
@@ -645,6 +645,16 @@ struct field_info
 
     /* Number of entries in the fnfieldlists array.  */
     int nfnfields;
+
+    /* typedefs defined inside this class.  TYPEDEF_FIELD_LIST contains head of
+       a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements.  */
+    struct typedef_field_list
+      {
+	struct typedef_field field;
+	struct typedef_field_list *next;
+      }
+    *typedef_field_list;
+    unsigned typedef_field_list_count;
   };
 
 /* One item on the queue of compilation units to read in full symbols
@@ -4668,6 +4678,39 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
     }
 }
 
+/* Add a typedef defined in the scope of the FIP's class.  */
+
+static void
+dwarf2_add_typedef (struct field_info *fip, struct die_info *die,
+		    struct dwarf2_cu *cu)
+{ 
+  struct objfile *objfile = cu->objfile;
+  struct gdbarch *gdbarch = get_objfile_arch (objfile);
+  struct typedef_field_list *new_field;
+  struct attribute *attr;
+  struct typedef_field *fp;
+  char *fieldname = "";
+
+  /* Allocate a new field list entry and link it in.  */
+  new_field = xzalloc (sizeof (*new_field));
+  make_cleanup (xfree, new_field);
+
+  gdb_assert (die->tag == DW_TAG_typedef);
+
+  fp = &new_field->field;
+
+  /* Get name of field.  */
+  fp->name = dwarf2_name (die, cu);
+  if (fp->name == NULL)
+    return;
+
+  fp->type = read_type_die (die, cu);
+
+  new_field->next = fip->typedef_field_list;
+  fip->typedef_field_list = new_field;
+  fip->typedef_field_list_count++;
+}
+
 /* Create the vector of fields, and attach it to the type.  */
 
 static void
@@ -5199,6 +5242,8 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
 	      /* C++ base class field.  */
 	      dwarf2_add_field (&fi, child_die, cu);
 	    }
+	  else if (child_die->tag == DW_TAG_typedef)
+	    dwarf2_add_typedef (&fi, child_die, cu);
 	  child_die = sibling_die (child_die);
 	}
 
@@ -5272,6 +5317,28 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
 		}
 	    }
 	}
+
+      /* Copy fi.typedef_field_list linked list elements content into the
+	 allocated array TYPE_TYPEDEF_FIELD_ARRAY (type).  */
+      if (fi.typedef_field_list)
+	{
+	  int i = fi.typedef_field_list_count;
+
+	  TYPE_TYPEDEF_FIELD_ARRAY (type)
+	    = TYPE_ALLOC (type, sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * i);
+	  TYPE_TYPEDEF_FIELD_COUNT (type) = i;
+
+	  /* Reverse the list order to keep the debug info elements order.  */
+	  while (--i >= 0)
+	    {
+	      struct typedef_field *dest, *src;
+	      
+	      dest = &TYPE_TYPEDEF_FIELD (type, i);
+	      src = &fi.typedef_field_list->field;
+	      fi.typedef_field_list = fi.typedef_field_list->next;
+	      *dest = *src;
+	    }
+	}
     }
 
   quirk_gcc_member_function_pointer (type, cu->objfile);
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -820,6 +820,19 @@ struct cplus_struct_type
 	int line;
       }
      *localtype_ptr;
+
+    /* typedefs defined inside this class.  TYPEDEF_FIELD points to an array of
+       TYPEDEF_FIELD_COUNT elements.  */
+    struct typedef_field
+      {
+	/* Unqualified name to be prefixed by owning class qualified name.  */
+	const char *name;
+
+	/* Type this typedef named NAME represents.  */
+	struct type *type;
+      }
+    *typedef_field;
+    unsigned typedef_field_count;
   };
 
 /* Struct used in computing virtual base list */
@@ -1047,6 +1060,17 @@ extern void allocate_gnat_aux_type (struct type *);
 #define TYPE_LOCALTYPE_FILE(thistype) (TYPE_CPLUS_SPECIFIC(thistype)->localtype_ptr->file)
 #define TYPE_LOCALTYPE_LINE(thistype) (TYPE_CPLUS_SPECIFIC(thistype)->localtype_ptr->line)
 
+#define TYPE_TYPEDEF_FIELD_ARRAY(thistype) \
+  TYPE_CPLUS_SPECIFIC (thistype)->typedef_field
+#define TYPE_TYPEDEF_FIELD(thistype, n) \
+  TYPE_CPLUS_SPECIFIC (thistype)->typedef_field[n]
+#define TYPE_TYPEDEF_FIELD_NAME(thistype, n) \
+  TYPE_TYPEDEF_FIELD (thistype, n).name
+#define TYPE_TYPEDEF_FIELD_TYPE(thistype, n) \
+  TYPE_TYPEDEF_FIELD (thistype, n).type
+#define TYPE_TYPEDEF_FIELD_COUNT(thistype) \
+  TYPE_CPLUS_SPECIFIC (thistype)->typedef_field_count
+
 #define TYPE_IS_OPAQUE(thistype) (((TYPE_CODE (thistype) == TYPE_CODE_STRUCT) ||        \
                                    (TYPE_CODE (thistype) == TYPE_CODE_UNION))        && \
                                   (TYPE_NFIELDS (thistype) == 0)                     && \
--- a/gdb/testsuite/gdb.cp/namespace.exp
+++ b/gdb/testsuite/gdb.cp/namespace.exp
@@ -265,6 +265,21 @@ gdb_test "ptype OtherFileClass" "type = (class C::OtherFileClass \{\r\n  public:
 gdb_test "ptype ::C::OtherFileClass" "type = class C::OtherFileClass \{\r\n  public:\r\n    int z;\r\n.*\}"
 gdb_test "ptype C::OtherFileClass" "No symbol \"OtherFileClass\" in namespace \"C::C\"."
 
+# Test class typedefs printing.
+set expect "type = class C::OtherFileClass \{\r\n.*\r\n *typedef short cOtherFileClassType;\r\n *typedef long cOtherFileClassType2;\r\n\}"
+if {[test_compiler_info {gcc-[0-3]-*}]
+    || [test_compiler_info {gcc-4-[0-4]-*}]} {
+    # The type in class is missing in older GCCs.
+    setup_xfail *-*-* 
+}
+gdb_test "ptype OtherFileClass" $expect "ptype OtherFileClass typedefs"
+if {[test_compiler_info {gcc-[0-3]-*}]
+    || [test_compiler_info {gcc-4-[0-4]-*}]} {
+    # The type in class is missing in older GCCs.
+    setup_xfail *-*-* 
+}
+gdb_test "ptype ::C::OtherFileClass" $expect "ptype ::C::OtherFileClass typedefs"
+
 # Some anonymous namespace tests.
 
 gdb_test "print cX" "\\$\[0-9\].* = 6"
--- a/gdb/testsuite/gdb.cp/namespace1.cc
+++ b/gdb/testsuite/gdb.cp/namespace1.cc
@@ -23,12 +23,14 @@ namespace C
     int z;
 
     typedef short cOtherFileClassType;
+    typedef long cOtherFileClassType2;
     static const cOtherFileClassType cOtherFileClassVar = 318;
+    static const cOtherFileClassType2 cOtherFileClassVar2 = 320;
     cOtherFileClassType cOtherFileClassVar_use ();
   };
   OtherFileClass::cOtherFileClassType OtherFileClass::cOtherFileClassVar_use ()
   {
-    return cOtherFileClassVar;
+    return cOtherFileClassVar + cOtherFileClassVar2;
   }
 
   namespace {
@@ -45,10 +47,12 @@ namespace C
   }
 
   typedef short cOtherFileType;
+  typedef long cOtherFileType2;
   static const cOtherFileType cOtherFileVar = 319;
+  static const cOtherFileType2 cOtherFileVar2 = 321;
   cOtherFileType cOtherFileVar_use ()
   {
-    return cOtherFileVar;
+    return cOtherFileVar + cOtherFileVar2;
   }
 }
 
--- a/gdb/testsuite/gdb.cp/userdef.exp
+++ b/gdb/testsuite/gdb.cp/userdef.exp
@@ -148,7 +148,7 @@ gdb_test "break A2::'operator +'" ".*Breakpoint $decimal at.*"
 gdb_test "print c" "\\\$\[0-9\]* = {m = {z = .*}}"
 gdb_test "print *c" "\\\$\[0-9\]* = \\(Member &\\) @$hex: {z = .*}"
 gdb_test "print &*c" "\\\$\[0-9\]* = \\(Member \\*\\) $hex"
-gdb_test "ptype &*c" "type = (struct|class) Member {(\[\r\n \]+public:)?\[\r\n \]+int z;\[\r\n\]+} &\\*"
+gdb_test "ptype &*c" "type = (struct|class) Member {(\[\r\n \]+public:)?\[\r\n \]+int z;\[\r\n\].*} &\\*"
 
 gdb_test "print operator== (mem1, mem2)" " = false"
 gdb_test "print operator== (mem1, mem1)" " = true"


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