diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index e0c18c883da..6d9192f2a26 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 #include "stringpool.h"
 #include "attribs.h"
+#include "bitmap.h"
 
 /* Local functions, macros and variables.  */
 static int  dump_ada_node (pretty_printer *, tree, tree, int, bool, bool);
@@ -1475,30 +1476,21 @@ dump_ada_decl_name (pretty_printer *buffer, tree decl, bool limited_access)
     }
 }
 
-/* Dump in BUFFER a name based on both T1 and T2 followed by a suffix.  */
+/* Dump in BUFFER a name for the type T, which is a _TYPE without TYPE_NAME.
+   PARENT is the parent node of T.  */
 
 static void
-dump_ada_double_name (pretty_printer *buffer, tree t1, tree t2)
+dump_anonymous_type_name (pretty_printer *buffer, tree t, tree parent)
 {
-  if (DECL_NAME (t1))
-    pp_ada_tree_identifier (buffer, DECL_NAME (t1), t1, false);
+  if (DECL_NAME (parent))
+    pp_ada_tree_identifier (buffer, DECL_NAME (parent), parent, false);
   else
     {
       pp_string (buffer, "anon");
-      pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (t1)));
+      pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (parent)));
     }
 
-  pp_underscore (buffer);
-
-  if (DECL_NAME (t2))
-    pp_ada_tree_identifier (buffer, DECL_NAME (t2), t2, false);
-  else
-    {
-      pp_string (buffer, "anon");
-      pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (t2)));
-    }
-
-  switch (TREE_CODE (TREE_TYPE (t2)))
+  switch (TREE_CODE (t))
     {
     case ARRAY_TYPE:
       pp_string (buffer, "_array");
@@ -1516,6 +1508,8 @@ dump_ada_double_name (pretty_printer *buffer, tree t1, tree t2)
       pp_string (buffer, "_unknown");
       break;
     }
+
+  pp_scalar (buffer, "%d", TYPE_UID (t));
 }
 
 /* Dump in BUFFER aspect Import on a given node T.  SPC is the current
@@ -1816,10 +1810,9 @@ dump_ada_array_type (pretty_printer *buffer, tree node, tree type, int spc)
   /* Print the dimensions.  */
   dump_ada_array_domains (buffer, node, spc);
 
-  /* Print array's type.  */
+  /* Print the component type.  */
   if (!char_array)
     {
-      /* Retrieve the element type.  */
       tree tmp = node;
       while (TREE_CODE (tmp) == ARRAY_TYPE)
 	tmp = TREE_TYPE (tmp);
@@ -1829,10 +1822,12 @@ dump_ada_array_type (pretty_printer *buffer, tree node, tree type, int spc)
       if (TREE_CODE (tmp) != POINTER_TYPE)
 	pp_string (buffer, "aliased ");
 
-      if (TYPE_NAME (tmp) || !RECORD_OR_UNION_TYPE_P (tmp))
+      if (TYPE_NAME (tmp)
+	  || (!RECORD_OR_UNION_TYPE_P (tmp)
+	      && TREE_CODE (tmp) != ENUMERAL_TYPE))
 	dump_ada_node (buffer, tmp, node, spc, false, true);
-      else
-	dump_ada_double_name (buffer, type, get_underlying_decl (tmp));
+      else if (type)
+	dump_anonymous_type_name (buffer, tmp, type);
     }
 }
 
@@ -2469,10 +2464,11 @@ dump_forward_type (pretty_printer *buffer, tree type, tree t, int spc)
   TREE_VISITED (decl) = 1;
 }
 
-static void dump_nested_type (pretty_printer *, tree, tree, tree, int);
+static void dump_nested_type (pretty_printer *, tree, tree, tree, bitmap, int);
 
-/* Dump in BUFFER anonymous types nested inside T's definition.
-   PARENT is the parent node of T.  SPC is the indentation level.
+/* Dump in BUFFER anonymous types nested inside T's definition.  PARENT is the
+   parent node of T.  DUMPED_TYPES is the bitmap of already dumped types.  SPC
+   is the indentation level.
 
    In C anonymous nested tagged types have no name whereas in C++ they have
    one.  In C their TYPE_DECL is at top level whereas in C++ it is nested.
@@ -2484,13 +2480,14 @@ static void dump_nested_type (pretty_printer *, tree, tree, tree, int);
    pass on the nested TYPE_DECLs and a second pass on the unnamed types.  */
 
 static void
