OSDN Git Service

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