Record and output access specifiers for nested typedefs
[deliverable/binutils-gdb.git] / gdb / c-typeprint.c
index 421b72014865e17521b142f907aeb12a88546a79..22fdaa5beb7badbbeb6b2f5aa60005ab0ab89b24 100644 (file)
@@ -1,5 +1,5 @@
 /* Support for printing C and C++ types for GDB, the GNU debugger.
-   Copyright (C) 1986-2015 Free Software Foundation, Inc.
+   Copyright (C) 1986-2017 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "c-lang.h"
 #include "typeprint.h"
 #include "cp-abi.h"
-#include "jv-lang.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,
@@ -50,7 +59,7 @@ static void c_type_print_modifier (struct type *,
 static const char *
 find_typedef_for_canonicalize (struct type *t, void *data)
 {
-  return find_typedef_in_hash (data, t);
+  return find_typedef_in_hash ((const struct type_print_options *) data, t);
 }
 
 /* Print NAME on STREAM.  If the 'raw' field of FLAGS is not set,
@@ -61,15 +70,14 @@ print_name_maybe_canonical (const char *name,
                            const struct type_print_options *flags,
                            struct ui_file *stream)
 {
-  char *s = NULL;
+  std::string s;
 
   if (!flags->raw)
     s = cp_canonicalize_string_full (name,
                                     find_typedef_for_canonicalize,
                                     (void *) flags);
 
-  fputs_filtered (s ? s : name, stream);
-  xfree (s);
+  fputs_filtered (!s.empty () ? s.c_str () : name, stream);
 }
 
 \f
@@ -89,7 +97,7 @@ c_print_type (struct type *type,
   const char *local_name;
 
   if (show > 0)
-    CHECK_TYPEDEF (type);
+    type = check_typedef (type);
 
   local_name = find_typedef_in_hash (flags, type);
   if (local_name != NULL)
@@ -112,7 +120,7 @@ c_print_type (struct type *type,
                      && !TYPE_VECTOR (type))
                  || code == TYPE_CODE_MEMBERPTR
                  || code == TYPE_CODE_METHODPTR
-                 || code == TYPE_CODE_REF)))
+                 || TYPE_IS_REFERENCE (type))))
        fputs_filtered (" ", stream);
       need_post_space = (varstring != NULL && strcmp (varstring, "") != 0);
       c_type_print_varspec_prefix (type, stream, show, 0, need_post_space,
@@ -144,7 +152,7 @@ c_print_typedef (struct type *type,
                 struct symbol *new_symbol,
                 struct ui_file *stream)
 {
-  CHECK_TYPEDEF (type);
+  type = check_typedef (type);
   fprintf_filtered (stream, "typedef ");
   type_print (type, "", stream, 0);
   if (TYPE_NAME ((SYMBOL_TYPE (new_symbol))) == 0
@@ -228,13 +236,21 @@ cp_type_print_method_args (struct type *mtype, const char *prefix,
                           language_cplus, DMGL_ANSI);
   fputs_filtered ("(", stream);
 
-  /* Skip the class variable.  */
+  /* Skip the class variable.  We keep this here to accommodate older
+     compilers and debug formats which may not support artificial
+     parameters.  */
   i = staticp ? 0 : 1;
   if (nargs > i)
     {
       while (i < nargs)
        {
-         c_print_type (args[i++].type, "", stream, 0, 0, flags);
+         struct field arg = args[i++];
+
+         /* Skip any artificial arguments.  */
+         if (FIELD_ARTIFICIAL (arg))
+           continue;
+
+         c_print_type (arg.type, "", stream, 0, 0, flags);
 
          if (i == nargs && varargs)
            fprintf_filtered (stream, ", ...");
@@ -341,9 +357,10 @@ c_type_print_varspec_prefix (struct type *type,
       break;
 
     case TYPE_CODE_REF:
+    case TYPE_CODE_RVALUE_REF:
       c_type_print_varspec_prefix (TYPE_TARGET_TYPE (type),
                                   stream, show, 1, 0, flags);
-      fprintf_filtered (stream, "&");
+      fprintf_filtered (stream, TYPE_CODE(type) == TYPE_CODE_REF ? "&" : "&&");
       c_type_print_modifier (type, stream, 1, need_post_space);
       break;
 
@@ -371,6 +388,7 @@ c_type_print_varspec_prefix (struct type *type,
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
     case TYPE_CODE_ENUM:
+    case TYPE_CODE_FLAGS:
     case TYPE_CODE_INT:
     case TYPE_CODE_FLT:
     case TYPE_CODE_VOID:
@@ -409,8 +427,7 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
   /* We don't print `const' qualifiers for references --- since all
      operators affect the thing referenced, not the reference itself,
      every reference is `const'.  */
-  if (TYPE_CONST (type)
-      && TYPE_CODE (type) != TYPE_CODE_REF)
+  if (TYPE_CONST (type) && !TYPE_IS_REFERENCE (type))
     {
       if (need_pre_space)
        fprintf_filtered (stream, " ");
@@ -464,7 +481,7 @@ c_type_print_modifier (struct type *type, struct ui_file *stream,
    parameter types get removed their possible const and volatile qualifiers to
    match demangled linkage name parameters part of such function type.
    LANGUAGE is the language in which TYPE was defined.  This is a necessary
-   evil since this code is used by the C, C++, and Java backends.  */
+   evil since this code is used by the C and C++.  */
 
 void
 c_type_print_args (struct type *type, struct ui_file *stream,
@@ -503,10 +520,7 @@ c_type_print_args (struct type *type, struct ui_file *stream,
          param_type = make_cv_type (0, 0, param_type, NULL);
        }
 
-      if (language == language_java)
-       java_print_type (param_type, "", stream, -1, 0, flags);
-      else
-       c_print_type (param_type, "", stream, -1, 0, flags);
+      c_print_type (param_type, "", stream, -1, 0, flags);
       printed_any = 1;
     }
 
@@ -523,8 +537,7 @@ c_type_print_args (struct type *type, struct ui_file *stream,
        }
     }
   else if (!printed_any
-          && ((TYPE_PROTOTYPED (type) && language != language_java)
-              || language == language_cplus))
+          && (TYPE_PROTOTYPED (type) || language == language_cplus))
     fprintf_filtered (stream, "void");
 
   fprintf_filtered (stream, ")");
@@ -544,7 +557,7 @@ is_type_conversion_operator (struct type *type, int i, int j)
      some other way, feel free to rewrite this function.  */
   const char *name = TYPE_FN_FIELDLIST_NAME (type, i);
 
-  if (!startswith (name, "operator"))
+  if (!startswith (name, CP_OPERATOR_STR))
     return 0;
 
   name += 8;
@@ -725,6 +738,7 @@ c_type_print_varspec_suffix (struct type *type,
 
     case TYPE_CODE_PTR:
     case TYPE_CODE_REF:
+    case TYPE_CODE_RVALUE_REF:
       c_type_print_varspec_suffix (TYPE_TARGET_TYPE (type), stream,
                                   show, 1, 0, flags);
       break;
@@ -748,6 +762,7 @@ c_type_print_varspec_suffix (struct type *type,
     case TYPE_CODE_UNDEF:
     case TYPE_CODE_STRUCT:
     case TYPE_CODE_UNION:
+    case TYPE_CODE_FLAGS:
     case TYPE_CODE_ENUM:
     case TYPE_CODE_INT:
     case TYPE_CODE_FLT:
@@ -821,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.
@@ -845,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;
 
@@ -876,7 +926,7 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       return;
     }
 
-  CHECK_TYPEDEF (type);
+  type = check_typedef (type);
 
   switch (TYPE_CODE (type))
     {
@@ -888,12 +938,19 @@ c_type_print_base (struct type *type, struct ui_file *stream,
       fprintf_filtered (stream, _("<unnamed typedef>"));
       break;
 
+    case TYPE_CODE_FUNC:
+    case TYPE_CODE_METHOD:
+      if (TYPE_TARGET_TYPE (type) == NULL)
+       type_print_unknown_return_type (stream);
+      else
+       c_type_print_base (TYPE_TARGET_TYPE (type),
+                          stream, show, level, flags);
+      break;
     case TYPE_CODE_ARRAY:
     case TYPE_CODE_PTR:
     case TYPE_CODE_MEMBERPTR:
     case TYPE_CODE_REF:
-    case TYPE_CODE_FUNC:
-    case TYPE_CODE_METHOD:
+    case TYPE_CODE_RVALUE_REF:
     case TYPE_CODE_METHODPTR:
       c_type_print_base (TYPE_TARGET_TYPE (type),
                         stream, show, level, flags);
@@ -1022,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
              {
@@ -1056,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,
@@ -1076,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);
@@ -1175,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))
@@ -1305,27 +1341,34 @@ c_type_print_base (struct type *type, struct ui_file *stream,
              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 ");
-
-                   /* We want to print typedefs with substitutions
-                      from the template parameters or globally-known
-                      typedefs but not local typedefs.  */
-                   c_print_type (target,
-                                 TYPE_TYPEDEF_FIELD_NAME (type, i),
-                                 stream, show - 1, level + 4,
-                                 &semi_local_flags);
-                   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);
+
+                 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 ");
+
+                 /* We want to print typedefs with substitutions
+                    from the template parameters or globally-known
+                    typedefs but not local typedefs.  */
+                 c_print_type (target,
+                               TYPE_TYPEDEF_FIELD_NAME (type, i),
+                               stream, show - 1, level + 4,
+                               &semi_local_flags);
+                 fprintf_filtered (stream, ";\n");
+               }
+           }
 
            fprintfi_filtered (level, stream, "}");
          }
@@ -1402,6 +1445,55 @@ c_type_print_base (struct type *type, struct ui_file *stream,
        }
       break;
 
+    case TYPE_CODE_FLAGS:
+      {
+       struct type_print_options local_flags = *flags;
+
+       local_flags.local_typedefs = NULL;
+
+       c_type_print_modifier (type, stream, 0, 1);
+       fprintf_filtered (stream, "flag ");
+       print_name_maybe_canonical (TYPE_NAME (type), flags, stream);
+       if (show > 0)
+         {
+           fputs_filtered (" ", stream);
+           fprintf_filtered (stream, "{\n");
+           if (TYPE_NFIELDS (type) == 0)
+             {
+               if (TYPE_STUB (type))
+                 fprintfi_filtered (level + 4, stream,
+                                    _("<incomplete type>\n"));
+               else
+                 fprintfi_filtered (level + 4, stream,
+                                    _("<no data fields>\n"));
+             }
+           len = TYPE_NFIELDS (type);
+           for (i = 0; i < len; i++)
+             {
+               QUIT;
+               print_spaces_filtered (level + 4, stream);
+               /* We pass "show" here and not "show - 1" to get enum types
+                  printed.  There's no other way to see them.  */
+               c_print_type (TYPE_FIELD_TYPE (type, i),
+                             TYPE_FIELD_NAME (type, i),
+                             stream, show, level + 4,
+                             &local_flags);
+               fprintf_filtered (stream, " @%s",
+                                 plongest (TYPE_FIELD_BITPOS (type, i)));
+               if (TYPE_FIELD_BITSIZE (type, i) > 1)
+                 {
+                   fprintf_filtered (stream, "-%s",
+                                     plongest (TYPE_FIELD_BITPOS (type, i)
+                                               + TYPE_FIELD_BITSIZE (type, i)
+                                               - 1));
+                 }
+               fprintf_filtered (stream, ";\n");
+             }
+           fprintfi_filtered (level, stream, "}");
+         }
+      }
+      break;
+
     case TYPE_CODE_VOID:
       fprintf_filtered (stream, "void");
       break;
This page took 0.029659 seconds and 4 git commands to generate.