Record and output access specifiers for nested typedefs
authorKeith Seitz <keiths@redhat.com>
Tue, 17 Oct 2017 00:19:29 +0000 (17:19 -0700)
committerKeith Seitz <keiths@redhat.com>
Tue, 17 Oct 2017 00:19:29 +0000 (17:19 -0700)
We currently do not record access information for typedefs defined inside
classes.  Consider:

struct foo
{
   typedef int PUBLIC;
 private:
   typedef int PRIVATE;
   PRIVATE b;
};

(gdb) ptype foo
type = struct foo {
  private:
    PRIVATE b;

    typedef int PRIVATE;
    typedef int PUBLIC;
}

This patch fixes this:

(gdb) ptype foo
type = struct foo {
  private:
    PRIVATE b;

    typedef int PRIVATE;
  public:
    typedef int PUBLIC;
}

gdb/ChangeLog:

* c-typeprint.c (enum access_specifier): Moved here from
c_type_print_base.
(output_access_specifier): New function.
(c_type_print_base): Consider typedefs when assessing
whether access labels are needed.
Use output_access_specifier as needed.
Output access specifier for typedefs, if needed.
* dwarf2read.c (dwarf2_add_typedef): Record DW_AT_accessibility.
* gdbtypes.h (struct typedef_field) <is_protected, is_private>: New
fields.
(TYPE_TYPEDEF_FIELD_PROTECTED, TYPE_TYPEDEF_FIELD_PRIVATE): New
accessor macros.

gdb/testsuite/ChangeLog:

* gdb.cp/classes.cc (class_with_typedefs, class_with_public_typedef)
(class_with_protected_typedef, class_with_private_typedef)
(struct_with_public_typedef, struct_with_protected_typedef)
(struct_with_private_typedef): New classes/structs.
* gdb.cp/classes.exp (test_ptype_class_objects): Add tests for
typedefs and access specifiers.

gdb/c-typeprint.c
gdb/dwarf2read.c
gdb/gdbtypes.h
gdb/testsuite/gdb.cp/classes.cc
gdb/testsuite/gdb.cp/classes.exp

index f752300403ee66090315128d8df1b0a05b039049..22fdaa5beb7badbbeb6b2f5aa60005ab0ab89b24 100644 (file)
 #include "cp-abi.h"
 #include "cp-support.h"
 