-dump_nested_types (pretty_printer *buffer, tree t, tree parent, int spc)
+dump_nested_types_1 (pretty_printer *buffer, tree t, tree parent,
+		     bitmap dumped_types, int spc)
 {
   tree type, field;
 
   /* Find possible anonymous pointers/arrays/structs/unions recursively.  */
   type = TREE_TYPE (t);
-  if (type == NULL_TREE)
+  if (!type)
     return;
 
   for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
@@ -2498,19 +2495,31 @@ dump_nested_types (pretty_printer *buffer, tree t, tree parent, int spc)
 	&& DECL_NAME (field) != DECL_NAME (t)
 	&& !DECL_ORIGINAL_TYPE (field)
 	&& TYPE_NAME (TREE_TYPE (field)) != TYPE_NAME (type))
-      dump_nested_type (buffer, field, t, parent, spc);
+      dump_nested_type (buffer, field, t, parent, dumped_types, spc);
 
   for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
     if (TREE_CODE (field) == FIELD_DECL && !TYPE_NAME (TREE_TYPE (field)))
-      dump_nested_type (buffer, field, t, parent, spc);
+      dump_nested_type (buffer, field, t, parent, dumped_types, spc);
 }
 
-/* Dump in BUFFER the anonymous type of FIELD inside T.
-   PARENT is the parent node of T.  SPC is the indentation level.  */
+/* Likewise, but to be invoked only at top level.  We dump each anonymous type
+   nested inside T's definition exactly once, even if it is referenced several
+   times in it (typically an array type), with a name prefixed by that of T.  */
+
+static void
+dump_nested_types (pretty_printer *buffer, tree t, int spc)
+{
+  auto_bitmap dumped_types;
+  dump_nested_types_1 (buffer, t, t, dumped_types, spc);
+}
+
+/* Dump in BUFFER the anonymous type of FIELD inside T.  PARENT is the parent
+   node of T.  DUMPED_TYPES is the bitmap of already dumped types.  SPC is the
+   indentation level.  */
 
 static void
 dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
-		  int spc)
+		  bitmap dumped_types, int spc)
 {
   tree field_type = TREE_TYPE (field);
   tree decl, tmp;
@@ -2523,6 +2532,11 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
       break;
 
     case ARRAY_TYPE:
+      /* Anonymous array types are shared.  */
+      if (!bitmap_set_bit (dumped_types, TYPE_UID (field_type)))
+	return;
+
+      /* Recurse on the element type if need be.  */
       tmp = TREE_TYPE (field_type);
       while (TREE_CODE (tmp) == ARRAY_TYPE)
 	tmp = TREE_TYPE (tmp);
@@ -2533,7 +2547,7 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
 	  && !TREE_VISITED (decl))
 	{
 	  /* Generate full declaration.  */
-	  dump_nested_type (buffer, decl, t, parent, spc);
+	  dump_nested_type (buffer, decl, t, parent, dumped_types, spc);
 	  TREE_VISITED (decl) = 1;
 	}
       else if (!decl && TREE_CODE (tmp) == POINTER_TYPE)
@@ -2545,7 +2559,7 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
       else
 	pp_string (buffer, "type ");
 
-      dump_ada_double_name (buffer, parent, field);
+      dump_anonymous_type_name (buffer, field_type, parent);
       pp_string (buffer, " is ");
       dump_ada_array_type (buffer, field_type, parent, spc);
       pp_semicolon (buffer);
@@ -2561,7 +2575,7 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
       if (TYPE_NAME (field_type))
 	dump_ada_node (buffer, field_type, NULL_TREE, spc, false, true);
       else
-	dump_ada_double_name (buffer, parent, field);
+	dump_anonymous_type_name (buffer, field_type, parent);
       pp_string (buffer, " is ");
       dump_ada_enum_type (buffer, field_type, spc);
       pp_semicolon (buffer);
@@ -2570,14 +2584,14 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
 
     case RECORD_TYPE:
     case UNION_TYPE:
-      dump_nested_types (buffer, field, t, spc);
+      dump_nested_types_1 (buffer, field, parent, dumped_types, spc);
 
       pp_string (buffer, "type ");
 
       if (TYPE_NAME (field_type))
 	dump_ada_node (buffer, field_type, NULL_TREE, spc, false, true);
       else
