OSDN Git Service

2010-12-09 Yao Qi <yao@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / godump.c
1 /* Output Go language descriptions of types.
2    Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor <iant@google.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 /* This file is used during the build process to emit Go language
22    descriptions of declarations from C header files.  It uses the
23    debug info hooks to emit the descriptions.  The Go language
24    descriptions then become part of the Go runtime support
25    library.
26
27    All global names are output with a leading underscore, so that they
28    are all hidden in Go.  */
29
30 #include "config.h"
31 #include "system.h"
32 #include "coretypes.h"
33 #include "diagnostic-core.h"
34 #include "tree.h"
35 #include "ggc.h"
36 #include "pointer-set.h"
37 #include "obstack.h"
38 #include "debug.h"
39
40 /* We dump this information from the debug hooks.  This gives us a
41    stable and maintainable API to hook into.  In order to work
42    correctly when -g is used, we build our own hooks structure which
43    wraps the hooks we need to change.  */
44
45 /* Our debug hooks.  This is initialized by dump_go_spec_init.  */
46
47 static struct gcc_debug_hooks go_debug_hooks;
48
49 /* The real debug hooks.  */
50
51 static const struct gcc_debug_hooks *real_debug_hooks;
52
53 /* The file where we should write information.  */
54
55 static FILE *go_dump_file;
56
57 /* A queue of decls to output.  */
58
59 static GTY(()) VEC(tree,gc) *queue;
60
61 /* A hash table of macros we have seen.  */
62
63 static htab_t macro_hash;
64
65 /* For the hash tables.  */
66
67 static int
68 string_hash_eq (const void *y1, const void *y2)
69 {
70   return strcmp ((const char *) y1, (const char *) y2) == 0;
71 }
72
73 /* A macro definition.  */
74
75 static void
76 go_define (unsigned int lineno, const char *buffer)
77 {
78   const char *p;
79   const char *name_end;
80   char *out_buffer;
81   char *q;
82   char *copy;
83   hashval_t hashval;
84   void **slot;
85
86   real_debug_hooks->define (lineno, buffer);
87
88   /* Skip macro functions.  */
89   for (p = buffer; *p != '\0' && *p != ' '; ++p)
90     if (*p == '(')
91       return;
92
93   if (*p == '\0')
94     return;
95
96   name_end = p;
97
98   ++p;
99   if (*p == '\0')
100     return;
101
102   copy = XNEWVEC (char, name_end - buffer + 1);
103   memcpy (copy, buffer, name_end - buffer);
104   copy[name_end - buffer] = '\0';
105
106   hashval = htab_hash_string (copy);
107   slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
108   if (slot != NULL)
109     {
110       XDELETEVEC (copy);
111       return;
112     }
113
114   /* For simplicity, we force all names to be hidden by adding an
115      initial underscore, and let the user undo this as needed.  */
116   out_buffer = XNEWVEC (char, strlen (p) * 2 + 1);
117   q = out_buffer;
118   while (*p != '\0')
119     {
120       if (ISALPHA (*p) || *p == '_')
121         {
122           const char *start;
123           char *n;
124
125           start = p;
126           while (ISALNUM (*p) || *p == '_')
127             ++p;
128           n = XALLOCAVEC (char, p - start + 1);
129           memcpy (n, start, p - start);
130           n[p - start] = '\0';
131           slot = htab_find_slot (macro_hash, n, NO_INSERT);
132           if (slot == NULL || *slot == NULL)
133             {
134               /* This is a reference to a name which was not defined
135                  as a macro.  */
136               fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
137               return;
138             }
139
140           *q++ = '_';
141           memcpy (q, start, p - start);
142           q += p - start;
143         }
144       else if (ISDIGIT (*p)
145                || (*p == '.' && ISDIGIT (p[1])))
146         {
147           const char *start;
148           bool is_hex;
149
150           start = p;
151           is_hex = false;
152           if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
153             {
154               p += 2;
155               is_hex = true;
156             }
157           while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
158                  || (is_hex
159                      && ((*p >= 'a' && *p <= 'f')
160                          || (*p >= 'A' && *p <= 'F'))))
161             ++p;
162           memcpy (q, start, p - start);
163           q += p - start;
164           while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
165                  || *p == 'f' || *p == 'F'
166                  || *p == 'd' || *p == 'D')
167             {
168               /* Go doesn't use any of these trailing type
169                  modifiers.  */
170               ++p;
171             }
172         }
173       else if (ISSPACE (*p)
174                || *p == '+' || *p == '-'
175                || *p == '*' || *p == '/' || *p == '%'
176                || *p == '|' || *p == '&'
177                || *p == '>' || *p == '<'
178                || *p == '!'
179                || *p == '(' || *p == ')'
180                || *p == '"' || *p == '\'')
181         *q++ = *p++;
182       else
183         {
184           /* Something we don't recognize.  */
185           fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
186           return;
187         }
188     }
189   *q = '\0';
190
191   slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
192   *slot = copy;
193
194   fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
195
196   XDELETEVEC (out_buffer);
197 }
198
199 /* A macro undef.  */
200
201 static void
202 go_undef (unsigned int lineno, const char *buffer)
203 {
204   void **slot;
205
206   real_debug_hooks->undef (lineno, buffer);
207
208   slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
209   if (slot == NULL)
210     return;
211   fprintf (go_dump_file, "// undef _%s\n", buffer);
212   /* We don't delete the slot from the hash table because that will
213      cause a duplicate const definition.  */
214 }
215
216 /* A function or variable decl.  */
217
218 static void
219 go_decl (tree decl)
220 {
221   if (!TREE_PUBLIC (decl)
222       || DECL_IS_BUILTIN (decl)
223       || DECL_NAME (decl) == NULL_TREE)
224     return;
225   VEC_safe_push (tree, gc, queue, decl);
226 }
227
228 /* A function decl.  */
229
230 static void
231 go_function_decl (tree decl)
232 {
233   real_debug_hooks->function_decl (decl);
234   go_decl (decl);
235 }
236
237 /* A global variable decl.  */
238
239 static void
240 go_global_decl (tree decl)
241 {
242   real_debug_hooks->global_decl (decl);
243   go_decl (decl);
244 }
245
246 /* A type declaration.  */
247
248 static void
249 go_type_decl (tree decl, int local)
250 {
251   real_debug_hooks->type_decl (decl, local);
252
253   if (local || DECL_IS_BUILTIN (decl))
254     return;
255   if (DECL_NAME (decl) == NULL_TREE
256       && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
257           || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
258       && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
259     return;
260   VEC_safe_push (tree, gc, queue, decl);
261 }
262
263 /* A container for the data we pass around when generating information
264    at the end of the compilation.  */
265
266 struct godump_container
267 {
268   /* DECLs that we have already seen.  */
269   struct pointer_set_t *decls_seen;
270
271   /* Types which may potentially have to be defined as dummy
272      types.  */
273   struct pointer_set_t *pot_dummy_types;
274
275   /* Go keywords.  */
276   htab_t keyword_hash;
277
278   /* Global type definitions.  */
279   htab_t type_hash;
280
281   /* Obstack used to write out a type definition.  */
282   struct obstack type_obstack;
283 };
284
285 /* Append an IDENTIFIER_NODE to OB.  */
286
287 static void
288 go_append_string (struct obstack *ob, tree id)
289 {
290   obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
291 }
292
293 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
294    USE_TYPE_NAME is true if we can simply use a type name here without
295    needing to define it.  IS_FUNC_OK is true if we can output a func
296    type here; the "func" keyword will already have been added.  Return
297    true if the type can be represented in Go, false otherwise.  */
298
299 static bool
300 go_format_type (struct godump_container *container, tree type,
301                 bool use_type_name, bool is_func_ok)
302 {
303   bool ret;
304   struct obstack *ob;
305
306   ret = true;
307   ob = &container->type_obstack;
308
309   if (TYPE_NAME (type) != NULL_TREE
310       && (pointer_set_contains (container->decls_seen, type)
311           || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
312       && (AGGREGATE_TYPE_P (type)
313           || POINTER_TYPE_P (type)
314           || TREE_CODE (type) == FUNCTION_TYPE))
315     {
316       tree name;
317
318       name = TYPE_NAME (type);
319       if (TREE_CODE (name) == IDENTIFIER_NODE)
320         {
321           obstack_1grow (ob, '_');
322           go_append_string (ob, name);
323           return ret;
324         }
325       else if (TREE_CODE (name) == TYPE_DECL)
326         {
327           obstack_1grow (ob, '_');
328           go_append_string (ob, DECL_NAME (name));
329           return ret;
330         }
331     }
332
333   pointer_set_insert (container->decls_seen, type);
334
335   switch (TREE_CODE (type))
336     {
337     case ENUMERAL_TYPE:
338       obstack_grow (ob, "int", 3);
339       break;
340
341     case TYPE_DECL:
342       obstack_1grow (ob, '_');
343       go_append_string (ob, DECL_NAME (type));
344       break;
345
346     case INTEGER_TYPE:
347       {
348         const char *s;
349         char buf[100];
350
351         switch (TYPE_PRECISION (type))
352           {
353           case 8:
354             s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
355             break;
356           case 16:
357             s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
358             break;
359           case 32:
360             s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
361             break;
362           case 64:
363             s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
364             break;
365           default:
366             snprintf (buf, sizeof buf, "INVALID-int-%u%s",
367                       TYPE_PRECISION (type),
368                       TYPE_UNSIGNED (type) ? "u" : "");
369             s = buf;
370             ret = false;
371             break;
372           }
373         obstack_grow (ob, s, strlen (s));
374       }
375       break;
376
377     case REAL_TYPE:
378       {
379         const char *s;
380         char buf[100];
381
382         switch (TYPE_PRECISION (type))
383           {
384           case 32:
385             s = "float32";
386             break;
387           case 64:
388             s = "float64";
389             break;
390           case 80:
391             s = "float80";
392             break;
393           default:
394             snprintf (buf, sizeof buf, "INVALID-float-%u",
395                       TYPE_PRECISION (type));
396             s = buf;
397             ret = false;
398             break;
399           }
400         obstack_grow (ob, s, strlen (s));
401       }
402       break;
403
404     case BOOLEAN_TYPE:
405       obstack_grow (ob, "bool", 4);
406       break;
407
408     case POINTER_TYPE:
409       if (use_type_name
410           && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
411           && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
412               || (POINTER_TYPE_P (TREE_TYPE (type))
413                   && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
414                       == FUNCTION_TYPE))))
415         {
416           tree name;
417
418           name = TYPE_NAME (TREE_TYPE (type));
419           if (TREE_CODE (name) == IDENTIFIER_NODE)
420             {
421               obstack_grow (ob, "*_", 2);
422               go_append_string (ob, name);
423
424               /* The pointer here can be used without the struct or
425                  union definition.  So this struct or union is a a
426                  potential dummy type.  */
427               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
428                 pointer_set_insert (container->pot_dummy_types,
429                                     IDENTIFIER_POINTER (name));
430
431               return ret;
432             }
433           else if (TREE_CODE (name) == TYPE_DECL)
434             {
435               obstack_grow (ob, "*_", 2);
436               go_append_string (ob, DECL_NAME (name));
437               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
438                 pointer_set_insert (container->pot_dummy_types,
439                                     IDENTIFIER_POINTER (DECL_NAME (name)));
440               return ret;
441             }
442         }
443       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
444         obstack_grow (ob, "func", 4);
445       else
446         obstack_1grow (ob, '*');
447       if (VOID_TYPE_P (TREE_TYPE (type)))
448         obstack_grow (ob, "byte", 4);
449       else
450         {
451           if (!go_format_type (container, TREE_TYPE (type), use_type_name,
452                                true))
453             ret = false;
454         }
455       break;
456
457     case ARRAY_TYPE:
458       obstack_1grow (ob, '[');
459       if (TYPE_DOMAIN (type) != NULL_TREE
460           && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
461           && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
462           && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
463           && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
464           && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
465           && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
466           && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
467         {
468           char buf[100];
469
470           snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
471                     tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
472           obstack_grow (ob, buf, strlen (buf));
473         }
474       obstack_1grow (ob, ']');
475       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
476         ret = false;
477       break;
478
479     case UNION_TYPE:
480     case RECORD_TYPE:
481       {
482         tree field;
483         int i;
484
485         obstack_grow (ob, "struct { ", 9);
486         i = 0;
487         for (field = TYPE_FIELDS (type);
488              field != NULL_TREE;
489              field = TREE_CHAIN (field))
490           {
491             if (DECL_NAME (field) == NULL)
492               {
493                 char buf[100];
494
495                 obstack_grow (ob, "_f", 2);
496                 snprintf (buf, sizeof buf, "%d", i);
497                 obstack_grow (ob, buf, strlen (buf));
498                 i++;
499               }
500             else
501               {
502                 const char *var_name;
503                 void **slot;
504
505                 /* Start variable name with an underscore if a keyword.  */
506                 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
507                 slot = htab_find_slot (container->keyword_hash, var_name,
508                                        NO_INSERT);
509                 if (slot != NULL)
510                   obstack_1grow (ob, '_');
511                 go_append_string (ob, DECL_NAME (field));
512               }
513             obstack_1grow (ob, ' ');
514             if (DECL_BIT_FIELD (field))
515               {
516                 obstack_grow (ob, "INVALID-bit-field", 17);
517                 ret = false;
518               }
519             else
520               {
521                 /* Do not expand type if a record or union type or a
522                    function pointer.  */
523                 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
524                     && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
525                         || (POINTER_TYPE_P (TREE_TYPE (field))
526                             && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
527                                 == FUNCTION_TYPE))))
528                   {
529                     tree name = TYPE_NAME (TREE_TYPE (field));
530                     if (TREE_CODE (name) == IDENTIFIER_NODE)
531                       {
532                         obstack_1grow (ob, '_');
533                         go_append_string (ob, name);
534                       }
535                     else if (TREE_CODE (name) == TYPE_DECL)
536                       {
537                         obstack_1grow (ob, '_');
538                         go_append_string (ob, DECL_NAME (name));
539                       }
540                   }
541                 else
542                   {
543                     if (!go_format_type (container, TREE_TYPE (field), true,
544                                          false))
545                       ret = false;
546                   }
547               }
548             obstack_grow (ob, "; ", 2);
549
550             /* Only output the first field of a union, and hope for
551                the best.  */
552             if (TREE_CODE (type) == UNION_TYPE)
553               break;
554           }
555         obstack_1grow (ob, '}');
556       }
557       break;
558
559     case FUNCTION_TYPE:
560       {
561         tree args;
562         bool is_varargs;
563         tree result;
564
565         /* Go has no way to write a type which is a function but not a
566            pointer to a function.  */
567         if (!is_func_ok)
568           {
569             obstack_grow (ob, "func*", 5);
570             ret = false;
571           }
572
573         obstack_1grow (ob, '(');
574         is_varargs = true;
575         for (args = TYPE_ARG_TYPES (type);
576              args != NULL_TREE;
577              args = TREE_CHAIN (args))
578           {
579             if (VOID_TYPE_P (TREE_VALUE (args)))
580               {
581                 gcc_assert (TREE_CHAIN (args) == NULL);
582                 is_varargs = false;
583                 break;
584               }
585             if (args != TYPE_ARG_TYPES (type))
586               obstack_grow (ob, ", ", 2);
587             if (!go_format_type (container, TREE_VALUE (args), true, false))
588               ret = false;
589           }
590         if (is_varargs)
591           {
592             if (TYPE_ARG_TYPES (type) != NULL_TREE)
593               obstack_grow (ob, ", ", 2);
594             obstack_grow (ob, "...interface{}", 14);
595           }
596         obstack_1grow (ob, ')');
597
598         result = TREE_TYPE (type);
599         if (!VOID_TYPE_P (result))
600           {
601             obstack_1grow (ob, ' ');
602             if (!go_format_type (container, result, use_type_name, false))
603               ret = false;
604           }
605       }
606       break;
607
608     default:
609       obstack_grow (ob, "INVALID-type", 12);
610       ret = false;
611       break;
612     }
613
614   return ret;
615 }
616
617 /* Output the type which was built on the type obstack, and then free
618    it.  */
619
620 static void
621 go_output_type (struct godump_container *container)
622 {
623   struct obstack *ob;
624
625   ob = &container->type_obstack;
626   obstack_1grow (ob, '\0');
627   fputs (obstack_base (ob), go_dump_file);
628   obstack_free (ob, obstack_base (ob));
629 }
630
631 /* Output a function declaration.  */
632
633 static void
634 go_output_fndecl (struct godump_container *container, tree decl)
635 {
636   if (!go_format_type (container, TREE_TYPE (decl), false, true))
637     fprintf (go_dump_file, "// ");
638   fprintf (go_dump_file, "func _%s ",
639            IDENTIFIER_POINTER (DECL_NAME (decl)));
640   go_output_type (container);
641   fprintf (go_dump_file, " __asm__(\"%s\")\n",
642            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
643 }
644
645 /* Output a typedef or something like a struct definition.  */
646
647 static void
648 go_output_typedef (struct godump_container *container, tree decl)
649 {
650   /* If we have an enum type, output the enum constants
651      separately.  */
652   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
653       && TYPE_SIZE (TREE_TYPE (decl)) != 0
654       && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
655       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
656           || !pointer_set_contains (container->decls_seen,
657                                     TYPE_CANONICAL (TREE_TYPE (decl)))))
658     {
659       tree element;
660
661       for (element = TYPE_VALUES (TREE_TYPE (decl));
662            element != NULL_TREE;
663            element = TREE_CHAIN (element))
664         fprintf (go_dump_file, "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
665                  IDENTIFIER_POINTER (TREE_PURPOSE (element)),
666                  tree_low_cst (TREE_VALUE (element), 0));
667       pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
668       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
669         pointer_set_insert (container->decls_seen,
670                             TYPE_CANONICAL (TREE_TYPE (decl)));
671     }
672
673   if (DECL_NAME (decl) != NULL_TREE)
674     {
675       void **slot;
676       const char *type;
677
678       type = IDENTIFIER_POINTER (DECL_NAME (decl));
679       /* If type defined already, skip.  */
680       slot = htab_find_slot (container->type_hash, type, INSERT);
681       if (*slot != NULL)
682         return;
683       *slot = CONST_CAST (void *, (const void *) type);
684
685       if (!go_format_type (container, TREE_TYPE (decl), false, false))
686         fprintf (go_dump_file, "// ");
687       fprintf (go_dump_file, "type _%s ",
688                IDENTIFIER_POINTER (DECL_NAME (decl)));
689       go_output_type (container);
690       pointer_set_insert (container->decls_seen, decl);
691     }
692   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
693     {
694        void **slot;
695        const char *type;
696
697        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
698        /* If type defined already, skip.  */
699        slot = htab_find_slot (container->type_hash, type, INSERT);
700        if (*slot != NULL)
701          return;
702        *slot = CONST_CAST (void *, (const void *) type);
703
704        if (!go_format_type (container, TREE_TYPE (decl), false, false))
705          fprintf (go_dump_file, "// ");
706        fprintf (go_dump_file, "type _%s ",
707                IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
708        go_output_type (container);
709     }
710   else
711     return;
712
713   fprintf (go_dump_file, "\n");
714 }
715
716 /* Output a variable.  */
717
718 static void
719 go_output_var (struct godump_container *container, tree decl)
720 {
721   if (pointer_set_contains (container->decls_seen, decl)
722       || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
723     return;
724   pointer_set_insert (container->decls_seen, decl);
725   pointer_set_insert (container->decls_seen, DECL_NAME (decl));
726   if (!go_format_type (container, TREE_TYPE (decl), true, false))
727     fprintf (go_dump_file, "// ");
728   fprintf (go_dump_file, "var _%s ",
729            IDENTIFIER_POINTER (DECL_NAME (decl)));
730   go_output_type (container);
731   fprintf (go_dump_file, "\n");
732
733   /* Sometimes an extern variable is declared with an unknown struct
734      type.  */
735   if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
736       && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
737     {
738       tree type_name = TYPE_NAME (TREE_TYPE (decl));
739       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
740         pointer_set_insert (container->pot_dummy_types,
741                             IDENTIFIER_POINTER (type_name));
742       else if (TREE_CODE (type_name) == TYPE_DECL)
743         pointer_set_insert (container->pot_dummy_types,
744                             IDENTIFIER_POINTER (DECL_NAME (type_name)));
745     }
746 }
747
748 /* Build a hash table with the Go keywords.  */
749
750 static const char * const keywords[] = {
751   "__asm__", "break", "case", "chan", "const", "continue", "default",
752   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
753   "import", "interface", "map", "package", "range", "return", "select",
754   "struct", "switch", "type", "var"
755 };
756
757 static void
758 keyword_hash_init (struct godump_container *container)
759 {
760   size_t i;
761   size_t count = sizeof (keywords) / sizeof (keywords[0]);
762   void **slot;
763
764   for (i = 0; i < count; i++)
765     {
766       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
767       *slot = CONST_CAST (void *, (const void *) keywords[i]);
768     }
769 }
770
771 /* Traversing the pot_dummy_types and seeing which types are present
772    in the global types hash table and creating dummy definitions if
773    not found.  This function is invoked by pointer_set_traverse.  */
774
775 static bool
776 find_dummy_types (const void *ptr, void *adata)
777 {
778   struct godump_container *data = (struct godump_container *) adata;
779   const char *type = (const char *) ptr;
780   void **slot;
781
782   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
783   if (slot == NULL)
784     fprintf (go_dump_file, "type _%s struct {}\n", type);
785   return true;
786 }
787
788 /* Output symbols.  */
789
790 static void
791 go_finish (const char *filename)
792 {
793   struct godump_container container;
794   unsigned int ix;
795   tree decl;
796
797   real_debug_hooks->finish (filename);
798
799   container.decls_seen = pointer_set_create ();
800   container.pot_dummy_types = pointer_set_create ();
801   container.type_hash = htab_create (100, htab_hash_string,
802                                      string_hash_eq, NULL);
803   container.keyword_hash = htab_create (50, htab_hash_string,
804                                         string_hash_eq, NULL);
805   obstack_init (&container.type_obstack);
806
807   keyword_hash_init (&container);
808
809   FOR_EACH_VEC_ELT (tree, queue, ix, decl)
810     {
811       switch (TREE_CODE (decl))
812         {
813         case FUNCTION_DECL:
814           go_output_fndecl (&container, decl);
815           break;
816
817         case TYPE_DECL:
818           go_output_typedef (&container, decl);
819           break;
820
821         case VAR_DECL:
822           go_output_var (&container, decl);
823           break;
824
825         default:
826           gcc_unreachable();
827         }
828     }
829
830   /* To emit dummy definitions.  */
831   pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
832                         (void *) &container);
833
834   pointer_set_destroy (container.decls_seen);
835   pointer_set_destroy (container.pot_dummy_types);
836   htab_delete (container.type_hash);
837   htab_delete (container.keyword_hash);
838   obstack_free (&container.type_obstack, NULL);
839
840   queue = NULL;
841
842   if (fclose (go_dump_file) != 0)
843     error ("could not close Go dump file: %m");
844   go_dump_file = NULL;
845 }
846
847 /* Set up our hooks.  */
848
849 const struct gcc_debug_hooks *
850 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
851 {
852   go_dump_file = fopen (filename, "w");
853   if (go_dump_file == NULL)
854     {
855       error ("could not open Go dump file %qs: %m", filename);
856       return hooks;
857     }
858
859   go_debug_hooks = *hooks;
860   real_debug_hooks = hooks;
861
862   go_debug_hooks.finish = go_finish;
863   go_debug_hooks.define = go_define;
864   go_debug_hooks.undef = go_undef;
865   go_debug_hooks.function_decl = go_function_decl;
866   go_debug_hooks.global_decl = go_global_decl;
867   go_debug_hooks.type_decl = go_type_decl;
868
869   macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
870
871   return &go_debug_hooks;
872 }
873
874 #include "gt-godump.h"