+/* A list of access specifiers used for printing.  */
+
+enum access_specifier
+{
+  s_none,
+  s_public,
+  s_private,
+  s_protected
+};
+
 static void c_type_print_varspec_prefix (struct type *,
                                         struct ui_file *,
                                         int, int, int,
@@ -826,6 +836,45 @@ c_type_print_template_args (const struct type_print_options *flags,
     fputs_filtered (_("] "), stream);
 }
 
+/* Output an access specifier to STREAM, if needed.  LAST_ACCESS is the
+   last access specifier output (typically returned by this function).  */
+
+static enum access_specifier
+output_access_specifier (struct ui_file *stream,
+                        enum access_specifier last_access,
+                        int level, bool is_protected, bool is_private)
+{
+  if (is_protected)
+    {
+      if (last_access != s_protected)
+       {
+         last_access = s_protected;
+         fprintfi_filtered (level + 2, stream,
+                            "protected:\n");
+       }
+    }
+  else if (is_private)
+    {
+      if (last_access != s_private)
+       {
+         last_access = s_private;
+         fprintfi_filtered (level + 2, stream,
+                            "private:\n");
+       }
+    }
+  else
+    {
+      if (last_access != s_public)
+       {
+         last_access = s_public;
+         fprintfi_filtered (level + 2, stream,
+                            "public:\n");
+       }
+    }
+
+  return last_access;
+}
+
 /* Print the name of the type (or the ultimate pointer target,
    function value or array element), or the description of a structure
    or union.
@@ -850,11 +899,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 {
   int i;
   int len, real_len;
-  enum
-    {
-      s_none, s_public, s_private, s_protected
-    }
-  section_type;
+  enum access_specifier section_type;
   int need_access_label = 0;
   int j, len2;
 
@@ -1034,6 +1079,18 @@ c_type_print_base (struct type *type, struct ui_file *stream,
                          break;
                      }
                  }
+               QUIT;
+               if (!need_access_label)
+                 {
+                   for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); ++i)
+                     {
+                       if (!TYPE_TYPEDEF_FIELD_PRIVATE (type, i))
+                         {
+                           need_access_label = 1;
+                           break;
+                         }
+                     }
+                 }
              }
            else
              {
@@ -1068,6 +1125,19 @@ c_type_print_base (struct type *type, struct ui_file *stream,
                          break;
                      }
                  }
+               QUIT;
+               if (!need_access_label)
+                 {
+                   for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); ++i)
+                     {
+                       if (TYPE_TYPEDEF_FIELD_PROTECTED (type, i)
+                           || TYPE_TYPEDEF_FIELD_PRIVATE (type, i))
+                         {
+                           need_access_label = 1;
+                           break;
+                         }
+                     }
+                 }
              }
 
            /* If there is a base class for this type,
@@ -1088,33 +1158,10 @@ c_type_print_base (struct type *type, struct ui_file *stream,
 
                if (need_access_label)
                  {
-                   if (TYPE_FIELD_PROTECTED (type, i))
-                     {
-                       if (section_type != s_protected)
-                         {
-                           section_type = s_protected;
-                           fprintfi_filtered (level + 2, stream,
-                                              "protected:\n");
-                         }
-                     }
-                   else if (TYPE_FIELD_PRIVATE (type, i))
-                     {
-                       if (section_type != s_private)
-                         {
-                           section_type = s_private;
-                           fprintfi_filtered (level + 2, stream,
-                                              "private:\n");
-                         }
-                     }
-                   else
-                     {
-                       if (section_type != s_public)
-                         {
-                           section_type = s_public;
-                           fprintfi_filtered (level + 2, stream,
-                                              "public:\n");
-                         }
-                     }
+                   section_type = output_access_specifier
+                     (stream, section_type, level,
+                      TYPE_FIELD_PROTECTED (type, i),
+                      TYPE_FIELD_PRIVATE (type, i));
                  }
 
                print_spaces_filtered (level + 4, stream);
@@ -1187,33 +1234,10 @@ c_type_print_base (struct type *type, struct ui_file *stream,
                  inner_cleanup = make_cleanup (null_cleanup, NULL);
 
                  QUIT;
-                 if (TYPE_FN_FIELD_PROTECTED (f, j))
-                   {
-                     if (section_type != s_protected)
-                       {
-                         section_type = s_protected;
-                         fprintfi_filtered (level + 2, stream,
-                                            "protected:\n");
-                       }
-                   }
-                 else if (TYPE_FN_FIELD_PRIVATE (f, j))
-                   {
-                     if (section_type != s_private)
-                       {
-                         section_type = s_private;
-                         fprintfi_filtered (level + 2, stream,
-                                            "private:\n");
-                       }
-                   }
-                 else
-                   {
-                     if (section_type != s_public)
-                       {
-                         section_type = s_public;
-                         fprintfi_filtered (level + 2, stream,
-                                            "public:\n");
-                       }
-                   }
+                 section_type = output_access_specifier
+                   (stream, section_type, level,
+                    TYPE_FN_FIELD_PROTECTED (f, j),
+                    TYPE_FN_FIELD_PRIVATE (f, j));
 
                  print_spaces_filtered (level + 4, stream);
                  if (TYPE_FN_FIELD_VIRTUAL_P (f, j))
@@ -1325,6 +1349,13 @@ c_type_print_base (struct type *type, struct ui_file *stream,
                  gdb_assert (TYPE_CODE (target) == TYPE_CODE_TYPEDEF);
                  target = TYPE_TARGET_TYPE (target);
 
+                 if (need_access_label)
+                   {
+                     section_type = output_access_specifier
+                       (stream, section_type, level,
+                        TYPE_TYPEDEF_FIELD_PROTECTED (type, i),
+                        TYPE_TYPEDEF_FIELD_PRIVATE (type, i));
+                   }
                  print_spaces_filtered (level + 4, stream);
                  fprintf_filtered (stream, "typedef ");
 
index af4bb648a0cc7a66fec31bf06e189886e7a99962..f27d9b96afe5f5760e51b5267523fe6af9ef2d35 100644 (file)
@@ -13112,6 +13112,28 @@ dwarf2_add_typedef (struct field_info *fip, struct die_info *die,
 
   fp->type = read_type_die (die, cu);
 
+  /* Save accessibility.  */
+  enum dwarf_access_attribute accessibility;
+  struct attribute *attr = dwarf2_attr (die, DW_AT_accessibility, cu);
+  if (attr != NULL)
+    accessibility = (enum dwarf_access_attribute) DW_UNSND (attr);
+  else
+    accessibility = dwarf2_default_access_attribute (die, cu);
+  switch (accessibility)
+    {
+    case DW_ACCESS_public:
+      /* The assumed value if neither private nor protected.  */
+      break;
+    case DW_ACCESS_private:
+      fp->is_private = 1;
+      break;
+    case DW_ACCESS_protected:
+      fp->is_protected = 1;
+      break;
+    default:
+      gdb_assert_not_reached ("unexpected accessibility attribute");
+    }
+
   new_field->next = fip->typedef_field_list;
   fip->typedef_field_list = new_field;
   fip->typedef_field_list_count++;
index 009cea90d93921034ae6984763c372175de6e19a..5c1aecd211b16d21ae2f7618b4953e9e6aa96a38 100644 (file)
@@ -873,6 +873,12 @@ struct typedef_field
   /* * Type this typedef named NAME represents.  */
 
   struct type *type;
+
+  /* * True if this field was declared protected, false otherwise.  */
+  unsigned int is_protected : 1;
+
+  /* * True if this field was declared private, false otherwise.  */
+  unsigned int is_private : 1;
 };
 
 /* * C++ language-specific information for TYPE_CODE_STRUCT and
@@ -1402,6 +1408,7 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
 #define TYPE_FN_FIELD_VIRTUAL_P(thisfn, n) ((thisfn)[n].voffset > 1)
 #define TYPE_FN_FIELD_STATIC_P(thisfn, n) ((thisfn)[n].voffset == VOFFSET_STATIC)
 
+/* Accessors for typedefs defined by a class.  */
 #define TYPE_TYPEDEF_FIELD_ARRAY(thistype) \
   TYPE_CPLUS_SPECIFIC (thistype)->typedef_field
 #define TYPE_TYPEDEF_FIELD(thistype, n) \
