OSDN Git Service

* godump.c (go_format_type): Check for invalid type names, pointer
[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             if (DECL_NAME (field) == NULL)
689               {
690                 char buf[100];
691
692                 obstack_grow (ob, "Godump_", 2);
693                 snprintf (buf, sizeof buf, "%d", i);
694                 obstack_grow (ob, buf, strlen (buf));
695                 i++;
696               }
697             else
698               {
699                 const char *var_name;
700                 void **slot;
701
702                 /* Start variable name with an underscore if a keyword.  */
703                 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
704                 slot = htab_find_slot (container->keyword_hash, var_name,
705                                        NO_INSERT);
706                 if (slot != NULL)
707                   obstack_1grow (ob, '_');
708                 go_append_string (ob, DECL_NAME (field));
709               }
710             obstack_1grow (ob, ' ');
711             if (DECL_BIT_FIELD (field))
712               {
713                 obstack_grow (ob, "INVALID-bit-field", 17);
714                 ret = false;
715               }
716             else
717               {
718                 /* Do not expand type if a record or union type or a
719                    function pointer.  */
720                 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
721                     && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
722                         || (POINTER_TYPE_P (TREE_TYPE (field))
723                             && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
724                                 == FUNCTION_TYPE))))
725                   {
726                     tree name;
727                     void **slot;
728
729                     name = TYPE_NAME (TREE_TYPE (field));
730                     if (TREE_CODE (name) == TYPE_DECL)
731                       name = DECL_NAME (name);
732
733                     slot = htab_find_slot (container->invalid_hash,
734                                            IDENTIFIER_POINTER (name),
735                                            NO_INSERT);
736                     if (slot != NULL)
737                       ret = false;
738
739                     obstack_1grow (ob, '_');
740                     go_append_string (ob, name);
741                   }
742                 else
743                   {
744                     if (!go_format_type (container, TREE_TYPE (field), true,
745                                          false))
746                       ret = false;
747                   }
748               }
749             obstack_grow (ob, "; ", 2);
750
751             /* Only output the first field of a union, and hope for
752                the best.  */
753             if (TREE_CODE (type) == UNION_TYPE)
754               break;
755           }
756         obstack_1grow (ob, '}');
757       }
758       break;
759
760     case FUNCTION_TYPE:
761       {
762         tree arg_type;
763         bool is_varargs;
764         tree result;
765         function_args_iterator iter;
766         bool seen_arg;
767
768         /* Go has no way to write a type which is a function but not a
769            pointer to a function.  */
770         if (!is_func_ok)
771           {
772             obstack_grow (ob, "func*", 5);
773             ret = false;
774           }
775
776         obstack_1grow (ob, '(');
777         is_varargs = stdarg_p (type);
778         seen_arg = false;
779         FOREACH_FUNCTION_ARGS (type, arg_type, iter)
780           {
781             if (VOID_TYPE_P (arg_type))
782               break;
783             if (seen_arg)
784               obstack_grow (ob, ", ", 2);
785             if (!go_format_type (container, arg_type, true, false))
786               ret = false;
787             seen_arg = true;
788           }
789         if (is_varargs)
790           {
791             if (prototype_p (type))
792               obstack_grow (ob, ", ", 2);
793             obstack_grow (ob, "...interface{}", 14);
794           }
795         obstack_1grow (ob, ')');
796
797         result = TREE_TYPE (type);
798         if (!VOID_TYPE_P (result))
799           {
800             obstack_1grow (ob, ' ');
801             if (!go_format_type (container, result, use_type_name, false))
802               ret = false;
803           }
804       }
805       break;
806
807     default:
808       obstack_grow (ob, "INVALID-type", 12);
809       ret = false;
810       break;
811     }
812
813   return ret;
814 }
815
816 /* Output the type which was built on the type obstack, and then free
817    it.  */
818
819 static void
820 go_output_type (struct godump_container *container)
821 {
822   struct obstack *ob;
823
824   ob = &container->type_obstack;
825   obstack_1grow (ob, '\0');
826   fputs (obstack_base (ob), go_dump_file);
827   obstack_free (ob, obstack_base (ob));
828 }
829
830 /* Output a function declaration.  */
831
832 static void
833 go_output_fndecl (struct godump_container *container, tree decl)
834 {
835   if (!go_format_type (container, TREE_TYPE (decl), false, true))
836     fprintf (go_dump_file, "// ");
837   fprintf (go_dump_file, "func _%s ",
838            IDENTIFIER_POINTER (DECL_NAME (decl)));
839   go_output_type (container);
840   fprintf (go_dump_file, " __asm__(\"%s\")\n",
841            IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
842 }
843
844 /* Output a typedef or something like a struct definition.  */
845
846 static void
847 go_output_typedef (struct godump_container *container, tree decl)
848 {
849   /* If we have an enum type, output the enum constants
850      separately.  */
851   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
852       && TYPE_SIZE (TREE_TYPE (decl)) != 0
853       && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
854       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
855           || !pointer_set_contains (container->decls_seen,
856                                     TYPE_CANONICAL (TREE_TYPE (decl)))))
857     {
858       tree element;
859
860       for (element = TYPE_VALUES (TREE_TYPE (decl));
861            element != NULL_TREE;
862            element = TREE_CHAIN (element))
863         {
864           const char *name;
865           void **slot;
866
867           name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
868
869           /* Sometimes a name will be defined as both an enum constant
870              and a macro.  Avoid duplicate definition errors by
871              treating enum constants as macros.  */
872           slot = htab_find_slot (macro_hash, name, INSERT);
873           if (*slot == NULL)
874             {
875               *slot = CONST_CAST (char *, name);
876               fprintf (go_dump_file,
877                        "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
878                        name, tree_low_cst (TREE_VALUE (element), 0));
879             }
880         }
881       pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
882       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
883         pointer_set_insert (container->decls_seen,
884                             TYPE_CANONICAL (TREE_TYPE (decl)));
885     }
886
887   if (DECL_NAME (decl) != NULL_TREE)
888     {
889       void **slot;
890       const char *type;
891
892       type = IDENTIFIER_POINTER (DECL_NAME (decl));
893       /* If type defined already, skip.  */
894       slot = htab_find_slot (container->type_hash, type, INSERT);
895       if (*slot != NULL)
896         return;
897       *slot = CONST_CAST (void *, (const void *) type);
898
899       if (!go_format_type (container, TREE_TYPE (decl), false, false))
900         {
901           fprintf (go_dump_file, "// ");
902           slot = htab_find_slot (container->invalid_hash, type, INSERT);
903           *slot = CONST_CAST (void *, (const void *) type);
904         }
905       fprintf (go_dump_file, "type _%s ",
906                IDENTIFIER_POINTER (DECL_NAME (decl)));
907       go_output_type (container);
908       pointer_set_insert (container->decls_seen, decl);
909     }
910   else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
911     {
912        void **slot;
913        const char *type;
914
915        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
916        /* If type defined already, skip.  */
917        slot = htab_find_slot (container->type_hash, type, INSERT);
918        if (*slot != NULL)
919          return;
920        *slot = CONST_CAST (void *, (const void *) type);
921
922        if (!go_format_type (container, TREE_TYPE (decl), false, false))
923          {
924            fprintf (go_dump_file, "// ");
925            slot = htab_find_slot (container->invalid_hash, type, INSERT);
926            *slot = CONST_CAST (void *, (const void *) type);
927          }
928        fprintf (go_dump_file, "type _%s ",
929                IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
930        go_output_type (container);
931     }
932   else
933     return;
934
935   fprintf (go_dump_file, "\n");
936 }
937
938 /* Output a variable.  */
939
940 static void
941 go_output_var (struct godump_container *container, tree decl)
942 {
943   bool is_valid;
944
945   if (pointer_set_contains (container->decls_seen, decl)
946       || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
947     return;
948   pointer_set_insert (container->decls_seen, decl);
949   pointer_set_insert (container->decls_seen, DECL_NAME (decl));
950
951   is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
952   if (is_valid
953       && htab_find_slot (container->type_hash,
954                          IDENTIFIER_POINTER (DECL_NAME (decl)),
955                          NO_INSERT) != NULL)
956     {
957       /* There is already a type with this name, probably from a
958          struct tag.  Prefer the type to the variable.  */
959       is_valid = false;
960     }
961   if (!is_valid)
962     fprintf (go_dump_file, "// ");
963
964   fprintf (go_dump_file, "var _%s ",
965            IDENTIFIER_POINTER (DECL_NAME (decl)));
966   go_output_type (container);
967   fprintf (go_dump_file, "\n");
968
969   /* Sometimes an extern variable is declared with an unknown struct
970      type.  */
971   if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
972       && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
973     {
974       tree type_name = TYPE_NAME (TREE_TYPE (decl));
975       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
976         pointer_set_insert (container->pot_dummy_types,
977                             IDENTIFIER_POINTER (type_name));
978       else if (TREE_CODE (type_name) == TYPE_DECL)
979         pointer_set_insert (container->pot_dummy_types,
980                             IDENTIFIER_POINTER (DECL_NAME (type_name)));
981     }
982 }
983
984 /* Build a hash table with the Go keywords.  */
985
986 static const char * const keywords[] = {
987   "__asm__", "break", "case", "chan", "const", "continue", "default",
988   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
989   "import", "interface", "map", "package", "range", "return", "select",
990   "struct", "switch", "type", "var"
991 };
992
993 static void
994 keyword_hash_init (struct godump_container *container)
995 {
996   size_t i;
997   size_t count = sizeof (keywords) / sizeof (keywords[0]);
998   void **slot;
999
1000   for (i = 0; i < count; i++)
1001     {
1002       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1003       *slot = CONST_CAST (void *, (const void *) keywords[i]);
1004     }
1005 }
1006
1007 /* Traversing the pot_dummy_types and seeing which types are present
1008    in the global types hash table and creating dummy definitions if
1009    not found.  This function is invoked by pointer_set_traverse.  */
1010
1011 static bool
1012 find_dummy_types (const void *ptr, void *adata)
1013 {
1014   struct godump_container *data = (struct godump_container *) adata;
1015   const char *type = (const char *) ptr;
1016   void **slot;
1017
1018   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1019   if (slot == NULL)
1020     fprintf (go_dump_file, "type _%s struct {}\n", type);
1021   return true;
1022 }
1023
1024 /* Output symbols.  */
1025
1026 static void
1027 go_finish (const char *filename)
1028 {
1029   struct godump_container container;
1030   unsigned int ix;
1031   tree decl;
1032
1033   real_debug_hooks->finish (filename);
1034
1035   container.decls_seen = pointer_set_create ();
1036   container.pot_dummy_types = pointer_set_create ();
1037   container.type_hash = htab_create (100, htab_hash_string,
1038                                      string_hash_eq, NULL);
1039   container.invalid_hash = htab_create (10, htab_hash_string,
1040                                         string_hash_eq, NULL);
1041   container.keyword_hash = htab_create (50, htab_hash_string,
1042                                         string_hash_eq, NULL);
1043   obstack_init (&container.type_obstack);
1044
1045   keyword_hash_init (&container);
1046
1047   FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1048     {
1049       switch (TREE_CODE (decl))
1050         {
1051         case FUNCTION_DECL:
1052           go_output_fndecl (&container, decl);
1053           break;
1054
1055         case TYPE_DECL:
1056           go_output_typedef (&container, decl);
1057           break;
1058
1059         case VAR_DECL:
1060           go_output_var (&container, decl);
1061           break;
1062
1063         default:
1064           gcc_unreachable();
1065         }
1066     }
1067
1068   /* To emit dummy definitions.  */
1069   pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1070                         (void *) &container);
1071
1072   pointer_set_destroy (container.decls_seen);
1073   pointer_set_destroy (container.pot_dummy_types);
1074   htab_delete (container.type_hash);
1075   htab_delete (container.invalid_hash);
1076   htab_delete (container.keyword_hash);
1077   obstack_free (&container.type_obstack, NULL);
1078
1079   queue = NULL;
1080
1081   if (fclose (go_dump_file) != 0)
1082     error ("could not close Go dump file: %m");
1083   go_dump_file = NULL;
1084 }
1085
1086 /* Set up our hooks.  */
1087
1088 const struct gcc_debug_hooks *
1089 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1090 {
1091   go_dump_file = fopen (filename, "w");
1092   if (go_dump_file == NULL)
1093     {
1094       error ("could not open Go dump file %qs: %m", filename);
1095       return hooks;
1096     }
1097
1098   go_debug_hooks = *hooks;
1099   real_debug_hooks = hooks;
1100
1101   go_debug_hooks.finish = go_finish;
1102   go_debug_hooks.define = go_define;
1103   go_debug_hooks.undef = go_undef;
1104   go_debug_hooks.function_decl = go_function_decl;
1105   go_debug_hooks.global_decl = go_global_decl;
1106   go_debug_hooks.type_decl = go_type_decl;
1107
1108   macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1109
1110   return &go_debug_hooks;
1111 }
1112
1113 #include "gt-godump.h"