OSDN Git Service

7ee7af0e861ab23b8c5faa3a5e106aad312c65a9
[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   /* Obstack used to write out a type definition.  */
468   struct obstack type_obstack;
469 };
470
471 /* Append an IDENTIFIER_NODE to OB.  */
472
473 static void
474 go_append_string (struct obstack *ob, tree id)
475 {
476   obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
477 }
478
479 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
480    USE_TYPE_NAME is true if we can simply use a type name here without
481    needing to define it.  IS_FUNC_OK is true if we can output a func
482    type here; the "func" keyword will already have been added.  Return
483    true if the type can be represented in Go, false otherwise.  */
484
485 static bool
486 go_format_type (struct godump_container *container, tree type,
487                 bool use_type_name, bool is_func_ok)
488 {
489   bool ret;
490   struct obstack *ob;
491
492   ret = true;
493   ob = &container->type_obstack;
494
495   if (TYPE_NAME (type) != NULL_TREE
496       && (pointer_set_contains (container->decls_seen, type)
497           || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
498       && (AGGREGATE_TYPE_P (type)
499           || POINTER_TYPE_P (type)
500           || TREE_CODE (type) == FUNCTION_TYPE))
501     {
502       tree name;
503
504       name = TYPE_NAME (type);
505       if (TREE_CODE (name) == IDENTIFIER_NODE)
506         {
507           obstack_1grow (ob, '_');
508           go_append_string (ob, name);
509           return ret;
510         }
511       else if (TREE_CODE (name) == TYPE_DECL)
512         {
513           obstack_1grow (ob, '_');
514           go_append_string (ob, DECL_NAME (name));
515           return ret;
516         }
517     }
518
519   pointer_set_insert (container->decls_seen, type);
520
521   switch (TREE_CODE (type))
522     {
523     case ENUMERAL_TYPE:
524       obstack_grow (ob, "int", 3);
525       break;
526
527     case TYPE_DECL:
528       obstack_1grow (ob, '_');
529       go_append_string (ob, DECL_NAME (type));
530       break;
531
532     case INTEGER_TYPE:
533       {
534         const char *s;
535         char buf[100];
536
537         switch (TYPE_PRECISION (type))
538           {
539           case 8:
540             s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
541             break;
542           case 16:
543             s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
544             break;
545           case 32:
546             s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
547             break;
548           case 64:
549             s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
550             break;
551           default:
552             snprintf (buf, sizeof buf, "INVALID-int-%u%s",
553                       TYPE_PRECISION (type),
554                       TYPE_UNSIGNED (type) ? "u" : "");
555             s = buf;
556             ret = false;
557             break;
558           }
559         obstack_grow (ob, s, strlen (s));
560       }
561       break;
562
563     case REAL_TYPE:
564       {
565         const char *s;
566         char buf[100];
567
568         switch (TYPE_PRECISION (type))
569           {
570           case 32:
571             s = "float32";
572             break;
573           case 64:
574             s = "float64";
575             break;
576           default:
577             snprintf (buf, sizeof buf, "INVALID-float-%u",
578                       TYPE_PRECISION (type));
579             s = buf;
580             ret = false;
581             break;
582           }
583         obstack_grow (ob, s, strlen (s));
584       }
585       break;
586
587     case BOOLEAN_TYPE:
588       obstack_grow (ob, "bool", 4);
589       break;
590
591     case POINTER_TYPE:
592       if (use_type_name
593           && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
594           && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
595               || (POINTER_TYPE_P (TREE_TYPE (type))
596                   && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
597                       == FUNCTION_TYPE))))
598         {
599           tree name;
600
601           name = TYPE_NAME (TREE_TYPE (type));
602           if (TREE_CODE (name) == IDENTIFIER_NODE)
603             {
604               obstack_grow (ob, "*_", 2);
605               go_append_string (ob, name);
606
607               /* The pointer here can be used without the struct or
608                  union definition.  So this struct or union is a a
609                  potential dummy type.  */
610               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
611                 pointer_set_insert (container->pot_dummy_types,
612                                     IDENTIFIER_POINTER (name));
613
614               return ret;
615             }
616           else if (TREE_CODE (name) == TYPE_DECL)
617             {
618               obstack_grow (ob, "*_", 2);
619               go_append_string (ob, DECL_NAME (name));
620               if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
621                 pointer_set_insert (container->pot_dummy_types,
622                                     IDENTIFIER_POINTER (DECL_NAME (name)));
623               return ret;
624             }
625         }
626       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
627         obstack_grow (ob, "func", 4);
628       else
629         obstack_1grow (ob, '*');
630       if (VOID_TYPE_P (TREE_TYPE (type)))
631         obstack_grow (ob, "byte", 4);
632       else
633         {
634           if (!go_format_type (container, TREE_TYPE (type), use_type_name,
635                                true))
636             ret = false;
637         }
638       break;
639
640     case ARRAY_TYPE:
641       obstack_1grow (ob, '[');
642       if (TYPE_DOMAIN (type) != NULL_TREE
643           && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
644           && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
645           && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
646           && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
647           && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
648           && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
649           && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
650         {
651           char buf[100];
652
653           snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
654                     tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
655           obstack_grow (ob, buf, strlen (buf));
656         }
657       obstack_1grow (ob, ']');
658       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
659         ret = false;
660       break;
661
662     case UNION_TYPE:
663     case RECORD_TYPE:
664       {
665         tree field;
666         int i;
667
668         obstack_grow (ob, "struct { ", 9);
669         i = 0;
670         for (field = TYPE_FIELDS (type);
671              field != NULL_TREE;
672              field = TREE_CHAIN (field))
673           {
674             if (DECL_NAME (field) == NULL)
675               {
676                 char buf[100];
677
678                 obstack_grow (ob, "_f", 2);
679                 snprintf (buf, sizeof buf, "%d", i);
680                 obstack_grow (ob, buf, strlen (buf));
681                 i++;
682               }
683             else
684               {
685                 const char *var_name;
686                 void **slot;
687
688                 /* Start variable name with an underscore if a keyword.  */
689                 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
690                 slot = htab_find_slot (container->keyword_hash, var_name,
691                                        NO_INSERT);
692                 if (slot != NULL)
693                   obstack_1grow (ob, '_');
694                 go_append_string (ob, DECL_NAME (field));
695               }
696             obstack_1grow (ob, ' ');
697             if (DECL_BIT_FIELD (field))
698               {
699                 obstack_grow (ob, "INVALID-bit-field", 17);
700                 ret = false;
701               }
702             else
703               {
704                 /* Do not expand type if a record or union type or a
705                    function pointer.  */
706                 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
707                     && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
708                         || (POINTER_TYPE_P (TREE_TYPE (field))
709                             && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
710                                 == FUNCTION_TYPE))))
711                   {
712                     tree name = TYPE_NAME (TREE_TYPE (field));
713                     if (TREE_CODE (name) == IDENTIFIER_NODE)
714                       {
715                         obstack_1grow (ob, '_');
716                         go_append_string (ob, name);
717                       }
718                     else if (TREE_CODE (name) == TYPE_DECL)
719                       {
720                         obstack_1grow (ob, '_');
721                         go_append_string (ob, DECL_NAME (name));
722                       }
723                   }
724                 else
725                   {
726                     if (!go_format_type (container, TREE_TYPE (field), true,
727                                          false))
728                       ret = false;
729                   }
730               }
731             obstack_grow (ob, "; ", 2);
732
733             /* Only output the first field of a union, and hope for
734                the best.  */
735             if (TREE_CODE (type) == UNION_TYPE)
736               break;
737           }
738         obstack_1grow (ob, '}');
739       }
740       break;
741
742     case FUNCTION_TYPE:
743       {
744         tree args;
745         bool is_varargs;
746         tree result;
747
748         /* Go has no way to write a type which is a function but not a
749            pointer to a function.  */
750         if (!is_func_ok)
751           {
752             obstack_grow (ob, "func*", 5);
753             ret = false;
754           }
755
756         obstack_1grow (ob, '(');
757         is_varargs = true;
758         for (args = TYPE_ARG_TYPES (type);
759              args != NULL_TREE;
760              args = TREE_CHAIN (args))
761           {
762             if (VOID_TYPE_P (TREE_VALUE (args)))
763               {
764                 gcc_assert (TREE_CHAIN (args) == NULL);
765                 is_varargs = false;
766                 break;
767               }
768             if (args != TYPE_ARG_TYPES (type))
769               obstack_grow (ob, ", ", 2);
770             if (!go_format_type (container, TREE_VALUE (args), true, false))
771               ret = false;
772           }
773         if (is_varargs)
774           {
775             if (TYPE_ARG_TYPES (type) != NULL_TREE)
776               obstack_grow (ob, ", ", 2);
777             obstack_grow (ob, "...interface{}", 14);
778           }
779         obstack_1grow (ob, ')');
780
781         result = TREE_TYPE (type);
782         if (!VOID_TYPE_P (result))
783           {
784             obstack_1grow (ob, ' ');
785             if (!go_format_type (container, result, use_type_name, false))
786               ret = false;
787           }
788       }
789       break;
790
791     default:
792       obstack_grow (ob, "INVALID-type", 12);
793       ret = false;
794       break;
795     }
796
797   return ret;
798 }
799
800 /* Output the type which was built on the type obstack, and then free
801    it.  */
802
803 static void
804 go_output_type (struct godump_container *container)
805 {
806   struct obstack *ob;
807
808   ob = &container->type_obstack;
809   obstack_1grow (ob, '\0');
810   fputs (obstack_base (ob), go_dump_file);
811   obstack_free (ob, obstack_base (ob));
812 }
813
814 /* Output a function declaration.  */
815
816 static void
817 go_output_fndecl (struct godump_container *container, tree decl)
818 {
819   if (!go_format_type (container, TREE_TYPE (decl), false, true))
820     fprintf (go_dump_file, "// ");
821   fprintf (go_dump_file, "func _%s ",
822            IDENTIFIER_POINTER (DECL_NAME (decl)));
823   go_output_type (container);
824   fprintf (go_dump_file, " __asm__(\"%s\")\n",
825            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
826 }
827
828 /* Output a typedef or something like a struct definition.  */
829
830 static void
831 go_output_typedef (struct godump_container *container, tree decl)
832 {
833   /* If we have an enum type, output the enum constants
834      separately.  */
835   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
836       && TYPE_SIZE (TREE_TYPE (decl)) != 0
837       && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
838       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
839           || !pointer_set_contains (container->decls_seen,
840                                     TYPE_CANONICAL (TREE_TYPE (decl)))))
841     {
842       tree element;
843
844       for (element = TYPE_VALUES (TREE_TYPE (decl));
845            element != NULL_TREE;
846            element = TREE_CHAIN (element))
847         fprintf (go_dump_file, "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
848                  IDENTIFIER_POINTER (TREE_PURPOSE (element)),
849                  tree_low_cst (TREE_VALUE (element), 0));
850       pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
851       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
852         pointer_set_insert (container->decls_seen,
853                             TYPE_CANONICAL (TREE_TYPE (decl)));
854     }
855
856   if (DECL_NAME (decl) != NULL_TREE)
857     {
858       void **slot;
859       const char *type;
860
861       type = IDENTIFIER_POINTER (DECL_NAME (decl));
862       /* If type defined already, skip.  */
863       slot = htab_find_slot (container->type_hash, type, INSERT);
864       if (*slot != NULL)
865         return;
866       *slot = CONST_CAST (void *, (const void *) type);
867
868       if (!go_format_type (container, TREE_TYPE (decl), false, false))
869         fprintf (go_dump_file, "// ");
870       fprintf (go_dump_file, "type _%s ",
871                IDENTIFIER_POINTER (DECL_NAME (decl)));
872       go_output_type (container);
873       pointer_set_insert (container->decls_seen, decl);
874     }
875   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
876     {
877        void **slot;
878        const char *type;
879
880        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
881        /* If type defined already, skip.  */
882        slot = htab_find_slot (container->type_hash, type, INSERT);
883        if (*slot != NULL)
884          return;
885        *slot = CONST_CAST (void *, (const void *) type);
886
887        if (!go_format_type (container, TREE_TYPE (decl), false, false))
888          fprintf (go_dump_file, "// ");
889        fprintf (go_dump_file, "type _%s ",
890                IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
891        go_output_type (container);
892     }
893   else
894     return;
895
896   fprintf (go_dump_file, "\n");
897 }
898
899 /* Output a variable.  */
900
901 static void
902 go_output_var (struct godump_container *container, tree decl)
903 {
904   bool is_valid;
905
906   if (pointer_set_contains (container->decls_seen, decl)
907       || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
908     return;
909   pointer_set_insert (container->decls_seen, decl);
910   pointer_set_insert (container->decls_seen, DECL_NAME (decl));
911
912   is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
913   if (is_valid
914       && htab_find_slot (container->type_hash,
915                          IDENTIFIER_POINTER (DECL_NAME (decl)),
916                          NO_INSERT) != NULL)
917     {
918       /* There is already a type with this name, probably from a
919          struct tag.  Prefer the type to the variable.  */
920       is_valid = false;
921     }
922   if (!is_valid)
923     fprintf (go_dump_file, "// ");
924
925   fprintf (go_dump_file, "var _%s ",
926            IDENTIFIER_POINTER (DECL_NAME (decl)));
927   go_output_type (container);
928   fprintf (go_dump_file, "\n");
929
930   /* Sometimes an extern variable is declared with an unknown struct
931      type.  */
932   if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
933       && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
934     {
935       tree type_name = TYPE_NAME (TREE_TYPE (decl));
936       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
937         pointer_set_insert (container->pot_dummy_types,
938                             IDENTIFIER_POINTER (type_name));
939       else if (TREE_CODE (type_name) == TYPE_DECL)
940         pointer_set_insert (container->pot_dummy_types,
941                             IDENTIFIER_POINTER (DECL_NAME (type_name)));
942     }
943 }
944
945 /* Build a hash table with the Go keywords.  */
946
947 static const char * const keywords[] = {
948   "__asm__", "break", "case", "chan", "const", "continue", "default",
949   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
950   "import", "interface", "map", "package", "range", "return", "select",
951   "struct", "switch", "type", "var"
952 };
953
954 static void
955 keyword_hash_init (struct godump_container *container)
956 {
957   size_t i;
958   size_t count = sizeof (keywords) / sizeof (keywords[0]);
959   void **slot;
960
961   for (i = 0; i < count; i++)
962     {
963       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
964       *slot = CONST_CAST (void *, (const void *) keywords[i]);
965     }
966 }
967
968 /* Traversing the pot_dummy_types and seeing which types are present
969    in the global types hash table and creating dummy definitions if
970    not found.  This function is invoked by pointer_set_traverse.  */
971
972 static bool
973 find_dummy_types (const void *ptr, void *adata)
974 {
975   struct godump_container *data = (struct godump_container *) adata;
976   const char *type = (const char *) ptr;
977   void **slot;
978
979   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
980   if (slot == NULL)
981     fprintf (go_dump_file, "type _%s struct {}\n", type);
982   return true;
983 }
984
985 /* Output symbols.  */
986
987 static void
988 go_finish (const char *filename)
989 {
990   struct godump_container container;
991   unsigned int ix;
992   tree decl;
993
994   real_debug_hooks->finish (filename);
995
996   container.decls_seen = pointer_set_create ();
997   container.pot_dummy_types = pointer_set_create ();
998   container.type_hash = htab_create (100, htab_hash_string,
999                                      string_hash_eq, NULL);
1000   container.keyword_hash = htab_create (50, htab_hash_string,
1001                                         string_hash_eq, NULL);
1002   obstack_init (&container.type_obstack);
1003
1004   keyword_hash_init (&container);
1005
1006   FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1007     {
1008       switch (TREE_CODE (decl))
1009         {
1010         case FUNCTION_DECL:
1011           go_output_fndecl (&container, decl);
1012           break;
1013
1014         case TYPE_DECL:
1015           go_output_typedef (&container, decl);
1016           break;
1017
1018         case VAR_DECL:
1019           go_output_var (&container, decl);
1020           break;
1021
1022         default:
1023           gcc_unreachable();
1024         }
1025     }
1026
1027   /* To emit dummy definitions.  */
1028   pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1029                         (void *) &container);
1030
1031   pointer_set_destroy (container.decls_seen);
1032   pointer_set_destroy (container.pot_dummy_types);
1033   htab_delete (container.type_hash);
1034   htab_delete (container.keyword_hash);
1035   obstack_free (&container.type_obstack, NULL);
1036
1037   queue = NULL;
1038
1039   if (fclose (go_dump_file) != 0)
1040     error ("could not close Go dump file: %m");
1041   go_dump_file = NULL;
1042 }
1043
1044 /* Set up our hooks.  */
1045
1046 const struct gcc_debug_hooks *
1047 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1048 {
1049   go_dump_file = fopen (filename, "w");
1050   if (go_dump_file == NULL)
1051     {
1052       error ("could not open Go dump file %qs: %m", filename);
1053       return hooks;
1054     }
1055
1056   go_debug_hooks = *hooks;
1057   real_debug_hooks = hooks;
1058
1059   go_debug_hooks.finish = go_finish;
1060   go_debug_hooks.define = go_define;
1061   go_debug_hooks.undef = go_undef;
1062   go_debug_hooks.function_decl = go_function_decl;
1063   go_debug_hooks.global_decl = go_global_decl;
1064   go_debug_hooks.type_decl = go_type_decl;
1065
1066   macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1067
1068   return &go_debug_hooks;
1069 }
1070
1071 #include "gt-godump.h"