OSDN Git Service

* gcc.dg/ipa/ipa-sra-2.c: Add dg-require-effective-target
[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, "const _%s = ", name);
924               if (host_integerp (TREE_VALUE (element), 0))
925                 fprintf (go_dump_file, HOST_WIDE_INT_PRINT_DEC,
926                          tree_low_cst (TREE_VALUE (element), 0));
927               else if (host_integerp (TREE_VALUE (element), 1))
928                 fprintf (go_dump_file, HOST_WIDE_INT_PRINT_UNSIGNED,
929                          ((unsigned HOST_WIDE_INT)
930                           tree_low_cst (TREE_VALUE (element), 1)));
931               else
932                 fprintf (go_dump_file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
933                          ((unsigned HOST_WIDE_INT)
934                           TREE_INT_CST_HIGH (TREE_VALUE (element))),
935                          TREE_INT_CST_LOW (TREE_VALUE (element)));
936               fprintf (go_dump_file, "\n");
937             }
938         }
939       pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
940       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
941         pointer_set_insert (container->decls_seen,
942                             TYPE_CANONICAL (TREE_TYPE (decl)));
943     }
944
945   if (DECL_NAME (decl) != NULL_TREE)
946     {
947       void **slot;
948       const char *type;
949
950       type = IDENTIFIER_POINTER (DECL_NAME (decl));
951       /* If type defined already, skip.  */
952       slot = htab_find_slot (container->type_hash, type, INSERT);
953       if (*slot != NULL)
954         return;
955       *slot = CONST_CAST (void *, (const void *) type);
956
957       if (!go_format_type (container, TREE_TYPE (decl), false, false))
958         {
959           fprintf (go_dump_file, "// ");
960           slot = htab_find_slot (container->invalid_hash, type, INSERT);
961           *slot = CONST_CAST (void *, (const void *) type);
962         }
963       fprintf (go_dump_file, "type _%s ",
964                IDENTIFIER_POINTER (DECL_NAME (decl)));
965       go_output_type (container);
966       pointer_set_insert (container->decls_seen, decl);
967     }
968   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
969     {
970        void **slot;
971        const char *type;
972
973        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
974        /* If type defined already, skip.  */
975        slot = htab_find_slot (container->type_hash, type, INSERT);
976        if (*slot != NULL)
977          return;
978        *slot = CONST_CAST (void *, (const void *) type);
979
980        if (!go_format_type (container, TREE_TYPE (decl), false, false))
981          {
982            fprintf (go_dump_file, "// ");
983            slot = htab_find_slot (container->invalid_hash, type, INSERT);
984            *slot = CONST_CAST (void *, (const void *) type);
985          }
986        fprintf (go_dump_file, "type _%s ",
987                IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
988        go_output_type (container);
989     }
990   else
991     return;
992
993   fprintf (go_dump_file, "\n");
994 }
995
996 /* Output a variable.  */
997
998 static void
999 go_output_var (struct godump_container *container, tree decl)
1000 {
1001   bool is_valid;
1002
1003   if (pointer_set_contains (container->decls_seen, decl)
1004       || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
1005     return;
1006   pointer_set_insert (container->decls_seen, decl);
1007   pointer_set_insert (container->decls_seen, DECL_NAME (decl));
1008
1009   is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
1010   if (is_valid
1011       && htab_find_slot (container->type_hash,
1012                          IDENTIFIER_POINTER (DECL_NAME (decl)),
1013                          NO_INSERT) != NULL)
1014     {
1015       /* There is already a type with this name, probably from a
1016          struct tag.  Prefer the type to the variable.  */
1017       is_valid = false;
1018     }
1019   if (!is_valid)
1020     fprintf (go_dump_file, "// ");
1021
1022   fprintf (go_dump_file, "var _%s ",
1023            IDENTIFIER_POINTER (DECL_NAME (decl)));
1024   go_output_type (container);
1025   fprintf (go_dump_file, "\n");
1026
1027   /* Sometimes an extern variable is declared with an unknown struct
1028      type.  */
1029   if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
1030       && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1031     {
1032       tree type_name = TYPE_NAME (TREE_TYPE (decl));
1033       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1034         pointer_set_insert (container->pot_dummy_types,
1035                             IDENTIFIER_POINTER (type_name));
1036       else if (TREE_CODE (type_name) == TYPE_DECL)
1037         pointer_set_insert (container->pot_dummy_types,
1038                             IDENTIFIER_POINTER (DECL_NAME (type_name)));
1039     }
1040 }
1041
1042 /* Build a hash table with the Go keywords.  */
1043
1044 static const char * const keywords[] = {
1045   "__asm__", "break", "case", "chan", "const", "continue", "default",
1046   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1047   "import", "interface", "map", "package", "range", "return", "select",
1048   "struct", "switch", "type", "var"
1049 };
1050
1051 static void
1052 keyword_hash_init (struct godump_container *container)
1053 {
1054   size_t i;
1055   size_t count = sizeof (keywords) / sizeof (keywords[0]);
1056   void **slot;
1057
1058   for (i = 0; i < count; i++)
1059     {
1060       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1061       *slot = CONST_CAST (void *, (const void *) keywords[i]);
1062     }
1063 }
1064
1065 /* Traversing the pot_dummy_types and seeing which types are present
1066    in the global types hash table and creating dummy definitions if
1067    not found.  This function is invoked by pointer_set_traverse.  */
1068
1069 static bool
1070 find_dummy_types (const void *ptr, void *adata)
1071 {
1072   struct godump_container *data = (struct godump_container *) adata;
1073   const char *type = (const char *) ptr;
1074   void **slot;
1075
1076   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1077   if (slot == NULL)
1078     fprintf (go_dump_file, "type _%s struct {}\n", type);
1079   return true;
1080 }
1081
1082 /* Output symbols.  */
1083
1084 static void
1085 go_finish (const char *filename)
1086 {
1087   struct godump_container container;
1088   unsigned int ix;
1089   tree decl;
1090
1091   real_debug_hooks->finish (filename);
1092
1093   container.decls_seen = pointer_set_create ();
1094   container.pot_dummy_types = pointer_set_create ();
1095   container.type_hash = htab_create (100, htab_hash_string,
1096                                      string_hash_eq, NULL);
1097   container.invalid_hash = htab_create (10, htab_hash_string,
1098                                         string_hash_eq, NULL);
1099   container.keyword_hash = htab_create (50, htab_hash_string,
1100                                         string_hash_eq, NULL);
1101   obstack_init (&container.type_obstack);
1102
1103   keyword_hash_init (&container);
1104
1105   FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1106     {
1107       switch (TREE_CODE (decl))
1108         {
1109         case FUNCTION_DECL:
1110           go_output_fndecl (&container, decl);
1111           break;
1112
1113         case TYPE_DECL:
1114           go_output_typedef (&container, decl);
1115           break;
1116
1117         case VAR_DECL:
1118           go_output_var (&container, decl);
1119           break;
1120
1121         default:
1122           gcc_unreachable();
1123         }
1124     }
1125
1126   /* To emit dummy definitions.  */
1127   pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1128                         (void *) &container);
1129
1130   pointer_set_destroy (container.decls_seen);
1131   pointer_set_destroy (container.pot_dummy_types);
1132   htab_delete (container.type_hash);
1133   htab_delete (container.invalid_hash);
1134   htab_delete (container.keyword_hash);
1135   obstack_free (&container.type_obstack, NULL);
1136
1137   queue = NULL;
1138
1139   if (fclose (go_dump_file) != 0)
1140     error ("could not close Go dump file: %m");
1141   go_dump_file = NULL;
1142 }
1143
1144 /* Set up our hooks.  */
1145
1146 const struct gcc_debug_hooks *
1147 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1148 {
1149   go_dump_file = fopen (filename, "w");
1150   if (go_dump_file == NULL)
1151     {
1152       error ("could not open Go dump file %qs: %m", filename);
1153       return hooks;
1154     }
1155
1156   go_debug_hooks = *hooks;
1157   real_debug_hooks = hooks;
1158
1159   go_debug_hooks.finish = go_finish;
1160   go_debug_hooks.define = go_define;
1161   go_debug_hooks.undef = go_undef;
1162   go_debug_hooks.function_decl = go_function_decl;
1163   go_debug_hooks.global_decl = go_global_decl;
1164   go_debug_hooks.type_decl = go_type_decl;
1165
1166   macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1167
1168   return &go_debug_hooks;
1169 }
1170
1171 #include "gt-godump.h"