OSDN Git Service

* godump.c (struct godump_container): Add invalid_hash field.
[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   bool saw_operand;
83   bool need_operand;
84   char *copy;
85   hashval_t hashval;
86   void **slot;
87
88   real_debug_hooks->define (lineno, buffer);
89
90   /* Skip macro functions.  */
91   for (p = buffer; *p != '\0' && *p != ' '; ++p)
92     if (*p == '(')
93       return;
94
95   if (*p == '\0')
96     return;
97
98   name_end = p;
99
100   ++p;
101   if (*p == '\0')
102     return;
103
104   copy = XNEWVEC (char, name_end - buffer + 1);
105   memcpy (copy, buffer, name_end - buffer);
106   copy[name_end - buffer] = '\0';
107
108   hashval = htab_hash_string (copy);
109   slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
110   if (slot != NULL)
111     {
112       XDELETEVEC (copy);
113       return;
114     }
115
116   /* For simplicity, we force all names to be hidden by adding an
117      initial underscore, and let the user undo this as needed.  */
118   out_buffer = XNEWVEC (char, strlen (p) * 2 + 1);
119   q = out_buffer;
120   saw_operand = false;
121   need_operand = false;
122   while (*p != '\0')
123     {
124       switch (*p)
125         {
126         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
127         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
128         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
129         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
130         case 'Y': case 'Z':
131         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
132         case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
133         case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
134         case 's': case 't': case 'u': case 'v': case 'w': case 'x':
135         case 'y': case 'z':
136         case '_':
137           {
138             /* The start of an identifier.  Technically we should also
139                worry about UTF-8 identifiers, but they are not a
140                problem for practical uses of -fdump-go-spec so we
141                don't worry about them.  */
142             const char *start;
143             char *n;
144
145             if (saw_operand)
146               goto unknown;
147
148             start = p;
149             while (ISALNUM (*p) || *p == '_')
150               ++p;
151             n = XALLOCAVEC (char, p - start + 1);
152             memcpy (n, start, p - start);
153             n[p - start] = '\0';
154             slot = htab_find_slot (macro_hash, n, NO_INSERT);
155             if (slot == NULL || *slot == NULL)
156               {
157                 /* This is a reference to a name which was not defined
158                    as a macro.  */
159                 goto unknown;
160               }
161
162             *q++ = '_';
163             memcpy (q, start, p - start);
164             q += p - start;
165
166             saw_operand = true;
167             need_operand = false;
168           }
169           break;
170
171         case '.':
172           if (!ISDIGIT (p[1]))
173             goto unknown;
174           /* Fall through.  */
175         case '0': case '1': case '2': case '3': case '4':
176         case '5': case '6': case '7': case '8': case '9':
177           {
178             const char *start;
179             bool is_hex;
180
181             start = p;
182             is_hex = false;
183             if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
184               {
185                 p += 2;
186                 is_hex = true;
187               }
188             while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
189                    || (is_hex
190                        && ((*p >= 'a' && *p <= 'f')
191                            || (*p >= 'A' && *p <= 'F'))))
192               ++p;
193             memcpy (q, start, p - start);
194             q += p - start;
195             while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
196                    || *p == 'f' || *p == 'F'
197                    || *p == 'd' || *p == 'D')
198               {
199                 /* Go doesn't use any of these trailing type
200                    modifiers.  */
201                 ++p;
202               }
203
204             /* We'll pick up the exponent, if any, as an
205                expression.  */
206
207             saw_operand = true;
208             need_operand = false;
209           }
210           break;
211
212         case ' ': case '\t':
213           *q++ = *p++;
214           break;
215
216         case '(':
217           /* Always OK, not part of an operand, presumed to start an
218              operand.  */
219           *q++ = *p++;
220           saw_operand = false;
221           need_operand = false;
222           break;
223
224         case ')':
225           /* OK if we don't need an operand, and presumed to indicate
226              an operand.  */
227           if (need_operand)
228             goto unknown;
229           *q++ = *p++;
230           saw_operand = true;
231           break;
232
233         case '+': case '-':
234           /* Always OK, but not part of an operand.  */
235           *q++ = *p++;
236           saw_operand = false;
237           break;
238
239         case '*': case '/': case '%': case '|': case '&': case '^':
240           /* Must be a binary operator.  */
241           if (!saw_operand)
242             goto unknown;
243           *q++ = *p++;
244           saw_operand = false;
245           need_operand = true;
246           break;
247
248         case '=':
249           *q++ = *p++;
250           if (*p != '=')
251             goto unknown;
252           /* Must be a binary operator.  */
253           if (!saw_operand)
254             goto unknown;
255           *q++ = *p++;
256           saw_operand = false;
257           need_operand = true;
258           break;
259
260         case '!':
261           *q++ = *p++;
262           if (*p == '=')
263             {
264               /* Must be a binary operator.  */
265               if (!saw_operand)
266                 goto unknown;
267               *q++ = *p++;
268               saw_operand = false;
269               need_operand = true;
270             }
271           else
272             {
273               /* Must be a unary operator.  */
274               if (saw_operand)
275                 goto unknown;
276               need_operand = true;
277             }
278           break;
279
280         case '<': case '>':
281           /* Must be a binary operand, may be << or >> or <= or >=.  */
282           if (!saw_operand)
283             goto unknown;
284           *q++ = *p++;
285           if (*p == *(p - 1) || *p == '=')
286             *q++ = *p++;
287           saw_operand = false;
288           need_operand = true;
289           break;
290
291         case '~':
292           /* Must be a unary operand, must be translated for Go.  */
293           if (saw_operand)
294             goto unknown;
295           *q++ = '^';
296           p++;
297           need_operand = true;
298           break;
299
300         case '"':
301         case '\'':
302           {
303             char quote = *p;
304             *q++ = *p++;
305             while (*p != quote)
306               {
307                 int c;
308
309                 if (*p == '\0')
310                   goto unknown;
311
312                 if (*p != '\\')
313                   {
314                     *q++ = *p++;
315                     continue;
316                   }
317
318                 *q++ = *p++;
319                 switch (*p)
320                   {
321                   case '0': case '1': case '2': case '3':
322                   case '4': case '5': case '6': case '7':
323                     c = 0;
324                     while (*p >= '0' && *p <= '7')
325                       {
326                         *q++ = *p++;
327                         ++c;
328                       }
329                     /* Go octal characters are always 3
330                        digits.  */
331                     if (c != 3)
332                       goto unknown;
333                     break;
334
335                   case 'x':
336                     *q++ = *p++;
337                     c = 0;
338                     while (ISXDIGIT (*p))
339                       {
340                         *q++ = *p++;
341                         ++c;
342                       }
343                     /* Go hex characters are always 2 digits.  */
344                     if (c != 2)
345                       goto unknown;
346                     break;
347
348                   case 'a': case 'b': case 'f': case 'n': case 'r':
349                   case 't': case 'v': case '\\': case '\'': case '"':
350                     *q++ = *p++;
351                     break;
352
353                   default:
354                     goto unknown;
355                   }
356               }
357             *q++ = *p++;
358             break;
359           }
360
361         default:
362           goto unknown;
363         }
364     }
365
366   if (need_operand)
367     goto unknown;
368
369   *q = '\0';
370
371   slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
372   *slot = copy;
373
374   fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
375
376   XDELETEVEC (out_buffer);
377   return;
378
379  unknown:
380   fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
381   XDELETEVEC (out_buffer);
382   XDELETEVEC (copy);
383 }
384
385 /* A macro undef.  */
386
387 static void
388 go_undef (unsigned int lineno, const char *buffer)
389 {
390   void **slot;
391
392   real_debug_hooks->undef (lineno, buffer);
393
394   slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
395   if (slot == NULL)
396     return;
397   fprintf (go_dump_file, "// undef _%s\n", buffer);
398   /* We don't delete the slot from the hash table because that will
399      cause a duplicate const definition.  */
400 }
401
402 /* A function or variable decl.  */
403
404 static void
405 go_decl (tree decl)
406 {
407   if (!TREE_PUBLIC (decl)
408       || DECL_IS_BUILTIN (decl)
409       || DECL_NAME (decl) == NULL_TREE)
410     return;
411   VEC_safe_push (tree, gc, queue, decl);
412 }
413
414 /* A function decl.  */
415
416 static void
417 go_function_decl (tree decl)
418 {
419   real_debug_hooks->function_decl (decl);
420   go_decl (decl);
421 }
422
423 /* A global variable decl.  */
424
425 static void
426 go_global_decl (tree decl)
427 {
428   real_debug_hooks->global_decl (decl);
429   go_decl (decl);
430 }
431
432 /* A type declaration.  */
433
434 static void
435 go_type_decl (tree decl, int local)
436 {
437   real_debug_hooks->type_decl (decl, local);
438
439   if (local || DECL_IS_BUILTIN (decl))
440     return;
441   if (DECL_NAME (decl) == NULL_TREE
442       && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
443           || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
444       && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
445     return;
446   VEC_safe_push (tree, gc, queue, decl);
447 }
448
449 /* A container for the data we pass around when generating information
450    at the end of the compilation.  */
451
452 struct godump_container
453 {
454   /* DECLs that we have already seen.  */
455   struct pointer_set_t *decls_seen;
456
457   /* Types which may potentially have to be defined as dummy
458      types.  */
459   struct pointer_set_t *pot_dummy_types;
460
461   /* Go keywords.  */
462   htab_t keyword_hash;
463
464   /* Global type definitions.  */
465   htab_t type_hash;
466
467   /* Invalid types.  */
468   htab_t invalid_hash;
469
470   /* Obstack used to write out a type definition.  */
471   struct obstack type_obstack;
472 };
473
474 /* Append an IDENTIFIER_NODE to OB.  */
475
476 static void
477 go_append_string (struct obstack *ob, tree id)
478 {
479   obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
480 }
481
482 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
483    USE_TYPE_NAME is true if we can simply use a type name here without
484    needing to define it.  IS_FUNC_OK is true if we can output a func
485    type here; the "func" keyword will already have been added.  Return
486    true if the type can be represented in Go, false otherwise.  */
487
488 static bool
489 go_format_type (struct godump_container *container, tree type,
490                 bool use_type_name, bool is_func_ok)
491 {
492   bool ret;
493   struct obstack *ob;
494
495   ret = true;
496   ob = &container->type_obstack;
497
498   if (TYPE_NAME (type) != NULL_TREE
499       && (pointer_set_contains (container->decls_seen, type)
500           || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
501       && (AGGREGATE_TYPE_P (type)
502           || POINTER_TYPE_P (type)
503           || TREE_CODE (type) == FUNCTION_TYPE))
504     {
505       tree name;
506       void **slot;
507
508       name = TYPE_NAME (type);
509       if (TREE_CODE (name) == TYPE_DECL)
510         name = DECL_NAME (name);
511
512       slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
513                              NO_INSERT);
514       if (slot != NULL)
515         ret = false;
516
517       obstack_1grow (ob, '_');
518       go_append_string (ob, name);
519       return ret;
520     }
521
522   pointer_set_insert (container->decls_seen, type);
523
524   switch (TREE_CODE (type))
525     {
526     case ENUMERAL_TYPE:
527       obstack_grow (ob, "int", 3);
528       break;
529
530     case TYPE_DECL:
531       obstack_1grow (ob, '_');
532       go_append_string (ob, DECL_NAME (type));
533       break;
534
535     case INTEGER_TYPE:
536       {
537         const char *s;
538         char buf[100];
539
540         switch (TYPE_PRECISION (type))
541           {
542           case 8:
543             s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
544             break;
545           case 16:
546             s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
547             break;
548           case 32:
549             s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
550             break;
551           case 64:
552             s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
553             break;
554           default:
555             snprintf (buf, sizeof buf, "INVALID-int-%u%s",
556                       TYPE_PRECISION (type),
557                       TYPE_UNSIGNED (type) ? "u" : "");
558             s = buf;
559             ret = false;
560             break;
561           }
562         obstack_grow (ob, s, strlen (s));
563       }
564       break;
565
566     case REAL_TYPE:
567       {
568         const char *s;
569         char buf[100];
570
571         switch (TYPE_PRECISION (type))
572           {
573           case 32:
574             s = "float32";
575             break;
576           case 64:
577             s = "float64";
578             break;
579           default:
580             snprintf (buf, sizeof buf, "INVALID-float-%u",
581                       TYPE_PRECISION (type));
582             s = buf;
583             ret = false;
584             break;
585           }
586         obstack_grow (ob, s, strlen (s));
587       }
588       break;
589
590     case BOOLEAN_TYPE:
591       obstack_grow (ob, "bool", 4);
592       break;
593
594     case POINTER_TYPE:
595       if (use_type_name
596           && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
597           && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
598               || (POINTER_TYPE_P (TREE_TYPE (type))
599                   && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
600                       == FUNCTION_TYPE))))
601         {
602           tree name;
603
604           name = TYPE_NAME (TREE_TYPE (type));
605           if (TREE_CODE (name) == IDENTIFIER_NODE)
606             {
607               obstack_grow (ob, "*_", 2);
608               go_append_string (ob, name);
609
610               /* The pointer here can be used without the struct or
611                  union definition.  So this struct or union is a a
612                  potential dummy type.  */
613               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
614                 pointer_set_insert (container->pot_dummy_types,
615                                     IDENTIFIER_POINTER (name));
616
617               return ret;
618             }
619           else if (TREE_CODE (name) == TYPE_DECL)
620             {
621               obstack_grow (ob, "*_", 2);
622               go_append_string (ob, DECL_NAME (name));
623               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
624                 pointer_set_insert (container->pot_dummy_types,
625                                     IDENTIFIER_POINTER (DECL_NAME (name)));
626               return ret;
627             }
628         }
629       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
630         obstack_grow (ob, "func", 4);
631       else
632         obstack_1grow (ob, '*');
633       if (VOID_TYPE_P (TREE_TYPE (type)))
634         obstack_grow (ob, "byte", 4);
635       else
636         {
637           if (!go_format_type (container, TREE_TYPE (type), use_type_name,
638                                true))
639             ret = false;
640         }
641       break;
642
643     case ARRAY_TYPE:
644       obstack_1grow (ob, '[');
645       if (TYPE_DOMAIN (type) != NULL_TREE
646           && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
647           && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
648           && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
649           && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
650           && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
651           && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
652           && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
653         {
654           char buf[100];
655
656           snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
657                     tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
658           obstack_grow (ob, buf, strlen (buf));
659         }
660       obstack_1grow (ob, ']');
661       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
662         ret = false;
663       break;
664
665     case UNION_TYPE:
666     case RECORD_TYPE:
667       {
668         tree field;
669         int i;
670
671         obstack_grow (ob, "struct { ", 9);
672         i = 0;
673         for (field = TYPE_FIELDS (type);
674              field != NULL_TREE;
675              field = TREE_CHAIN (field))
676           {
677             if (DECL_NAME (field) == NULL)
678               {
679                 char buf[100];
680
681                 obstack_grow (ob, "Godump_", 2);
682                 snprintf (buf, sizeof buf, "%d", i);
683                 obstack_grow (ob, buf, strlen (buf));
684                 i++;
685               }
686             else
687               {
688                 const char *var_name;
689                 void **slot;
690
691                 /* Start variable name with an underscore if a keyword.  */
692                 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
693                 slot = htab_find_slot (container->keyword_hash, var_name,
694                                        NO_INSERT);
695                 if (slot != NULL)
696                   obstack_1grow (ob, '_');
697                 go_append_string (ob, DECL_NAME (field));
698               }
699             obstack_1grow (ob, ' ');
700             if (DECL_BIT_FIELD (field))
701               {
702                 obstack_grow (ob, "INVALID-bit-field", 17);
703                 ret = false;
704               }
705             else
706               {
707                 /* Do not expand type if a record or union type or a
708                    function pointer.  */
709                 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
710                     && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
711                         || (POINTER_TYPE_P (TREE_TYPE (field))
712                             && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
713                                 == FUNCTION_TYPE))))
714                   {
715                     tree name = TYPE_NAME (TREE_TYPE (field));
716                     if (TREE_CODE (name) == IDENTIFIER_NODE)
717                       {
718                         obstack_1grow (ob, '_');
719                         go_append_string (ob, name);
720                       }
721                     else if (TREE_CODE (name) == TYPE_DECL)
722                       {
723                         obstack_1grow (ob, '_');
724                         go_append_string (ob, DECL_NAME (name));
725                       }
726                   }
727                 else
728                   {
729                     if (!go_format_type (container, TREE_TYPE (field), true,
730                                          false))
731                       ret = false;
732                   }
733               }
734             obstack_grow (ob, "; ", 2);
735
736             /* Only output the first field of a union, and hope for
737                the best.  */
738             if (TREE_CODE (type) == UNION_TYPE)
739               break;
740           }
741         obstack_1grow (ob, '}');
742       }
743       break;
744
745     case FUNCTION_TYPE:
746       {
747         tree arg_type;
748         bool is_varargs;
749         tree result;
750         function_args_iterator iter;
751         bool seen_arg;
752
753         /* Go has no way to write a type which is a function but not a
754            pointer to a function.  */
755         if (!is_func_ok)
756           {
757             obstack_grow (ob, "func*", 5);
758             ret = false;
759           }
760
761         obstack_1grow (ob, '(');
762         is_varargs = stdarg_p (type);
763         seen_arg = false;
764         FOREACH_FUNCTION_ARGS (type, arg_type, iter)
765           {
766             if (VOID_TYPE_P (arg_type))
767               break;
768             if (seen_arg)
769               obstack_grow (ob, ", ", 2);
770             if (!go_format_type (container, arg_type, true, false))
771               ret = false;
772             seen_arg = true;
773           }
774         if (is_varargs)
775           {
776             if (prototype_p (type))
777               obstack_grow (ob, ", ", 2);
778             obstack_grow (ob, "...interface{}", 14);
779           }
780         obstack_1grow (ob, ')');
781
782         result = TREE_TYPE (type);
783         if (!VOID_TYPE_P (result))
784           {
785             obstack_1grow (ob, ' ');
786             if (!go_format_type (container, result, use_type_name, false))
787               ret = false;
788           }
789       }
790       break;
791
792     default:
793       obstack_grow (ob, "INVALID-type", 12);
794       ret = false;
795       break;
796     }
797
798   return ret;
799 }
800
801 /* Output the type which was built on the type obstack, and then free
802    it.  */
803
804 static void
805 go_output_type (struct godump_container *container)
806 {
807   struct obstack *ob;
808
809   ob = &container->type_obstack;
810   obstack_1grow (ob, '\0');
811   fputs (obstack_base (ob), go_dump_file);
812   obstack_free (ob, obstack_base (ob));
813 }
814
815 /* Output a function declaration.  */
816
817 static void
818 go_output_fndecl (struct godump_container *container, tree decl)
819 {
820   if (!go_format_type (container, TREE_TYPE (decl), false, true))
821     fprintf (go_dump_file, "// ");
822   fprintf (go_dump_file, "func _%s ",
823            IDENTIFIER_POINTER (DECL_NAME (decl)));
824   go_output_type (container);
825   fprintf (go_dump_file, " __asm__(\"%s\")\n",
826            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
827 }
828
829 /* Output a typedef or something like a struct definition.  */
830
831 static void
832 go_output_typedef (struct godump_container *container, tree decl)
833 {
834   /* If we have an enum type, output the enum constants
835      separately.  */
836   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
837       && TYPE_SIZE (TREE_TYPE (decl)) != 0
838       && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
839       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
840           || !pointer_set_contains (container->decls_seen,
841                                     TYPE_CANONICAL (TREE_TYPE (decl)))))
842     {
843       tree element;
844
845       for (element = TYPE_VALUES (TREE_TYPE (decl));
846            element != NULL_TREE;
847            element = TREE_CHAIN (element))
848         {
849           const char *name;
850           void **slot;
851
852           name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
853
854           /* Sometimes a name will be defined as both an enum constant
855              and a macro.  Avoid duplicate definition errors by
856              treating enum constants as macros.  */
857           slot = htab_find_slot (macro_hash, name, INSERT);
858           if (*slot == NULL)
859             {
860               *slot = CONST_CAST (char *, name);
861               fprintf (go_dump_file,
862                        "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
863                        name, tree_low_cst (TREE_VALUE (element), 0));
864             }
865         }
866       pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
867       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
868         pointer_set_insert (container->decls_seen,
869                             TYPE_CANONICAL (TREE_TYPE (decl)));
870     }
871
872   if (DECL_NAME (decl) != NULL_TREE)
873     {
874       void **slot;
875       const char *type;
876
877       type = IDENTIFIER_POINTER (DECL_NAME (decl));
878       /* If type defined already, skip.  */
879       slot = htab_find_slot (container->type_hash, type, INSERT);
880       if (*slot != NULL)
881         return;
882       *slot = CONST_CAST (void *, (const void *) type);
883
884       if (!go_format_type (container, TREE_TYPE (decl), false, false))
885         {
886           fprintf (go_dump_file, "// ");
887           slot = htab_find_slot (container->invalid_hash, type, INSERT);
888           *slot = CONST_CAST (void *, (const void *) type);
889         }
890       fprintf (go_dump_file, "type _%s ",
891                IDENTIFIER_POINTER (DECL_NAME (decl)));
892       go_output_type (container);
893       pointer_set_insert (container->decls_seen, decl);
894     }
895   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
896     {
897        void **slot;
898        const char *type;
899
900        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
901        /* If type defined already, skip.  */
902        slot = htab_find_slot (container->type_hash, type, INSERT);
903        if (*slot != NULL)
904          return;
905        *slot = CONST_CAST (void *, (const void *) type);
906
907        if (!go_format_type (container, TREE_TYPE (decl), false, false))
908          {
909            fprintf (go_dump_file, "// ");
910            slot = htab_find_slot (container->invalid_hash, type, INSERT);
911            *slot = CONST_CAST (void *, (const void *) type);
912          }
913        fprintf (go_dump_file, "type _%s ",
914                IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
915        go_output_type (container);
916     }
917   else
918     return;
919
920   fprintf (go_dump_file, "\n");
921 }
922
923 /* Output a variable.  */
924
925 static void
926 go_output_var (struct godump_container *container, tree decl)
927 {
928   bool is_valid;
929
930   if (pointer_set_contains (container->decls_seen, decl)
931       || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
932     return;
933   pointer_set_insert (container->decls_seen, decl);
934   pointer_set_insert (container->decls_seen, DECL_NAME (decl));
935
936   is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
937   if (is_valid
938       && htab_find_slot (container->type_hash,
939                          IDENTIFIER_POINTER (DECL_NAME (decl)),
940                          NO_INSERT) != NULL)
941     {
942       /* There is already a type with this name, probably from a
943          struct tag.  Prefer the type to the variable.  */
944       is_valid = false;
945     }
946   if (!is_valid)
947     fprintf (go_dump_file, "// ");
948
949   fprintf (go_dump_file, "var _%s ",
950            IDENTIFIER_POINTER (DECL_NAME (decl)));
951   go_output_type (container);
952   fprintf (go_dump_file, "\n");
953
954   /* Sometimes an extern variable is declared with an unknown struct
955      type.  */
956   if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
957       && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
958     {
959       tree type_name = TYPE_NAME (TREE_TYPE (decl));
960       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
961         pointer_set_insert (container->pot_dummy_types,
962                             IDENTIFIER_POINTER (type_name));
963       else if (TREE_CODE (type_name) == TYPE_DECL)
964         pointer_set_insert (container->pot_dummy_types,
965                             IDENTIFIER_POINTER (DECL_NAME (type_name)));
966     }
967 }
968
969 /* Build a hash table with the Go keywords.  */
970
971 static const char * const keywords[] = {
972   "__asm__", "break", "case", "chan", "const", "continue", "default",
973   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
974   "import", "interface", "map", "package", "range", "return", "select",
975   "struct", "switch", "type", "var"
976 };
977
978 static void
979 keyword_hash_init (struct godump_container *container)
980 {
981   size_t i;
982   size_t count = sizeof (keywords) / sizeof (keywords[0]);
983   void **slot;
984
985   for (i = 0; i < count; i++)
986     {
987       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
988       *slot = CONST_CAST (void *, (const void *) keywords[i]);
989     }
990 }
991
992 /* Traversing the pot_dummy_types and seeing which types are present
993    in the global types hash table and creating dummy definitions if
994    not found.  This function is invoked by pointer_set_traverse.  */
995
996 static bool
997 find_dummy_types (const void *ptr, void *adata)
998 {
999   struct godump_container *data = (struct godump_container *) adata;
1000   const char *type = (const char *) ptr;
1001   void **slot;
1002
1003   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1004   if (slot == NULL)
1005     fprintf (go_dump_file, "type _%s struct {}\n", type);
1006   return true;
1007 }
1008
1009 /* Output symbols.  */
1010
1011 static void
1012 go_finish (const char *filename)
1013 {
1014   struct godump_container container;
1015   unsigned int ix;
1016   tree decl;
1017
1018   real_debug_hooks->finish (filename);
1019
1020   container.decls_seen = pointer_set_create ();
1021   container.pot_dummy_types = pointer_set_create ();
1022   container.type_hash = htab_create (100, htab_hash_string,
1023                                      string_hash_eq, NULL);
1024   container.invalid_hash = htab_create (10, htab_hash_string,
1025                                         string_hash_eq, NULL);
1026   container.keyword_hash = htab_create (50, htab_hash_string,
1027                                         string_hash_eq, NULL);
1028   obstack_init (&container.type_obstack);
1029
1030   keyword_hash_init (&container);
1031
1032   FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1033     {
1034       switch (TREE_CODE (decl))
1035         {
1036         case FUNCTION_DECL:
1037           go_output_fndecl (&container, decl);
1038           break;
1039
1040         case TYPE_DECL:
1041           go_output_typedef (&container, decl);
1042           break;
1043
1044         case VAR_DECL:
1045           go_output_var (&container, decl);
1046           break;
1047
1048         default:
1049           gcc_unreachable();
1050         }
1051     }
1052
1053   /* To emit dummy definitions.  */
1054   pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1055                         (void *) &container);
1056
1057   pointer_set_destroy (container.decls_seen);
1058   pointer_set_destroy (container.pot_dummy_types);
1059   htab_delete (container.type_hash);
1060   htab_delete (container.invalid_hash);
1061   htab_delete (container.keyword_hash);
1062   obstack_free (&container.type_obstack, NULL);
1063
1064   queue = NULL;
1065
1066   if (fclose (go_dump_file) != 0)
1067     error ("could not close Go dump file: %m");
1068   go_dump_file = NULL;
1069 }
1070
1071 /* Set up our hooks.  */
1072
1073 const struct gcc_debug_hooks *
1074 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1075 {
1076   go_dump_file = fopen (filename, "w");
1077   if (go_dump_file == NULL)
1078     {
1079       error ("could not open Go dump file %qs: %m", filename);
1080       return hooks;
1081     }
1082
1083   go_debug_hooks = *hooks;
1084   real_debug_hooks = hooks;
1085
1086   go_debug_hooks.finish = go_finish;
1087   go_debug_hooks.define = go_define;
1088   go_debug_hooks.undef = go_undef;
1089   go_debug_hooks.function_decl = go_function_decl;
1090   go_debug_hooks.global_decl = go_global_decl;
1091   go_debug_hooks.type_decl = go_type_decl;
1092
1093   macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1094
1095   return &go_debug_hooks;
1096 }
1097
1098 #include "gt-godump.h"