OSDN Git Service

2011-09-27 Richard Guenther <rguenther@suse.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   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;
304             int count;
305
306             if (saw_operand)
307               goto unknown;
308             quote = *p;
309             *q++ = *p++;
310             count = 0;
311             while (*p != quote)
312               {
313                 int c;
314
315                 if (*p == '\0')
316                   goto unknown;
317
318                 ++count;
319
320                 if (*p != '\\')
321                   {
322                     *q++ = *p++;
323                     continue;
324                   }
325
326                 *q++ = *p++;
327                 switch (*p)
328                   {
329                   case '0': case '1': case '2': case '3':
330                   case '4': case '5': case '6': case '7':
331                     c = 0;
332                     while (*p >= '0' && *p <= '7')
333                       {
334                         *q++ = *p++;
335                         ++c;
336                       }
337                     /* Go octal characters are always 3
338                        digits.  */
339                     if (c != 3)
340                       goto unknown;
341                     break;
342
343                   case 'x':
344                     *q++ = *p++;
345                     c = 0;
346                     while (ISXDIGIT (*p))
347                       {
348                         *q++ = *p++;
349                         ++c;
350                       }
351                     /* Go hex characters are always 2 digits.  */
352                     if (c != 2)
353                       goto unknown;
354                     break;
355
356                   case 'a': case 'b': case 'f': case 'n': case 'r':
357                   case 't': case 'v': case '\\': case '\'': case '"':
358                     *q++ = *p++;
359                     break;
360
361                   default:
362                     goto unknown;
363                   }
364               }
365
366             *q++ = *p++;
367
368             if (quote == '\'' && count != 1)
369               goto unknown;
370
371             saw_operand = true;
372             need_operand = false;
373
374             break;
375           }
376
377         default:
378           goto unknown;
379         }
380     }
381
382   if (need_operand)
383     goto unknown;
384
385   *q = '\0';
386
387   slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
388   *slot = copy;
389
390   fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
391
392   XDELETEVEC (out_buffer);
393   return;
394
395  unknown:
396   fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
397   XDELETEVEC (out_buffer);
398   XDELETEVEC (copy);
399 }
400
401 /* A macro undef.  */
402
403 static void
404 go_undef (unsigned int lineno, const char *buffer)
405 {
406   void **slot;
407
408   real_debug_hooks->undef (lineno, buffer);
409
410   slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
411   if (slot == NULL)
412     return;
413   fprintf (go_dump_file, "// undef _%s\n", buffer);
414   /* We don't delete the slot from the hash table because that will
415      cause a duplicate const definition.  */
416 }
417
418 /* A function or variable decl.  */
419
420 static void
421 go_decl (tree decl)
422 {
423   if (!TREE_PUBLIC (decl)
424       || DECL_IS_BUILTIN (decl)
425       || DECL_NAME (decl) == NULL_TREE)
426     return;
427   VEC_safe_push (tree, gc, queue, decl);
428 }
429
430 /* A function decl.  */
431
432 static void
433 go_function_decl (tree decl)
434 {
435   real_debug_hooks->function_decl (decl);
436   go_decl (decl);
437 }
438
439 /* A global variable decl.  */
440
441 static void
442 go_global_decl (tree decl)
443 {
444   real_debug_hooks->global_decl (decl);
445   go_decl (decl);
446 }
447
448 /* A type declaration.  */
449
450 static void
451 go_type_decl (tree decl, int local)
452 {
453   real_debug_hooks->type_decl (decl, local);
454
455   if (local || DECL_IS_BUILTIN (decl))
456     return;
457   if (DECL_NAME (decl) == NULL_TREE
458       && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
459           || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
460       && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
461     return;
462   VEC_safe_push (tree, gc, queue, decl);
463 }
464
465 /* A container for the data we pass around when generating information
466    at the end of the compilation.  */
467
468 struct godump_container
469 {
470   /* DECLs that we have already seen.  */
471   struct pointer_set_t *decls_seen;
472
473   /* Types which may potentially have to be defined as dummy
474      types.  */
475   struct pointer_set_t *pot_dummy_types;
476
477   /* Go keywords.  */
478   htab_t keyword_hash;
479
480   /* Global type definitions.  */
481   htab_t type_hash;
482
483   /* Invalid types.  */
484   htab_t invalid_hash;
485
486   /* Obstack used to write out a type definition.  */
487   struct obstack type_obstack;
488 };
489
490 /* Append an IDENTIFIER_NODE to OB.  */
491
492 static void
493 go_append_string (struct obstack *ob, tree id)
494 {
495   obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
496 }
497
498 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
499    USE_TYPE_NAME is true if we can simply use a type name here without
500    needing to define it.  IS_FUNC_OK is true if we can output a func
501    type here; the "func" keyword will already have been added.  Return
502    true if the type can be represented in Go, false otherwise.  */
503
504 static bool
505 go_format_type (struct godump_container *container, tree type,
506                 bool use_type_name, bool is_func_ok)
507 {
508   bool ret;
509   struct obstack *ob;
510
511   ret = true;
512   ob = &container->type_obstack;
513
514   if (TYPE_NAME (type) != NULL_TREE
515       && (pointer_set_contains (container->decls_seen, type)
516           || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
517       && (AGGREGATE_TYPE_P (type)
518           || POINTER_TYPE_P (type)
519           || TREE_CODE (type) == FUNCTION_TYPE))
520     {
521       tree name;
522       void **slot;
523
524       name = TYPE_NAME (type);
525       if (TREE_CODE (name) == TYPE_DECL)
526         name = DECL_NAME (name);
527
528       slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
529                              NO_INSERT);
530       if (slot != NULL)
531         ret = false;
532
533       obstack_1grow (ob, '_');
534       go_append_string (ob, name);
535       return ret;
536     }
537
538   pointer_set_insert (container->decls_seen, type);
539
540   switch (TREE_CODE (type))
541     {
542     case ENUMERAL_TYPE:
543       obstack_grow (ob, "int", 3);
544       break;
545
546     case TYPE_DECL:
547       {
548         void **slot;
549
550         slot = htab_find_slot (container->invalid_hash,
551                                IDENTIFIER_POINTER (DECL_NAME (type)),
552                                NO_INSERT);
553         if (slot != NULL)
554           ret = false;
555
556         obstack_1grow (ob, '_');
557         go_append_string (ob, DECL_NAME (type));
558       }
559       break;
560
561     case INTEGER_TYPE:
562       {
563         const char *s;
564         char buf[100];
565
566         switch (TYPE_PRECISION (type))
567           {
568           case 8:
569             s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
570             break;
571           case 16:
572             s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
573             break;
574           case 32:
575             s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
576             break;
577           case 64:
578             s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
579             break;
580           default:
581             snprintf (buf, sizeof buf, "INVALID-int-%u%s",
582                       TYPE_PRECISION (type),
583                       TYPE_UNSIGNED (type) ? "u" : "");
584             s = buf;
585             ret = false;
586             break;
587           }
588         obstack_grow (ob, s, strlen (s));
589       }
590       break;
591
592     case REAL_TYPE:
593       {
594         const char *s;
595         char buf[100];
596
597         switch (TYPE_PRECISION (type))
598           {
599           case 32:
600             s = "float32";
601             break;
602           case 64:
603             s = "float64";
604             break;
605           default:
606             snprintf (buf, sizeof buf, "INVALID-float-%u",
607                       TYPE_PRECISION (type));
608             s = buf;
609             ret = false;
610             break;
611           }
612         obstack_grow (ob, s, strlen (s));
613       }
614       break;
615
616     case BOOLEAN_TYPE:
617       obstack_grow (ob, "bool", 4);
618       break;
619
620     case POINTER_TYPE:
621       if (use_type_name
622           && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
623           && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
624               || (POINTER_TYPE_P (TREE_TYPE (type))
625                   && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
626                       == FUNCTION_TYPE))))
627         {
628           tree name;
629           void **slot;
630
631           name = TYPE_NAME (TREE_TYPE (type));
632           if (TREE_CODE (name) == TYPE_DECL)
633             name = DECL_NAME (name);
634
635           slot = htab_find_slot (container->invalid_hash,
636                                  IDENTIFIER_POINTER (name), NO_INSERT);
637           if (slot != NULL)
638             ret = false;
639
640           obstack_grow (ob, "*_", 2);
641           go_append_string (ob, name);
642
643           /* The pointer here can be used without the struct or union
644              definition.  So this struct or union is a potential dummy
645              type.  */
646           if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
647             pointer_set_insert (container->pot_dummy_types,
648                                 IDENTIFIER_POINTER (name));
649
650           return ret;
651         }
652       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
653         obstack_grow (ob, "func", 4);
654       else
655         obstack_1grow (ob, '*');
656       if (VOID_TYPE_P (TREE_TYPE (type)))
657         obstack_grow (ob, "byte", 4);
658       else
659         {
660           if (!go_format_type (container, TREE_TYPE (type), use_type_name,
661                                true))
662             ret = false;
663         }
664       break;
665
666     case ARRAY_TYPE:
667       obstack_1grow (ob, '[');
668       if (TYPE_DOMAIN (type) != NULL_TREE
669           && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
670           && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
671           && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
672           && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
673           && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
674           && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
675           && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
676         {
677           char buf[100];
678
679           snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
680                     tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
681           obstack_grow (ob, buf, strlen (buf));
682         }
683       obstack_1grow (ob, ']');
684       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
685         ret = false;
686       break;
687
688     case UNION_TYPE:
689     case RECORD_TYPE:
690       {
691         tree field;
692         int i;
693
694         obstack_grow (ob, "struct { ", 9);
695         i = 0;
696         for (field = TYPE_FIELDS (type);
697              field != NULL_TREE;
698              field = TREE_CHAIN (field))
699           {
700             struct obstack hold_type_obstack;
701             bool field_ok;
702
703             if (TREE_CODE (type) == UNION_TYPE)
704               {
705                 hold_type_obstack = container->type_obstack;
706                 obstack_init (&container->type_obstack);
707               }
708
709             field_ok = true;
710
711             if (DECL_NAME (field) == NULL)
712               {
713                 char buf[100];
714
715                 obstack_grow (ob, "Godump_", 7);
716                 snprintf (buf, sizeof buf, "%d", i);
717                 obstack_grow (ob, buf, strlen (buf));
718                 i++;
719               }
720             else
721               {
722                 const char *var_name;
723                 void **slot;
724
725                 /* Start variable name with an underscore if a keyword.  */
726                 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
727                 slot = htab_find_slot (container->keyword_hash, var_name,
728                                        NO_INSERT);
729                 if (slot != NULL)
730                   obstack_1grow (ob, '_');
731                 go_append_string (ob, DECL_NAME (field));
732               }
733             obstack_1grow (ob, ' ');
734             if (DECL_BIT_FIELD (field))
735               {
736                 obstack_grow (ob, "INVALID-bit-field", 17);
737                 field_ok = false;
738               }
739             else
740               {
741                 /* Do not expand type if a record or union type or a
742                    function pointer.  */
743                 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
744                     && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
745                         || (POINTER_TYPE_P (TREE_TYPE (field))
746                             && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
747                                 == FUNCTION_TYPE))))
748                   {
749                     tree name;
750                     void **slot;
751
752                     name = TYPE_NAME (TREE_TYPE (field));
753                     if (TREE_CODE (name) == TYPE_DECL)
754                       name = DECL_NAME (name);
755
756                     slot = htab_find_slot (container->invalid_hash,
757                                            IDENTIFIER_POINTER (name),
758                                            NO_INSERT);
759                     if (slot != NULL)
760                       field_ok = false;
761
762                     obstack_1grow (ob, '_');
763                     go_append_string (ob, name);
764                   }
765                 else
766                   {
767                     if (!go_format_type (container, TREE_TYPE (field), true,
768                                          false))
769                       field_ok = false;
770                   }
771               }
772             obstack_grow (ob, "; ", 2);
773
774             /* Only output the first successful field of a union, and
775                hope for the best.  */
776             if (TREE_CODE (type) == UNION_TYPE)
777               {
778                 if (!field_ok && TREE_CHAIN (field) == NULL_TREE)
779                   {
780                     field_ok = true;
781                     ret = false;
782                   }
783                 if (field_ok)
784                   {
785                     unsigned int sz;
786
787                     sz = obstack_object_size (&container->type_obstack);
788                     obstack_grow (&hold_type_obstack,
789                                   obstack_base (&container->type_obstack),
790                                   sz);
791                   }
792                 obstack_free (&container->type_obstack, NULL);
793                 container->type_obstack = hold_type_obstack;
794                 if (field_ok)
795                   break;
796               }
797             else
798               {
799                 if (!field_ok)
800                   ret = false;
801               }
802           }
803         obstack_1grow (ob, '}');
804       }
805       break;
806
807     case FUNCTION_TYPE:
808       {
809         tree arg_type;
810         bool is_varargs;
811         tree result;
812         function_args_iterator iter;
813         bool seen_arg;
814
815         /* Go has no way to write a type which is a function but not a
816            pointer to a function.  */
817         if (!is_func_ok)
818           {
819             obstack_grow (ob, "func*", 5);
820             ret = false;
821           }
822
823         obstack_1grow (ob, '(');
824         is_varargs = stdarg_p (type);
825         seen_arg = false;
826         FOREACH_FUNCTION_ARGS (type, arg_type, iter)
827           {
828             if (VOID_TYPE_P (arg_type))
829               break;
830             if (seen_arg)
831               obstack_grow (ob, ", ", 2);
832             if (!go_format_type (container, arg_type, true, false))
833               ret = false;
834             seen_arg = true;
835           }
836         if (is_varargs)
837           {
838             if (prototype_p (type))
839               obstack_grow (ob, ", ", 2);
840             obstack_grow (ob, "...interface{}", 14);
841           }
842         obstack_1grow (ob, ')');
843
844         result = TREE_TYPE (type);
845         if (!VOID_TYPE_P (result))
846           {
847             obstack_1grow (ob, ' ');
848             if (!go_format_type (container, result, use_type_name, false))
849               ret = false;
850           }
851       }
852       break;
853
854     default:
855       obstack_grow (ob, "INVALID-type", 12);
856       ret = false;
857       break;
858     }
859
860   return ret;
861 }
862
863 /* Output the type which was built on the type obstack, and then free
864    it.  */
865
866 static void
867 go_output_type (struct godump_container *container)
868 {
869   struct obstack *ob;
870
871   ob = &container->type_obstack;
872   obstack_1grow (ob, '\0');
873   fputs (obstack_base (ob), go_dump_file);
874   obstack_free (ob, obstack_base (ob));
875 }
876
877 /* Output a function declaration.  */
878
879 static void
880 go_output_fndecl (struct godump_container *container, tree decl)
881 {
882   if (!go_format_type (container, TREE_TYPE (decl), false, true))
883     fprintf (go_dump_file, "// ");
884   fprintf (go_dump_file, "func _%s ",
885            IDENTIFIER_POINTER (DECL_NAME (decl)));
886   go_output_type (container);
887   fprintf (go_dump_file, " __asm__(\"%s\")\n",
888            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
889 }
890
891 /* Output a typedef or something like a struct definition.  */
892
893 static void
894 go_output_typedef (struct godump_container *container, tree decl)
895 {
896   /* If we have an enum type, output the enum constants
897      separately.  */
898   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
899       && TYPE_SIZE (TREE_TYPE (decl)) != 0
900       && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
901       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
902           || !pointer_set_contains (container->decls_seen,
903                                     TYPE_CANONICAL (TREE_TYPE (decl)))))
904     {
905       tree element;
906
907       for (element = TYPE_VALUES (TREE_TYPE (decl));
908            element != NULL_TREE;
909            element = TREE_CHAIN (element))
910         {
911           const char *name;
912           void **slot;
913
914           name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
915
916           /* Sometimes a name will be defined as both an enum constant
917              and a macro.  Avoid duplicate definition errors by
918              treating enum constants as macros.  */
919           slot = htab_find_slot (macro_hash, name, INSERT);
920           if (*slot == NULL)
921             {
922               *slot = CONST_CAST (char *, name);
923               fprintf (go_dump_file,
924                        "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
925                        name, tree_low_cst (TREE_VALUE (element), 0));
926             }
927         }
928       pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
929       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
930         pointer_set_insert (container->decls_seen,
931                             TYPE_CANONICAL (TREE_TYPE (decl)));
932     }
933
934   if (DECL_NAME (decl) != NULL_TREE)
935     {
936       void **slot;
937       const char *type;
938
939       type = IDENTIFIER_POINTER (DECL_NAME (decl));
940       /* If type defined already, skip.  */
941       slot = htab_find_slot (container->type_hash, type, INSERT);
942       if (*slot != NULL)
943         return;
944       *slot = CONST_CAST (void *, (const void *) type);
945
946       if (!go_format_type (container, TREE_TYPE (decl), false, false))
947         {
948           fprintf (go_dump_file, "// ");
949           slot = htab_find_slot (container->invalid_hash, type, INSERT);
950           *slot = CONST_CAST (void *, (const void *) type);
951         }
952       fprintf (go_dump_file, "type _%s ",
953                IDENTIFIER_POINTER (DECL_NAME (decl)));
954       go_output_type (container);
955       pointer_set_insert (container->decls_seen, decl);
956     }
957   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
958     {
959        void **slot;
960        const char *type;
961
962        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
963        /* If type defined already, skip.  */
964        slot = htab_find_slot (container->type_hash, type, INSERT);
965        if (*slot != NULL)
966          return;
967        *slot = CONST_CAST (void *, (const void *) type);
968
969        if (!go_format_type (container, TREE_TYPE (decl), false, false))
970          {
971            fprintf (go_dump_file, "// ");
972            slot = htab_find_slot (container->invalid_hash, type, INSERT);
973            *slot = CONST_CAST (void *, (const void *) type);
974          }
975        fprintf (go_dump_file, "type _%s ",
976                IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
977        go_output_type (container);
978     }
979   else
980     return;
981
982   fprintf (go_dump_file, "\n");
983 }
984
985 /* Output a variable.  */
986
987 static void
988 go_output_var (struct godump_container *container, tree decl)
989 {
990   bool is_valid;
991
992   if (pointer_set_contains (container->decls_seen, decl)
993       || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
994     return;
995   pointer_set_insert (container->decls_seen, decl);
996   pointer_set_insert (container->decls_seen, DECL_NAME (decl));
997
998   is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
999   if (is_valid
1000       && htab_find_slot (container->type_hash,
1001                          IDENTIFIER_POINTER (DECL_NAME (decl)),
1002                          NO_INSERT) != NULL)
1003     {
1004       /* There is already a type with this name, probably from a
1005          struct tag.  Prefer the type to the variable.  */
1006       is_valid = false;
1007     }
1008   if (!is_valid)
1009     fprintf (go_dump_file, "// ");
1010
1011   fprintf (go_dump_file, "var _%s ",
1012            IDENTIFIER_POINTER (DECL_NAME (decl)));
1013   go_output_type (container);
1014   fprintf (go_dump_file, "\n");
1015
1016   /* Sometimes an extern variable is declared with an unknown struct
1017      type.  */
1018   if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
1019       && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1020     {
1021       tree type_name = TYPE_NAME (TREE_TYPE (decl));
1022       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1023         pointer_set_insert (container->pot_dummy_types,
1024                             IDENTIFIER_POINTER (type_name));
1025       else if (TREE_CODE (type_name) == TYPE_DECL)
1026         pointer_set_insert (container->pot_dummy_types,
1027                             IDENTIFIER_POINTER (DECL_NAME (type_name)));
1028     }
1029 }
1030
1031 /* Build a hash table with the Go keywords.  */
1032
1033 static const char * const keywords[] = {
1034   "__asm__", "break", "case", "chan", "const", "continue", "default",
1035   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1036   "import", "interface", "map", "package", "range", "return", "select",
1037   "struct", "switch", "type", "var"
1038 };
1039
1040 static void
1041 keyword_hash_init (struct godump_container *container)
1042 {
1043   size_t i;
1044   size_t count = sizeof (keywords) / sizeof (keywords[0]);
1045   void **slot;
1046
1047   for (i = 0; i < count; i++)
1048     {
1049       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1050       *slot = CONST_CAST (void *, (const void *) keywords[i]);
1051     }
1052 }
1053
1054 /* Traversing the pot_dummy_types and seeing which types are present
1055    in the global types hash table and creating dummy definitions if
1056    not found.  This function is invoked by pointer_set_traverse.  */
1057
1058 static bool
1059 find_dummy_types (const void *ptr, void *adata)
1060 {
1061   struct godump_container *data = (struct godump_container *) adata;
1062   const char *type = (const char *) ptr;
1063   void **slot;
1064
1065   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1066   if (slot == NULL)
1067     fprintf (go_dump_file, "type _%s struct {}\n", type);
1068   return true;
1069 }
1070
1071 /* Output symbols.  */
1072
1073 static void
1074 go_finish (const char *filename)
1075 {
1076   struct godump_container container;
1077   unsigned int ix;
1078   tree decl;
1079
1080   real_debug_hooks->finish (filename);
1081
1082   container.decls_seen = pointer_set_create ();
1083   container.pot_dummy_types = pointer_set_create ();
1084   container.type_hash = htab_create (100, htab_hash_string,
1085                                      string_hash_eq, NULL);
1086   container.invalid_hash = htab_create (10, htab_hash_string,
1087                                         string_hash_eq, NULL);
1088   container.keyword_hash = htab_create (50, htab_hash_string,
1089                                         string_hash_eq, NULL);
1090   obstack_init (&container.type_obstack);
1091
1092   keyword_hash_init (&container);
1093
1094   FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1095     {
1096       switch (TREE_CODE (decl))
1097         {
1098         case FUNCTION_DECL:
1099           go_output_fndecl (&container, decl);
1100           break;
1101
1102         case TYPE_DECL:
1103           go_output_typedef (&container, decl);
1104           break;
1105
1106         case VAR_DECL:
1107           go_output_var (&container, decl);
1108           break;
1109
1110         default:
1111           gcc_unreachable();
1112         }
1113     }
1114
1115   /* To emit dummy definitions.  */
1116   pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1117                         (void *) &container);
1118
1119   pointer_set_destroy (container.decls_seen);
1120   pointer_set_destroy (container.pot_dummy_types);
1121   htab_delete (container.type_hash);
1122   htab_delete (container.invalid_hash);
1123   htab_delete (container.keyword_hash);
1124   obstack_free (&container.type_obstack, NULL);
1125
1126   queue = NULL;
1127
1128   if (fclose (go_dump_file) != 0)
1129     error ("could not close Go dump file: %m");
1130   go_dump_file = NULL;
1131 }
1132
1133 /* Set up our hooks.  */
1134
1135 const struct gcc_debug_hooks *
1136 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1137 {
1138   go_dump_file = fopen (filename, "w");
1139   if (go_dump_file == NULL)
1140     {
1141       error ("could not open Go dump file %qs: %m", filename);
1142       return hooks;
1143     }
1144
1145   go_debug_hooks = *hooks;
1146   real_debug_hooks = hooks;
1147
1148   go_debug_hooks.finish = go_finish;
1149   go_debug_hooks.define = go_define;
1150   go_debug_hooks.undef = go_undef;
1151   go_debug_hooks.function_decl = go_function_decl;
1152   go_debug_hooks.global_decl = go_global_decl;
1153   go_debug_hooks.type_decl = go_type_decl;
1154
1155   macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1156
1157   return &go_debug_hooks;
1158 }
1159
1160 #include "gt-godump.h"