@@ -1412,6 +1419,10 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
   TYPE_TYPEDEF_FIELD (thistype, n).type
 #define TYPE_TYPEDEF_FIELD_COUNT(thistype) \
   TYPE_CPLUS_SPECIFIC (thistype)->typedef_field_count
+#define TYPE_TYPEDEF_FIELD_PROTECTED(thistype, n) \
+  TYPE_TYPEDEF_FIELD (thistype, n).is_protected
+#define TYPE_TYPEDEF_FIELD_PRIVATE(thistype, n)        \
+  TYPE_TYPEDEF_FIELD (thistype, n).is_private
 
 #define TYPE_IS_OPAQUE(thistype) \
   (((TYPE_CODE (thistype) == TYPE_CODE_STRUCT) \
index 2a81473500def506fd2c3960e104c1033069b9e0..50f0740abe71510cdae1a8f5fbe630e1320d710e 100644 (file)
@@ -545,6 +545,82 @@ small::method ()
   return x + 5;
 }
 
+class class_with_typedefs
+{
+public:
+  typedef int public_int;
+protected:
+  typedef int protected_int;
+private:
+  typedef int private_int;
+
+public:
+  class_with_typedefs ()
+    : public_int_ (1), protected_int_ (2), private_int_ (3) {}
+  public_int add_public (public_int a) { return a + public_int_; }
+  public_int add_all (int a)
+  { return add_public (a) + add_protected (a) + add_private (a); }
+
+protected:
+  protected_int add_protected (protected_int a) { return a + protected_int_; }
+
+private:
+  private_int add_private (private_int a) { return a + private_int_; }
+
+protected:
+  public_int public_int_;
+  protected_int protected_int_;
+  private_int private_int_;
+};
+
+class class_with_public_typedef
+{
+  int a;
+public:
+  typedef int INT;
+  INT b;
+};
+
+class class_with_protected_typedef
+{
+  int a;
+protected:
+  typedef int INT;
+  INT b;
+};
+
+class class_with_private_typedef
+{
+  int a;
+private:
+  typedef int INT;
+  INT b;
+};
+
+struct struct_with_public_typedef
+{
+  int a;
+public:
+  typedef int INT;
+  INT b;
+};
+
+struct struct_with_protected_typedef
+{
+  int a;
+protected:
+  typedef int INT;
+  INT b;
+};
+
+struct struct_with_private_typedef
+{
+  int a;
+private:
+  typedef int INT;
+  INT b;
+};
+
 void marker_reg1 () {}
 
 int
@@ -624,3 +700,10 @@ protected_class protected_c;
 default_private_class default_private_c;
 explicit_private_class explicit_private_c;
 mixed_protection_class mixed_protection_c;
+class_with_typedefs class_with_typedefs_c;
+class_with_public_typedef class_with_public_typedef_c;
+class_with_protected_typedef class_with_protected_typedef_c;
+class_with_private_typedef class_with_private_typedef_c;
+struct_with_public_typedef struct_with_public_typedef_s;
+struct_with_protected_typedef struct_with_protected_typedef_s;
+struct_with_private_typedef struct_with_private_typedef_s;
index 256fa6885a096e732e1148036ab82f464743a71d..9e2630acef48715eadcac28d7a82cd24a436654e 100644 (file)
@@ -316,6 +316,64 @@ proc test_ptype_class_objects {} {
            { field  public "int y;" }
            { method public "DynamicBar(int, int);" }
        }
+
+    # Classes with typedefs of different access.
+
+    cp_test_ptype_class \
+       "class class_with_typedefs" "" "class" "class_with_typedefs" \
+       {
+           { field protected \
+                 "class_with_typedefs::public_int public_int_;" }
+           { field protected \
+                 "class_with_typedefs::protected_int protected_int_;" }
+           { field protected \
+                 "class_with_typedefs::private_int private_int_;" }
+           { method public "class_with_typedefs(void);" }
+           { method public "class_with_typedefs::public_int add_public(class_with_typedefs::public_int);" }
+           { method public \
+                 "class_with_typedefs::public_int add_all(int);" }
+           { method protected "class_with_typedefs::protected_int add_protected(class_with_typedefs::protected_int);" }
+           { method private "class_with_typedefs::private_int add_private(class_with_typedefs::private_int);" }
+           { typedef public "typedef int public_int;" }
+           { typedef protected "typedef int protected_int;" }
+           { typedef private "typedef int private_int;" }
+       }
+
+    cp_test_ptype_class \
+       "class class_with_public_typedef" "" "class" \
+       "class_with_public_typedef" {
+           { field private "int a;" }
+           { field public "class_with_public_typedef::INT b;" }
+           { typedef public "typedef int INT;" }
+       }
+    cp_test_ptype_class \
+       "class class_with_protected_typedef" "" "class" \
+       "class_with_protected_typedef" {
+           { field private "int a;" }
+           { field protected "class_with_protected_typedef::INT b;" }
+           { typedef protected "typedef int INT;" }
+       }
+    cp_test_ptype_class \
+       "struct struct_with_protected_typedef" "" "struct" \
+       "struct_with_protected_typedef" {
+           { field public "int a;" }
+           { field protected "struct_with_protected_typedef::INT b;" }
+           { typedef protected "typedef int INT;" }
+       }
+    cp_test_ptype_class \
+       "struct struct_with_private_typedef" "" "struct" \
+       "struct_with_private_typedef" {
+           { field public "int a;" }
+           { field private "struct_with_private_typedef::INT b;" }
+           { typedef private "typedef int INT;" }
+       }
+
+    # For the following two cases, we cannot use cp_test_ptype_class.
+    # We need to explicitly check whether the access label was suppressed.
+    set ws {[ \t\r\n]*}
+    foreach {tag lbl} {"class" "private" "struct" "public"} {
+       gdb_test "ptype/r ${tag}_with_${lbl}_typedef" "type = $tag ${tag}_with_${lbl}_typedef \{${ws}int a;${ws}${tag}_with_${lbl}_typedef::INT b;${ws}typedef int INT;${ws}\}"
+    }
 }
 
 # Test simple access to class members.