OSDN Git Service

* diagnostic.h (set_internal_error_function): Renamed.
[pf3gnuchains/gcc-fork.git] / gcc / java / mangle.c
1 /* Functions related to mangling class names for the GNU compiler
2    for the Java(TM) language.
3    Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
4
5 This file is part of GNU CC.
6
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING.  If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. 
21
22 Java and all Java-based marks are trademarks or registered trademarks
23 of Sun Microsystems, Inc. in the United States and other countries.
24 The Free Software Foundation is independent of Sun Microsystems, Inc.  */
25
26 /* Written by Per Bothner <bothner@cygnus.com> */
27
28 #include "config.h"
29 #include "system.h"
30 #include "jcf.h"
31 #include "tree.h"
32 #include "java-tree.h"
33 #include "obstack.h"
34 #include "toplev.h"
35 #include "obstack.h"
36 #include "ggc.h"
37
38 static void mangle_field_decl PARAMS ((tree));
39 static void mangle_method_decl PARAMS ((tree));
40
41 static void mangle_type PARAMS ((tree));
42 static void mangle_pointer_type PARAMS ((tree));
43 static void mangle_array_type PARAMS ((tree));
44 static int  mangle_record_type PARAMS ((tree, int));
45
46 static int find_compression_pointer_match PARAMS ((tree));
47 static int find_compression_array_match PARAMS ((tree));
48 static int find_compression_record_match PARAMS ((tree, tree *));
49 static int find_compression_array_template_match PARAMS ((tree));
50
51 static void set_type_package_list PARAMS ((tree));
52 static int  entry_match_pointer_p PARAMS ((tree, int));
53 static void emit_compression_string PARAMS ((int));
54
55 static void init_mangling PARAMS ((struct obstack *));
56 static tree finish_mangling PARAMS ((void));
57 static void compression_table_add PARAMS ((tree));
58
59 static void append_unicode_mangled_name PARAMS ((const char *, int));
60 static void append_gpp_mangled_name PARAMS ((const char *, int));
61 static int  unicode_mangling_length PARAMS ((const char *, int));
62 static int  mangle_member_name PARAMS ((tree));
63
64 /* We use an incoming obstack, always to be provided to the interface
65    functions. */
66 struct obstack *mangle_obstack;
67 #define MANGLE_RAW_STRING(S) \
68   obstack_grow (mangle_obstack, (S), sizeof (S)-1)
69
70 /* This is the mangling interface: a decl, a class field (.class) and
71    the vtable. */
72
73 tree
74 java_mangle_decl (obstack, decl)
75      struct obstack *obstack;
76      tree decl;
77 {
78   init_mangling (obstack);
79   switch (TREE_CODE (decl))
80     {
81     case VAR_DECL:
82       mangle_field_decl (decl);
83       break;
84     case FUNCTION_DECL:
85       mangle_method_decl (decl);
86       break;
87     default:
88       internal_error ("Can't mangle %s", tree_code_name [TREE_CODE (decl)]);
89     }
90   return finish_mangling ();
91 }
92
93 tree 
94 java_mangle_class_field (obstack, type)
95      struct obstack *obstack;
96      tree type;
97 {
98   init_mangling (obstack);
99   mangle_record_type (type, /* from_pointer = */ 0);
100   MANGLE_RAW_STRING ("6class$");
101   obstack_1grow (mangle_obstack, 'E');
102   return finish_mangling ();
103 }
104
105 tree
106 java_mangle_vtable (obstack, type)
107      struct obstack *obstack;
108      tree type;
109 {
110   init_mangling (obstack);
111   MANGLE_RAW_STRING ("TV");
112   mangle_record_type (type, /* from_pointer = */ 0);
113   obstack_1grow (mangle_obstack, 'E');
114   return finish_mangling ();
115 }
116
117 /* Beginning of the helper functions */
118
119 /* This mangles a field decl */
120
121 static void
122 mangle_field_decl (decl)
123      tree decl;
124 {
125   tree name = DECL_NAME (decl);
126   int field_name_needs_escapes = 0;
127
128   /* Mangle the name of the this the field belongs to */
129   mangle_record_type (DECL_CONTEXT (decl), /* from_pointer = */ 0);
130   
131   /* Mangle the name of the field */
132   field_name_needs_escapes = mangle_member_name (name);
133
134   /* Terminate the mangled name */
135   obstack_1grow (mangle_obstack, 'E');
136   if (field_name_needs_escapes)
137     obstack_1grow (mangle_obstack, 'U');
138 }
139
140 /* This mangles a method decl, first mangling its name and then all
141    its arguments. */
142
143 static void
144 mangle_method_decl (mdecl)
145      tree mdecl;
146 {
147   tree method_name = DECL_NAME (mdecl);
148   tree arglist;
149   int method_name_needs_escapes = 0;
150
151   /* Mangle the name of the type that contains mdecl */
152   mangle_record_type (DECL_CONTEXT (mdecl), /* from_pointer = */ 0);
153
154   /* Mangle the function name. There three cases
155        - mdecl is java.lang.Object.Object(), use `C2' for its name
156          (denotes a base object constructor.)
157        - mdecl is a constructor, use `C1' for its name, (denotes a
158          complete object constructor.)
159        - mdecl is not a constructor, standard mangling is performed.
160      We terminate the mangled function name with a `E'. */
161   if (ID_INIT_P (method_name))
162     {
163       if (DECL_CONTEXT (mdecl) == object_type_node)
164         obstack_grow (mangle_obstack, "C2", 2);
165       else
166         obstack_grow (mangle_obstack, "C1", 2);
167     }
168   else
169     method_name_needs_escapes = mangle_member_name (method_name);
170   obstack_1grow (mangle_obstack, 'E');
171
172   /* We mangled type.methodName. Now onto the arguments. */
173   arglist = TYPE_ARG_TYPES (TREE_TYPE (mdecl));
174   if (TREE_CODE (TREE_TYPE (mdecl)) == METHOD_TYPE)
175     arglist = TREE_CHAIN (arglist);
176   
177   /* No arguments is easy. We shortcut it. */
178   if (arglist == end_params_node)
179     obstack_1grow (mangle_obstack, 'v');
180   else
181     {
182       tree arg;
183       for (arg = arglist; arg != end_params_node;  arg = TREE_CHAIN (arg))
184         mangle_type (TREE_VALUE (arg));
185     }
186
187   /* Terminate the mangled name */
188   if (method_name_needs_escapes)
189     obstack_1grow (mangle_obstack, 'U');
190 }
191
192 /* This mangles a member name, like a function name or a field
193    name. Handle cases were `name' is a C++ keyword.  Return a non zero
194    value if unicode encoding was required.  */
195
196 static int
197 mangle_member_name (name)
198      tree name;
199 {
200   const char * name_string = IDENTIFIER_POINTER (name);
201   int len = IDENTIFIER_LENGTH (name);
202   int to_return = 0;
203
204   if (unicode_mangling_length (name_string, len) > 0)
205     {
206       append_unicode_mangled_name (name_string, len);
207       to_return = 1;
208     }
209   else
210     append_gpp_mangled_name (name_string, len);
211
212   /* If NAME happens to be a C++ keyword, add `$' or `.' or `_'. */
213   if (cxx_keyword_p (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name)))
214     {
215 #ifndef NO_DOLLAR_IN_LABEL
216       obstack_1grow (mangle_obstack, '$');
217 #else  /* NO_DOLLAR_IN_LABEL */
218 #ifndef NO_DOT_IN_LABEL
219       obstack_1grow (mangle_obstack, '.');
220 #else  /* NO_DOT_IN_LABEL */
221       obstack_1grow (mangle_obstack, '_');
222 #endif /* NO_DOT_IN_LABEL */
223 #endif /* NO_DOLLAR_IN_LABEL */
224     }
225
226   return to_return;
227 }
228
229 /* Assuming (NAME, LEN) is a Utf8-encoding string, calculate
230    the length of the string as mangled (a la g++) including Unicode escapes.
231    If no escapes are needed, return 0. */
232
233 static int
234 unicode_mangling_length (name, len)
235      const char *name; 
236      int len; 
237 {
238   const unsigned char *ptr;
239   const unsigned char *limit = (const unsigned char *)name + len;
240   int need_escapes = 0;
241   int num_chars = 0;
242   int underscores = 0;
243   for (ptr = (const unsigned char *) name;  ptr < limit;  )
244     {
245       int ch = UTF8_GET(ptr, limit);
246       if (ch < 0)
247         error ("internal error - invalid Utf8 name");
248       if (ch >= '0' && ch <= '9')
249         need_escapes += num_chars == 0;
250       else if (ch == '_')
251         underscores++;
252       else if (ch != '$' && (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'))
253         need_escapes++;
254       num_chars++;
255     }
256   if (need_escapes)
257     return num_chars + 4 * (need_escapes + underscores);
258   else
259     return 0;
260 }
261
262 /* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string
263    appropriately mangled (with Unicode escapes) to OBSTACK. */
264
265 static void
266 append_unicode_mangled_name (name, len)
267      const char *name;
268      int len;
269 {
270   const unsigned char *ptr;
271   const unsigned char *limit = (const unsigned char *)name + len;
272   for (ptr = (const unsigned char *) name;  ptr < limit;  )
273     {
274       int ch = UTF8_GET(ptr, limit);
275       int emit_escape;
276       if (ch < 0)
277         {
278           error ("internal error - bad Utf8 string");
279           break;
280         }
281       if (ch >= '0' && ch <= '9')
282         emit_escape = (ptr == (const unsigned char *) name);
283       else
284         emit_escape = (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z');
285       if (emit_escape)
286         {
287           char buf[6];
288           sprintf (buf, "_%04x", ch);
289           obstack_grow (mangle_obstack, buf, 5);
290         }
291       else
292         {
293           obstack_1grow (mangle_obstack, ch);
294         }
295     }
296 }
297
298 /* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string
299    appropriately mangled (with Unicode escapes if needed) to OBSTACK. */
300
301 static void
302 append_gpp_mangled_name (name, len)
303      const char *name;
304      int len;
305 {
306   int encoded_len = unicode_mangling_length (name, len);
307   int needs_escapes = encoded_len > 0;
308   char buf[6];
309   if (needs_escapes)
310     {
311       sprintf (buf, "U%d", encoded_len);
312       obstack_grow (mangle_obstack, buf, strlen(buf));
313       append_unicode_mangled_name (name, len);
314     }
315   else
316     {
317       sprintf (buf, "%d", len);
318       obstack_grow (mangle_obstack, buf, strlen(buf));
319       obstack_grow (mangle_obstack, name, len);
320     }
321 }
322
323 /* Append the mangled name of TYPE onto OBSTACK.  */
324
325 static void
326 mangle_type (type)
327      tree type;
328 {
329   switch (TREE_CODE (type))
330     {
331       char code;
332     case BOOLEAN_TYPE: code = 'b';  goto primitive;
333     case CHAR_TYPE:    code = 'w';  goto primitive;
334     case VOID_TYPE:    code = 'v';  goto primitive;
335     case INTEGER_TYPE:
336       /* Get the original type instead of the arguments promoted type.
337          Avoid symbol name clashes. Should call a function to do that.
338          FIXME.  */
339       if (type == promoted_short_type_node)
340         type = short_type_node;
341       if (type == promoted_byte_type_node)
342         type = byte_type_node;
343       switch (TYPE_PRECISION (type))
344         {
345         case  8:       code = 'c';  goto primitive;
346         case 16:       code = 's';  goto primitive;
347         case 32:       code = 'i';  goto primitive;
348         case 64:       code = 'x';  goto primitive;
349         default:  goto bad_type;
350         }
351     primitive:
352       obstack_1grow (mangle_obstack, code);
353       break;
354
355     case REAL_TYPE:
356       switch (TYPE_PRECISION (type))
357         {
358         case 32:       code = 'f';  goto primitive;
359         case 64:       code = 'd';  goto primitive;
360         default:  goto bad_type;
361         }
362     case POINTER_TYPE:
363       if (TYPE_ARRAY_P (TREE_TYPE (type)))
364         mangle_array_type (type);
365       else
366         mangle_pointer_type (type);
367       break;
368     bad_type:
369     default:
370       abort ();
371     }
372 }
373
374 /* The compression table is a vector that keeps track of things we've
375    already seen, so they can be reused. For example, java.lang.Object
376    Would generate three entries: two package names and a type. If
377    java.lang.String is presented next, the java.lang will be matched
378    against the first two entries (and kept for compression as S_0), and
379    type String would be added to the table. See mangle_record_type.
380    COMPRESSION_NEXT is the index to the location of the next insertion
381    of an element.  */
382
383 static tree compression_table;
384 static int  compression_next;
385
386 /* Find a POINTER_TYPE in the compression table. Use a special
387    function to match pointer entries and start from the end */
388
389 static int
390 find_compression_pointer_match (type)
391      tree type;
392 {
393   int i;
394
395   for (i = compression_next-1; i >= 0; i--)
396     if (entry_match_pointer_p (type, i))
397       return i;
398   return -1;
399 }
400
401 /* Already recorder arrays are handled like pointer as they're always
402    associated with it.  */
403
404 static int
405 find_compression_array_match (type)
406      tree type;
407 {
408   return find_compression_pointer_match (type);
409 }
410
411 /* Match the table of type against STRING.  */
412
413 static int
414 find_compression_array_template_match (string)
415      tree string;
416 {
417   int i;
418   for (i = 0; i < compression_next; i++)
419     if (TREE_VEC_ELT (compression_table, i) == string) 
420       return i;
421   return -1;
422 }
423
424 /* We go through the compression table and try to find a complete or
425    partial match. The function returns the compression table entry
426    that (evenutally partially) matches TYPE. *NEXT_CURRENT can be set
427    to the rest of TYPE to be mangled. */
428
429 static int
430 find_compression_record_match (type, next_current)
431      tree type;
432      tree *next_current;
433 {
434   int i, match;
435   tree current, saved_current;
436
437   /* Search from the beginning for something that matches TYPE, even
438      partially. */
439   for (current = TYPE_PACKAGE_LIST (type), i = 0, match = -1; current;
440        current = TREE_CHAIN (current))
441     {
442       int j;
443       for (j = i; j < compression_next; j++)
444         if (TREE_VEC_ELT (compression_table, j) == TREE_PURPOSE (current))
445           {
446             match = i = j;
447             saved_current = current;
448             break;
449           }
450     }
451
452   if (!next_current)
453     return match;
454
455   /* If we have a match, set next_current to the item next to the last
456      matched value. */
457   if (match >= 0)
458     *next_current = TREE_CHAIN (saved_current);
459   /* We had no match: we'll have to start from the beginning. */
460   if (match < 0)
461     *next_current = TYPE_PACKAGE_LIST (type);
462
463   return match;
464 }
465
466 /* Mangle a record type. If a non zero value is returned, it means
467    that a 'N' was emitted (so that a matching 'E' can be emitted if
468    necessary.)  */
469
470 static int
471 mangle_record_type (type, from_pointer)
472      tree type;
473      int from_pointer;
474 {
475   tree current;
476   int match;
477   int nadded_p = 0;
478
479 #define ADD_N() \
480   do { obstack_1grow (mangle_obstack, 'N'); nadded_p = 1; } while (0)
481
482   if (TREE_CODE (type) != RECORD_TYPE)
483     abort ();
484
485   if (!TYPE_PACKAGE_LIST (type))
486     set_type_package_list (type);
487
488   match = find_compression_record_match (type, &current);
489   if (match >= 0)
490     {
491       /* If we had a pointer, and there's more, we need to emit
492          'N' after 'P' (from pointer tells us we already emitted it.) */
493       if (from_pointer && current)
494         ADD_N();
495       emit_compression_string (match);
496     }
497   while (current)
498     {
499       /* Add the new type to the table */
500       compression_table_add (TREE_PURPOSE (current));
501       /* Add 'N' if we never got a chance to. */
502       if (!nadded_p)
503         ADD_N();
504       /* Use the bare type name for the mangle. */
505       append_gpp_mangled_name (IDENTIFIER_POINTER (TREE_VALUE (current)),
506                                IDENTIFIER_LENGTH (TREE_VALUE (current)));
507       current = TREE_CHAIN (current);
508     }
509   return nadded_p;
510 #undef ADD_N
511 }
512
513 /* Mangle a pointer type. There are two cases: the pointer is already
514    in the compression table: the compression is emited sans 'P'
515    indicator. Otherwise, a 'P' is emitted and, depending on the type,
516    a partial compression or/plus the rest of the mangling. */
517
518 static void
519 mangle_pointer_type (type)
520      tree type;
521 {
522   int match;
523   tree pointer_type;
524
525   /* Search for the type already in the compression table */
526   if ((match = find_compression_pointer_match (type)) >= 0) 
527     {
528       emit_compression_string (match);
529       return;
530     }
531   
532   /* This didn't work. We start by mangling the pointed-to type */
533   pointer_type = type;
534   type = TREE_TYPE (type);
535   if (TREE_CODE (type) != RECORD_TYPE)
536     abort ();
537   
538   obstack_1grow (mangle_obstack, 'P');
539   if (mangle_record_type (type, /* for_pointer = */ 1))
540     obstack_1grow (mangle_obstack, 'E');
541
542   /* Don't forget to insert the pointer type in the table */
543   compression_table_add (pointer_type);
544 }
545
546 /* Mangle an array type. Search for an easy solution first, then go
547    through the process of finding out whether the bare array type or even
548    the template indicator where already used an compress appropriately.
549    It handles pointers. */
550
551 static void
552 mangle_array_type (p_type)
553      tree p_type;
554 {
555   /* atms: array template mangled string. */
556   static tree atms = NULL_TREE;
557   tree type, elt_type;
558   int match;
559
560   type = TREE_TYPE (p_type);
561   if (!type)
562     abort ();
563
564   elt_type = TYPE_ARRAY_ELEMENT (type);
565
566   /* We cache a bit of the Jarray <> mangle. */
567   if (!atms)
568     {
569       atms = get_identifier ("6JArray");
570       ggc_add_tree_root (&atms, 1);
571     }
572
573   /* Maybe we have what we're looking in the compression table. */
574   if ((match = find_compression_array_match (p_type)) >= 0)
575     {
576       emit_compression_string (match);
577       return;
578     }
579
580   /* We know for a fact that all arrays are pointers */
581   obstack_1grow (mangle_obstack, 'P');
582   /* Maybe we already have a Jarray<t> somewhere. PSx_ will be enough. */
583   if ((match = find_compression_record_match (type, NULL)) > 0)
584     {
585       emit_compression_string (match);
586       return;
587     }
588
589   /* Maybe we already have just JArray somewhere */
590   if ((match = find_compression_array_template_match (atms)) > 0)
591     emit_compression_string (match);
592   else
593     {
594       /* Start the template mangled name */
595       obstack_grow (mangle_obstack, 
596                     IDENTIFIER_POINTER (atms), IDENTIFIER_LENGTH (atms));
597       /* Insert in the compression table */
598       compression_table_add (atms);
599     } 
600
601   /* Mangle Jarray <elt_type> */
602   obstack_1grow (mangle_obstack, 'I');
603   mangle_type (elt_type);
604   obstack_1grow (mangle_obstack, 'E');
605
606   /* Add `Jarray <elt_type>' and `Jarray <elt_type> *' to the table */
607   compression_table_add (type);
608   compression_table_add (p_type);
609 }
610
611 /* Write a substition string for entry I. Substitution string starts a
612    -1 (encoded S_.) The base is 36, and the code shamlessly taken from
613    cp/mangle.c.  */
614
615 static void
616 emit_compression_string (int i)
617 {
618   i -= 1;                       /* Adjust */
619   obstack_1grow (mangle_obstack, 'S');
620   if (i >= 0)
621     {
622       static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
623       unsigned HOST_WIDE_INT n;
624       unsigned HOST_WIDE_INT m=1;
625       /* How many digits for I in base 36? */
626       for (n = i; n >= 36; n /= 36, m *=36);
627       /* Write the digits out */
628       while (m > 0)
629         {
630           int digit = i / m;
631           obstack_1grow (mangle_obstack, digits [digit]);
632           i -= digit * m;
633           m /= 36;
634         }
635     }
636   obstack_1grow (mangle_obstack, '_');
637 }
638
639 /* If search the compression table at index I for a pointer type
640    equivalent to TYPE (meaning that after all the indirection, which
641    might all be unique, we find the same RECORD_TYPE.) */
642
643 static int
644 entry_match_pointer_p (type, i)
645      tree type;
646      int i;
647 {
648   tree t = TREE_VEC_ELT (compression_table, i);
649   
650   while (TREE_CODE (type) == POINTER_TYPE
651          && TREE_CODE (t) == POINTER_TYPE)
652     {
653       t = TREE_TYPE (t);
654       type = TREE_TYPE (type);
655     }
656   return (TREE_CODE (type) == RECORD_TYPE
657           && TREE_CODE (t) == RECORD_TYPE
658           && t == type);
659 }
660
661 /* Go through all qualification of type and build a list of list node
662    elements containings as a purpose what should be used for a match and
663    inserted in the compression table; and as it value the raw name of the
664    part. The result is stored in TYPE_PACKAGE_LIST to be reused.  */
665
666 static void
667 set_type_package_list (type)
668      tree type;
669 {
670   int i;
671   const char *type_string = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
672   char *ptr;
673   int qualifications;
674   tree list = NULL_TREE, elt;
675
676   for (ptr = (char *)type_string, qualifications = 0; *ptr; ptr++)
677     if (*ptr == '.')
678       qualifications += 1;
679
680   for (ptr = (char *)type_string, i = 0; i < qualifications; ptr++)
681     {
682       if (ptr [0] == '.')
683         {
684           char c;
685           tree identifier;
686
687           /* Can't use an obstack, we're already using it to
688              accumulate the mangling. */
689           c = ptr [0];
690           ptr [0] = '\0';
691           identifier = get_identifier (type_string);
692           ptr [0] = c;
693           elt = build_tree_list (identifier, identifier);
694           TREE_CHAIN (elt) = list;
695           list = elt;
696           type_string = ptr+1;
697           i += 1;
698         }
699     }
700
701   elt = build_tree_list (type, get_identifier (type_string));
702   TREE_CHAIN (elt) = list;
703   list = elt;
704   TYPE_PACKAGE_LIST (type) = nreverse (list);
705 }
706
707 /* Add TYPE as the last element of the compression table. Resize the
708    compression table if necessary.  */
709
710 static void
711 compression_table_add (type)
712      tree type;
713 {
714   if (compression_next == TREE_VEC_LENGTH (compression_table))
715     {
716       tree new = make_tree_vec (2*compression_next);
717       int i;
718
719       for (i = 0; i < compression_next; i++)
720         TREE_VEC_ELT (new, i) = TREE_VEC_ELT (compression_table, i);
721
722       ggc_del_root (&compression_table);
723       compression_table = new;
724       ggc_add_tree_root (&compression_table, 1);
725     }
726   TREE_VEC_ELT (compression_table, compression_next++) = type;
727 }
728
729 /* Mangling initialization routine.  */
730
731 static void
732 init_mangling (obstack)
733      struct obstack *obstack;
734 {
735   mangle_obstack = obstack;
736   if (!compression_table)
737     compression_table = make_tree_vec (10);
738   else
739     /* Mangling already in progress.  */
740     abort ();
741
742   /* Mangled name are to be suffixed */
743   obstack_grow (mangle_obstack, "_Z", 2);
744
745   /* Register the compression table with the GC */
746   ggc_add_tree_root (&compression_table, 1);
747 }
748
749 /* Mangling finalization routine. The mangled name is returned as a
750    IDENTIFIER_NODE.  */
751
752 static tree
753 finish_mangling ()
754 {
755   tree result;
756
757   if (!compression_table)
758     /* Mangling already finished.  */
759     abort ();
760
761   ggc_del_root (&compression_table);
762   compression_table = NULL_TREE;
763   compression_next = 0;
764   obstack_1grow (mangle_obstack, '\0');
765   result = get_identifier (obstack_base (mangle_obstack));
766   obstack_free (mangle_obstack, obstack_base (mangle_obstack));
767 #if 0
768   printf ("// %s\n", IDENTIFIER_POINTER (result));
769 #endif
770   return result;
771 }