OSDN Git Service

2011-01-13 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / godump.c
1 /* Output Go language descriptions of types.
2    Copyright (C) 2008, 2009, 2010, 2011 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           default:
391             snprintf (buf, sizeof buf, "INVALID-float-%u",
392                       TYPE_PRECISION (type));
393             s = buf;
394             ret = false;
395             break;
396           }
397         obstack_grow (ob, s, strlen (s));
398       }
399       break;
400
401     case BOOLEAN_TYPE:
402       obstack_grow (ob, "bool", 4);
403       break;
404
405     case POINTER_TYPE:
406       if (use_type_name
407           && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
408           && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
409               || (POINTER_TYPE_P (TREE_TYPE (type))
410                   && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
411                       == FUNCTION_TYPE))))
412         {
413           tree name;
414
415           name = TYPE_NAME (TREE_TYPE (type));
416           if (TREE_CODE (name) == IDENTIFIER_NODE)
417             {
418               obstack_grow (ob, "*_", 2);
419               go_append_string (ob, name);
420
421               /* The pointer here can be used without the struct or
422                  union definition.  So this struct or union is a a
423                  potential dummy type.  */
424               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
425                 pointer_set_insert (container->pot_dummy_types,
426                                     IDENTIFIER_POINTER (name));
427
428               return ret;
429             }
430           else if (TREE_CODE (name) == TYPE_DECL)
431             {
432               obstack_grow (ob, "*_", 2);
433               go_append_string (ob, DECL_NAME (name));
434               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
435                 pointer_set_insert (container->pot_dummy_types,
436                                     IDENTIFIER_POINTER (DECL_NAME (name)));
437               return ret;
438             }
439         }
440       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
441         obstack_grow (ob, "func", 4);
442       else
443         obstack_1grow (ob, '*');
444       if (VOID_TYPE_P (TREE_TYPE (type)))
445         obstack_grow (ob, "byte", 4);
446       else
447         {
448           if (!go_format_type (container, TREE_TYPE (type), use_type_name,
449                                true))
450             ret = false;
451         }
452       break;
453
454     case ARRAY_TYPE:
455       obstack_1grow (ob, '[');
456       if (TYPE_DOMAIN (type) != NULL_TREE
457           && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
458           && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
459           && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
460           && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
461           && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
462           && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
463           && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
464         {
465           char buf[100];
466
467           snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
468                     tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
469           obstack_grow (ob, buf, strlen (buf));
470         }
471       obstack_1grow (ob, ']');
472       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
473         ret = false;
474       break;
475
476     case UNION_TYPE:
477     case RECORD_TYPE:
478       {
479         tree field;
480         int i;
481
482         obstack_grow (ob, "struct { ", 9);
483         i = 0;
484         for (field = TYPE_FIELDS (type);
485              field != NULL_TREE;
486              field = TREE_CHAIN (field))
487           {
488             if (DECL_NAME (field) == NULL)
489               {
490                 char buf[100];
491
492                 obstack_grow (ob, "_f", 2);
493                 snprintf (buf, sizeof buf, "%d", i);
494                 obstack_grow (ob, buf, strlen (buf));
495                 i++;
496               }
497             else
498               {
499                 const char *var_name;
500                 void **slot;
501
502                 /* Start variable name with an underscore if a keyword.  */
503                 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
504                 slot = htab_find_slot (container->keyword_hash, var_name,
505                                        NO_INSERT);
506                 if (slot != NULL)
507                   obstack_1grow (ob, '_');
508                 go_append_string (ob, DECL_NAME (field));
509               }
510             obstack_1grow (ob, ' ');
511             if (DECL_BIT_FIELD (field))
512               {
513                 obstack_grow (ob, "INVALID-bit-field", 17);
514                 ret = false;
515               }
516             else
517               {
518                 /* Do not expand type if a record or union type or a
519                    function pointer.  */
520                 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
521                     && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
522                         || (POINTER_TYPE_P (TREE_TYPE (field))
523                             && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
524                                 == FUNCTION_TYPE))))
525                   {
526                     tree name = TYPE_NAME (TREE_TYPE (field));
527                     if (TREE_CODE (name) == IDENTIFIER_NODE)
528                       {
529                         obstack_1grow (ob, '_');
530                         go_append_string (ob, name);
531                       }
532                     else if (TREE_CODE (name) == TYPE_DECL)
533                       {
534                         obstack_1grow (ob, '_');
535                         go_append_string (ob, DECL_NAME (name));
536                       }
537                   }
538                 else
539                   {
540                     if (!go_format_type (container, TREE_TYPE (field), true,
541                                          false))
542                       ret = false;
543                   }
544               }
545             obstack_grow (ob, "; ", 2);
546
547             /* Only output the first field of a union, and hope for
548                the best.  */
549             if (TREE_CODE (type) == UNION_TYPE)
550               break;
551           }
552         obstack_1grow (ob, '}');
553       }
554       break;
555
556     case FUNCTION_TYPE:
557       {
558         tree args;
559         bool is_varargs;
560         tree result;
561
562         /* Go has no way to write a type which is a function but not a
563            pointer to a function.  */
564         if (!is_func_ok)
565           {
566             obstack_grow (ob, "func*", 5);
567             ret = false;
568           }
569
570         obstack_1grow (ob, '(');
571         is_varargs = true;
572         for (args = TYPE_ARG_TYPES (type);
573              args != NULL_TREE;
574              args = TREE_CHAIN (args))
575           {
576             if (VOID_TYPE_P (TREE_VALUE (args)))
577               {
578                 gcc_assert (TREE_CHAIN (args) == NULL);
579                 is_varargs = false;
580                 break;
581               }
582             if (args != TYPE_ARG_TYPES (type))
583               obstack_grow (ob, ", ", 2);
584             if (!go_format_type (container, TREE_VALUE (args), true, false))
585               ret = false;
586           }
587         if (is_varargs)
588           {
589             if (TYPE_ARG_TYPES (type) != NULL_TREE)
590               obstack_grow (ob, ", ", 2);
591             obstack_grow (ob, "...interface{}", 14);
592           }
593         obstack_1grow (ob, ')');
594
595         result = TREE_TYPE (type);
596         if (!VOID_TYPE_P (result))
597           {
598             obstack_1grow (ob, ' ');
599             if (!go_format_type (container, result, use_type_name, false))
600               ret = false;
601           }
602       }
603       break;
604
605     default:
606       obstack_grow (ob, "INVALID-type", 12);
607       ret = false;
608       break;
609     }
610
611   return ret;
612 }
613
614 /* Output the type which was built on the type obstack, and then free
615    it.  */
616
617 static void
618 go_output_type (struct godump_container *container)
619 {
620   struct obstack *ob;
621
622   ob = &container->type_obstack;
623   obstack_1grow (ob, '\0');
624   fputs (obstack_base (ob), go_dump_file);
625   obstack_free (ob, obstack_base (ob));
626 }
627
628 /* Output a function declaration.  */
629
630 static void
631 go_output_fndecl (struct godump_container *container, tree decl)
632 {
633   if (!go_format_type (container, TREE_TYPE (decl), false, true))
634     fprintf (go_dump_file, "// ");
635   fprintf (go_dump_file, "func _%s ",
636            IDENTIFIER_POINTER (DECL_NAME (decl)));
637   go_output_type (container);
638   fprintf (go_dump_file, " __asm__(\"%s\")\n",
639            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
640 }
641
642 /* Output a typedef or something like a struct definition.  */
643
644 static void
645 go_output_typedef (struct godump_container *container, tree decl)
646 {
647   /* If we have an enum type, output the enum constants
648      separately.  */
649   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
650       && TYPE_SIZE (TREE_TYPE (decl)) != 0
651       && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
652       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
653           || !pointer_set_contains (container->decls_seen,
654                                     TYPE_CANONICAL (TREE_TYPE (decl)))))
655     {
656       tree element;
657
658       for (element = TYPE_VALUES (TREE_TYPE (decl));
659            element != NULL_TREE;
660            element = TREE_CHAIN (element))
661         fprintf (go_dump_file, "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
662                  IDENTIFIER_POINTER (TREE_PURPOSE (element)),
663                  tree_low_cst (TREE_VALUE (element), 0));
664       pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
665       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
666         pointer_set_insert (container->decls_seen,
667                             TYPE_CANONICAL (TREE_TYPE (decl)));
668     }
669
670   if (DECL_NAME (decl) != NULL_TREE)
671     {
672       void **slot;
673       const char *type;
674
675       type = IDENTIFIER_POINTER (DECL_NAME (decl));
676       /* If type defined already, skip.  */
677       slot = htab_find_slot (container->type_hash, type, INSERT);
678       if (*slot != NULL)
679         return;
680       *slot = CONST_CAST (void *, (const void *) type);
681
682       if (!go_format_type (container, TREE_TYPE (decl), false, false))
683         fprintf (go_dump_file, "// ");
684       fprintf (go_dump_file, "type _%s ",
685                IDENTIFIER_POINTER (DECL_NAME (decl)));
686       go_output_type (container);
687       pointer_set_insert (container->decls_seen, decl);
688     }
689   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
690     {
691        void **slot;
692        const char *type;
693
694        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
695        /* If type defined already, skip.  */
696        slot = htab_find_slot (container->type_hash, type, INSERT);
697        if (*slot != NULL)
698          return;
699        *slot = CONST_CAST (void *, (const void *) type);
700
701        if (!go_format_type (container, TREE_TYPE (decl), false, false))
702          fprintf (go_dump_file, "// ");
703        fprintf (go_dump_file, "type _%s ",
704                IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
705        go_output_type (container);
706     }
707   else
708     return;
709
710   fprintf (go_dump_file, "\n");
711 }
712
713 /* Output a variable.  */
714
715 static void
716 go_output_var (struct godump_container *container, tree decl)
717 {
718   bool is_valid;
719
720   if (pointer_set_contains (container->decls_seen, decl)
721       || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
722     return;
723   pointer_set_insert (container->decls_seen, decl);
724   pointer_set_insert (container->decls_seen, DECL_NAME (decl));
725
726   is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
727   if (is_valid
728       && htab_find_slot (container->type_hash,
729                          IDENTIFIER_POINTER (DECL_NAME (decl)),
730                          NO_INSERT) != NULL)
731     {
732       /* There is already a type with this name, probably from a
733          struct tag.  Prefer the type to the variable.  */
734       is_valid = false;
735     }
736   if (!is_valid)
737     fprintf (go_dump_file, "// ");
738
739   fprintf (go_dump_file, "var _%s ",
740            IDENTIFIER_POINTER (DECL_NAME (decl)));
741   go_output_type (container);
742   fprintf (go_dump_file, "\n");
743
744   /* Sometimes an extern variable is declared with an unknown struct
745      type.  */
746   if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
747       && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
748     {
749       tree type_name = TYPE_NAME (TREE_TYPE (decl));
750       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
751         pointer_set_insert (container->pot_dummy_types,
752                             IDENTIFIER_POINTER (type_name));
753       else if (TREE_CODE (type_name) == TYPE_DECL)
754         pointer_set_insert (container->pot_dummy_types,
755                             IDENTIFIER_POINTER (DECL_NAME (type_name)));
756     }
757 }
758
759 /* Build a hash table with the Go keywords.  */
760
761 static const char * const keywords[] = {
762   "__asm__", "break", "case", "chan", "const", "continue", "default",
763   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
764   "import", "interface", "map", "package", "range", "return", "select",
765   "struct", "switch", "type", "var"
766 };
767
768 static void
769 keyword_hash_init (struct godump_container *container)
770 {
771   size_t i;
772   size_t count = sizeof (keywords) / sizeof (keywords[0]);
773   void **slot;
774
775   for (i = 0; i < count; i++)
776     {
777       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
778       *slot = CONST_CAST (void *, (const void *) keywords[i]);
779     }
780 }
781
782 /* Traversing the pot_dummy_types and seeing which types are present
783    in the global types hash table and creating dummy definitions if
784    not found.  This function is invoked by pointer_set_traverse.  */
785
786 static bool
787 find_dummy_types (const void *ptr, void *adata)
788 {
789   struct godump_container *data = (struct godump_container *) adata;
790   const char *type = (const char *) ptr;
791   void **slot;
792
793   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
794   if (slot == NULL)
795     fprintf (go_dump_file, "type _%s struct {}\n", type);
796   return true;
797 }
798
799 /* Output symbols.  */
800
801 static void
802 go_finish (const char *filename)
803 {
804   struct godump_container container;
805   unsigned int ix;
806   tree decl;
807
808   real_debug_hooks->finish (filename);
809
810   container.decls_seen = pointer_set_create ();
811   container.pot_dummy_types = pointer_set_create ();
812   container.type_hash = htab_create (100, htab_hash_string,
813                                      string_hash_eq, NULL);
814   container.keyword_hash = htab_create (50, htab_hash_string,
815                                         string_hash_eq, NULL);
816   obstack_init (&container.type_obstack);
817
818   keyword_hash_init (&container);
819
820   FOR_EACH_VEC_ELT (tree, queue, ix, decl)
821     {
822       switch (TREE_CODE (decl))
823         {
824         case FUNCTION_DECL:
825           go_output_fndecl (&container, decl);
826           break;
827
828         case TYPE_DECL:
829           go_output_typedef (&container, decl);
830           break;
831
832         case VAR_DECL:
833           go_output_var (&container, decl);
834           break;
835
836         default:
837           gcc_unreachable();
838         }
839     }
840
841   /* To emit dummy definitions.  */
842   pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
843                         (void *) &container);
844
845   pointer_set_destroy (container.decls_seen);
846   pointer_set_destroy (container.pot_dummy_types);
847   htab_delete (container.type_hash);
848   htab_delete (container.keyword_hash);
849   obstack_free (&container.type_obstack, NULL);
850
851   queue = NULL;
852
853   if (fclose (go_dump_file) != 0)
854     error ("could not close Go dump file: %m");
855   go_dump_file = NULL;
856 }
857
858 /* Set up our hooks.  */
859
860 const struct gcc_debug_hooks *
861 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
862 {
863   go_dump_file = fopen (filename, "w");
864   if (go_dump_file == NULL)
865     {
866       error ("could not open Go dump file %qs: %m", filename);
867       return hooks;
868     }
869
870   go_debug_hooks = *hooks;
871   real_debug_hooks = hooks;
872
873   go_debug_hooks.finish = go_finish;
874   go_debug_hooks.define = go_define;
875   go_debug_hooks.undef = go_undef;
876   go_debug_hooks.function_decl = go_function_decl;
877   go_debug_hooks.global_decl = go_global_decl;
878   go_debug_hooks.type_decl = go_type_decl;
879
880   macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
881
882   return &go_debug_hooks;
883 }
884
885 #include "gt-godump.h"