diff --git a/libiberty/cplus-dem.c b/libiberty/cplus-dem.c
index f20a5ef..396e617 100644
--- a/libiberty/cplus-dem.c
+++ b/libiberty/cplus-dem.c
@@ -895,18 +895,20 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
 
   /* Most of the demangling will trivially remove chars.  Operator names
      may add one char but because they are always preceeded by '__' which is
-     replaced by '.', they eventually never expand the size.  '___elabs' and
-     '___elabb' add only 2 chars, but they occur only once.  */
-  len0 = strlen (mangled) + 2 + 1;
+     replaced by '.', they eventually never expand the size.
+     A few special names such as '___elabs' add a few chars (at most 7), but
+     they occur only once.  */
+  len0 = strlen (mangled) + 7 + 1;
   demangled = XNEWVEC (char, len0);
   
   d = demangled;
   p = mangled;
   while (1)
     {
-      /* Convert name, which is always lower-case.  */
+      /* An entity names is expected.  */
       if (ISLOWER (*p))
         {
+          /* An identifier, which is always lower case.  */
           do
             *d++ = *p++;
           while (ISLOWER(*p) || ISDIGIT (*p)
@@ -914,6 +916,7 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
         }
       else if (p[0] == 'O')
         {
+          /* An operator name.  */
           static const char * const operators[][2] =
             {{"Oabs", "abs"},  {"Oand", "and"},    {"Omod", "mod"},
              {"Onot", "not"},  {"Oor", "or"},      {"Orem", "rem"},
@@ -948,6 +951,92 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
           goto unknown;
         }
 
+      /* The name can be directly followed by some uppercase letters.  */
+      if (p[0] == 'T' && p[1] == 'K')
+        {
+          /* Task stuff.  */
+          if (p[2] == 'B' && p[3] == 0)
+            {
+              /* Subprogram for task body.  */
+              break;
+            }
+          else if (p[2] == '_' && p[3] == '_')
+            {
+              /* Inner declarations in a task.  */
+              p += 4;
+              *d++ = '.';
+              continue;
+            }
+          else
+            goto unknown;
+        }
+      if (p[0] == 'E' && p[1] == 0)
+        {
+          /* Exception name.  */
+          goto unknown;
+        }
+      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
+        {
+          /* Protected type subprogram.  */
+          break;
+        }
+      if ((*p == 'N' || *p == 'S') && p[1] == 0)
+        {
+          /* Enumerated type name table.  */
+          goto unknown;
+        }
+      if (p[0] == 'X')
+        {
+          /* Body nested.  */
+          p++;
+          while (p[0] == 'n' || p[0] == 'b')
+            p++;
+        }
+      if (p[0] == 'S' && p[1] && (p[2] == '_' || p[2] == 0))
+        {
+          /* Stream operations.  */
+          const char *name;
+          switch (p[1])
+            {
+            case 'R':
+              name = "'Read";
+              break;
+            case 'W':
+              name = "'Write";
+              break;
+            case 'I':
+              name = "'Input";
+              break;
+            case 'O':
+              name = "'Output";
+              break;
+            default:
+              goto unknown;
+            }
+          p += 2;
+          strcpy (d, name);
+          d += strlen (name);
+        }
+      else if (p[0] == 'D')
+        {
+          /* Controlled type operation.  */
+          const char *name;
+          switch (p[1])
+            {
+            case 'F':
+              name = ".Finalize";
+              break;
+            case 'A':
+              name = ".Adjust";
+              break;
+            default:
+              goto unknown;
+            }
+          strcpy (d, name);
+          d += strlen (name);
+          break;
+        }
+
       if (p[0] == '_')
         {
           /* Separator.  */
@@ -955,24 +1044,49 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
             {
               /* Standard separator.  Handled first.  */
               p += 2;
+
               if (ISDIGIT (*p))
                 {
-                  /* Overloading.  */
+                  /* Overloading number.  */
                   do
                     p++;
                   while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1])));
+                  if (*p == 'X')
+                    {
+                      p++;
+                      while (p[0] == 'n' || p[0] == 'b')
+                        p++;
+                    }
                 }
-              else if (*p == '_' && !strcmp (p + 1, "elabb"))
-                {
-                  memcpy (d, "'Elab_Body", 10);
-                  d += 10;
-                  break;
-                }
-              else if (*p == '_' && !strcmp (p + 1, "elabs"))
+              else if (p[0] == '_' && p[1] != '_')
                 {
-                  memcpy (d, "'Elab_Spec", 10);
-                  d += 10;
-                  break;
+                  /* Special names.  */
+                  static const char * const special[][2] = {
+                    { "_elabb", "'Elab_Body" },
+                    { "_elabs", "'Elab_Spec" },
+                    { "_size", "'Size" },
+                    { "_alignment", "'Alignment" },
+                    { "_assign", ".\":=\"" },
+                    { NULL, NULL }
+                  };
+                  int k;
+
+                  for (k = 0; special[k][0]; k++)
+                    {
+                      int l = strlen (special[k][0]);
+                      if (!strncmp (p, special[k][0], l))
+                        {
+                          p += l;
+                          l = strlen (special[k][1]);
+                          memcpy (d, special[k][1], l);
+                          d += l;
+                          break;
+                        }
+                    }
+                  if (special[k][0])
+                    break;
+                  else
+                    goto unknown;
                 }
               else
                 {
@@ -995,46 +1109,6 @@ ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
             goto unknown;
         }
 
-      if (p[0] == 'T' && p[1] == 'K')
-        {
-          if (p[2] == 'B' && p[3] == 0)
-            {
-              /* Subprogram for task body.  */
-              break;
-            }
-          else if (p[2] == '_' && p[3] == '_')
-            {
-              /* Inner declarations in a task.  */
-              p += 4;
-              *d++ = '.';
-              continue;
-            }
-          else
-            goto unknown;
-        }
-      if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
-        {
-          /* Protected type subprogram.  */
-          break;
-        }
-      if (p[0] == 'E' && p[1] == 0)
-        {
-          /* Exception name.  */
-          goto unknown;
-        }
-      if (*p == 'N' || *p == 'S')
-        {
-          /* Enumerated type name table.  */
-          goto unknown;
-        }
-      if (p[0] == 'X')
-        {
-          /* Body nested.  */
-          if (p[1] == 'n' || p[1] == 'b')
-            p += 2;
-          else if (p[1] == 0)
-            p++;
-        }
       if (p[0] == '.' && ISDIGIT (p[1]))
         {
           /* Nested subprogram.  */
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index 15a0fe7..2cd5251 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -4047,6 +4047,36 @@ prot.lock.update
 --format=gnat
 prot__lock__update_E6s
 prot.lock.update
+# Controlled types
+--format=gnat
+gnat__sockets__sockets_library_controllerDF__2
+gnat.sockets.sockets_library_controller.Finalize
+--format=gnat
+system__partition_interface__racw_stub_typeDA
+system.partition_interface.racw_stub_type.Adjust
+# Stream operations
+--format=gnat
+gnat__wide_wide_string_split__slice_setSR__2
+gnat.wide_wide_string_split.slice_set'Read
+--format=gnat
+ada__real_time__timing_events__events__listSW__2Xnn
+ada.real_time.timing_events.events.list'Write
+--format=gnat
+system__finalization_root__root_controlledSI
+system.finalization_root.root_controlled'Input
+--format=gnat
+ada__finalization__limited_controlledSO__2
+ada.finalization.limited_controlled'Output
+# Tagged types
+--format=gnat
+ada__synchronous_task_control___size__2
+ada.synchronous_task_control'Size
+--format=gnat
+ada__real_time__timing_events__events___alignment__2Xnn
+ada.real_time.timing_events.events'Alignment
+--format=gnat
+system__finalization_root___assign__2
+system.finalization_root.":="
 #
 # Used to crash the demangler.
 --format=gnu-v3
