godump.c (go_output_typedef): Support printing enum values that don't fit in a signed...
[gcc.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"