-	dump_ada_double_name (buffer, parent, field);
+	dump_anonymous_type_name (buffer, field_type, parent);
 
       if (TREE_CODE (field_type) == UNION_TYPE)
 	pp_string (buffer, " (discr : unsigned := 0)");
@@ -2843,7 +2857,7 @@ dump_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
 	      pp_string (buffer, "subtype ");
 	    else
 	      {
-		dump_nested_types (buffer, t, t, spc);
+		dump_nested_types (buffer, t, spc);
 
                 if (separate_class_package (t))
 		  {
@@ -2920,8 +2934,6 @@ dump_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
 	}
       else
 	{
-	  tree tmp = TYPE_NAME (TREE_TYPE (t));
-
 	  if (spc == INDENT_INCR || TREE_STATIC (t))
 	    is_var = true;
 
@@ -2930,10 +2942,10 @@ dump_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
 	  if (TREE_CODE (TREE_TYPE (TREE_TYPE (t))) != POINTER_TYPE)
 	    pp_string (buffer, "aliased ");
 
-	  if (tmp)
-	    dump_ada_node (buffer, tmp, type, spc, false, true);
+	  if (TYPE_NAME (TREE_TYPE (t)))
+	    dump_ada_node (buffer, TREE_TYPE (t), type, spc, false, true);
 	  else if (type)
-	    dump_ada_double_name (buffer, type, t);
+	    dump_anonymous_type_name (buffer, TREE_TYPE (t), type);
 	  else
 	    dump_ada_array_type (buffer, TREE_TYPE (t), type, spc);
 	}
@@ -3152,33 +3164,21 @@ dump_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
 
 	  pp_string (buffer, " : ");
 
-	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))
-	      || TREE_CODE (TREE_TYPE (t)) == ENUMERAL_TYPE)
-	    {
-	      if (TYPE_NAME (TREE_TYPE (t))
-		  || TREE_CODE (TREE_TYPE (t)) != ENUMERAL_TYPE)
-		pp_string (buffer, "aliased ");
-
-	      if (TREE_READONLY (t) && TREE_CODE (t) != FIELD_DECL)
-		pp_string (buffer, "constant ");
-
-	      if (TYPE_NAME (TREE_TYPE (t)))
-		dump_ada_node (buffer, TREE_TYPE (t), t, spc, false, true);
-	      else if (type)
-		dump_ada_double_name (buffer, type, t);
-	    }
-	  else
-	    {
-	      if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE
-		  && (TYPE_NAME (TREE_TYPE (t))
-		      || TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE))
-		pp_string (buffer, "aliased ");
+	  if (TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE
+	      && (TYPE_NAME (TREE_TYPE (t))
+		  || (TREE_CODE (TREE_TYPE (t)) != INTEGER_TYPE
+		      && TREE_CODE (TREE_TYPE (t)) != ENUMERAL_TYPE)))
+	    pp_string (buffer, "aliased ");
 
-	      if (TREE_READONLY (t) && TREE_CODE (t) != FIELD_DECL)
-		pp_string (buffer, "constant ");
+	  if (TREE_READONLY (t) && TREE_CODE (t) != FIELD_DECL)
+	    pp_string (buffer, "constant ");
 
-	      dump_ada_node (buffer, TREE_TYPE (t), t, spc, false, true);
-	    }
+	  if (TYPE_NAME (TREE_TYPE (t))
+	      || (!RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))
+		  && TREE_CODE (TREE_TYPE (t)) != ENUMERAL_TYPE))
+	    dump_ada_node (buffer, TREE_TYPE (t), t, spc, false, true);
+	  else if (type)
+	    dump_anonymous_type_name (buffer, TREE_TYPE (t), type);
 	}
     }
 
@@ -3474,6 +3474,8 @@ void
 dump_ada_specs (void (*collect_all_refs)(const char *),
 		int (*check)(tree, cpp_operation))
 {
+  bitmap_obstack_initialize (NULL);
+
   /* Iterate over the list of files to dump specs for.  */
   for (int i = 0; i < source_refs_used; i++)
     dump_ads (source_refs[i], collect_all_refs, check);
@@ -3481,4 +3483,6 @@ dump_ada_specs (void (*collect_all_refs)(const char *),
   /* Free various tables.  */
   free (source_refs);
   delete overloaded_names;
+
+  bitmap_obstack_release (NULL);
 }
