OSDN Git Service

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