PR target/50465
[official-gcc.git] / gcc / godump.c
blob11cd32998ec92f737e225e5cbcd4e1d2759116f8
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>.
5 This file is part of GCC.
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.
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.
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/>. */
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.
27 All global names are output with a leading underscore, so that they
28 are all hidden in Go. */
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"
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. */
45 /* Our debug hooks. This is initialized by dump_go_spec_init. */
47 static struct gcc_debug_hooks go_debug_hooks;
49 /* The real debug hooks. */
51 static const struct gcc_debug_hooks *real_debug_hooks;
53 /* The file where we should write information. */
55 static FILE *go_dump_file;
57 /* A queue of decls to output. */
59 static GTY(()) VEC(tree,gc) *queue;
61 /* A hash table of macros we have seen. */
63 static htab_t macro_hash;
65 /* For the hash tables. */
67 static int
68 string_hash_eq (const void *y1, const void *y2)
70 return strcmp ((const char *) y1, (const char *) y2) == 0;
73 /* A macro definition. */
75 static void
76 go_define (unsigned int lineno, const char *buffer)
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;
88 real_debug_hooks->define (lineno, buffer);
90 /* Skip macro functions. */
91 for (p = buffer; *p != '\0' && *p != ' '; ++p)
92 if (*p == '(')
93 return;
95 if (*p == '\0')
96 return;
98 name_end = p;
100 ++p;
101 if (*p == '\0')
102 return;
104 copy = XNEWVEC (char, name_end - buffer + 1);
105 memcpy (copy, buffer, name_end - buffer);
106 copy[name_end - buffer] = '\0';
108 hashval = htab_hash_string (copy);
109 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
110 if (slot != NULL)
112 XDELETEVEC (copy);
113 return;
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')
124 switch (*p)
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 '_':
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;
145 if (saw_operand)
146 goto unknown;
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)
157 /* This is a reference to a name which was not defined
158 as a macro. */
159 goto unknown;
162 *q++ = '_';
163 memcpy (q, start, p - start);
164 q += p - start;
166 saw_operand = true;
167 need_operand = false;
169 break;
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':
178 const char *start;
179 bool is_hex;
181 start = p;
182 is_hex = false;
183 if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
185 p += 2;
186 is_hex = true;
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')
199 /* Go doesn't use any of these trailing type
200 modifiers. */
201 ++p;
204 /* We'll pick up the exponent, if any, as an
205 expression. */
207 saw_operand = true;
208 need_operand = false;
210 break;
212 case ' ': case '\t':
213 *q++ = *p++;
214 break;
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;
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;
233 case '+': case '-':
234 /* Always OK, but not part of an operand. */
235 *q++ = *p++;
236 saw_operand = false;
237 break;
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;
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;
260 case '!':
261 *q++ = *p++;
262 if (*p == '=')
264 /* Must be a binary operator. */
265 if (!saw_operand)
266 goto unknown;
267 *q++ = *p++;
268 saw_operand = false;
269 need_operand = true;
271 else
273 /* Must be a unary operator. */
274 if (saw_operand)
275 goto unknown;
276 need_operand = true;
278 break;
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;
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;
300 case '"':
301 case '\'':
303 char quote;
304 int count;
306 if (saw_operand)
307 goto unknown;
308 quote = *p;
309 *q++ = *p++;
310 count = 0;
311 while (*p != quote)
313 int c;
315 if (*p == '\0')
316 goto unknown;
318 ++count;
320 if (*p != '\\')
322 *q++ = *p++;
323 continue;
326 *q++ = *p++;
327 switch (*p)
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')
334 *q++ = *p++;
335 ++c;
337 /* Go octal characters are always 3
338 digits. */
339 if (c != 3)
340 goto unknown;
341 break;
343 case 'x':
344 *q++ = *p++;
345 c = 0;
346 while (ISXDIGIT (*p))
348 *q++ = *p++;
349 ++c;
351 /* Go hex characters are always 2 digits. */
352 if (c != 2)
353 goto unknown;
354 break;
356 case 'a': case 'b': case 'f': case 'n': case 'r':
357 case 't': case 'v': case '\\': case '\'': case '"':
358 *q++ = *p++;
359 break;
361 default:
362 goto unknown;
366 *q++ = *p++;
368 if (quote == '\'' && count != 1)
369 goto unknown;
371 saw_operand = true;
372 need_operand = false;
374 break;
377 default:
378 goto unknown;
382 if (need_operand)
383 goto unknown;
385 *q = '\0';
387 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
388 *slot = copy;
390 fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
392 XDELETEVEC (out_buffer);
393 return;
395 unknown:
396 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
397 XDELETEVEC (out_buffer);
398 XDELETEVEC (copy);
401 /* A macro undef. */
403 static void
404 go_undef (unsigned int lineno, const char *buffer)
406 void **slot;
408 real_debug_hooks->undef (lineno, buffer);
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. */
418 /* A function or variable decl. */
420 static void
421 go_decl (tree decl)
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);
430 /* A function decl. */
432 static void
433 go_function_decl (tree decl)
435 real_debug_hooks->function_decl (decl);
436 go_decl (decl);
439 /* A global variable decl. */
441 static void
442 go_global_decl (tree decl)
444 real_debug_hooks->global_decl (decl);
445 go_decl (decl);
448 /* A type declaration. */
450 static void
451 go_type_decl (tree decl, int local)
453 real_debug_hooks->type_decl (decl, local);
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);
465 /* A container for the data we pass around when generating information
466 at the end of the compilation. */
468 struct godump_container
470 /* DECLs that we have already seen. */
471 struct pointer_set_t *decls_seen;
473 /* Types which may potentially have to be defined as dummy
474 types. */
475 struct pointer_set_t *pot_dummy_types;
477 /* Go keywords. */
478 htab_t keyword_hash;
480 /* Global type definitions. */
481 htab_t type_hash;
483 /* Invalid types. */
484 htab_t invalid_hash;
486 /* Obstack used to write out a type definition. */
487 struct obstack type_obstack;
490 /* Append an IDENTIFIER_NODE to OB. */
492 static void
493 go_append_string (struct obstack *ob, tree id)
495 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
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. */
504 static bool
505 go_format_type (struct godump_container *container, tree type,
506 bool use_type_name, bool is_func_ok)
508 bool ret;
509 struct obstack *ob;
511 ret = true;
512 ob = &container->type_obstack;
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))
521 tree name;
522 void **slot;
524 name = TYPE_NAME (type);
525 if (TREE_CODE (name) == TYPE_DECL)
526 name = DECL_NAME (name);
528 slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
529 NO_INSERT);
530 if (slot != NULL)
531 ret = false;
533 obstack_1grow (ob, '_');
534 go_append_string (ob, name);
535 return ret;
538 pointer_set_insert (container->decls_seen, type);
540 switch (TREE_CODE (type))
542 case ENUMERAL_TYPE:
543 obstack_grow (ob, "int", 3);
544 break;
546 case TYPE_DECL:
548 void **slot;
550 slot = htab_find_slot (container->invalid_hash,
551 IDENTIFIER_POINTER (DECL_NAME (type)),
552 NO_INSERT);
553 if (slot != NULL)
554 ret = false;
556 obstack_1grow (ob, '_');
557 go_append_string (ob, DECL_NAME (type));
559 break;
561 case INTEGER_TYPE:
563 const char *s;
564 char buf[100];
566 switch (TYPE_PRECISION (type))
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;
588 obstack_grow (ob, s, strlen (s));
590 break;
592 case REAL_TYPE:
594 const char *s;
595 char buf[100];
597 switch (TYPE_PRECISION (type))
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;
612 obstack_grow (ob, s, strlen (s));
614 break;
616 case BOOLEAN_TYPE:
617 obstack_grow (ob, "bool", 4);
618 break;
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))))
628 tree name;
629 void **slot;
631 name = TYPE_NAME (TREE_TYPE (type));
632 if (TREE_CODE (name) == TYPE_DECL)
633 name = DECL_NAME (name);
635 slot = htab_find_slot (container->invalid_hash,
636 IDENTIFIER_POINTER (name), NO_INSERT);
637 if (slot != NULL)
638 ret = false;
640 obstack_grow (ob, "*_", 2);
641 go_append_string (ob, name);
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));
650 return ret;
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
660 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
661 true))
662 ret = false;
664 break;
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))
677 char buf[100];
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));
683 obstack_1grow (ob, ']');
684 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
685 ret = false;
686 break;
688 case UNION_TYPE:
689 case RECORD_TYPE:
691 tree field;
692 int i;
694 obstack_grow (ob, "struct { ", 9);
695 i = 0;
696 for (field = TYPE_FIELDS (type);
697 field != NULL_TREE;
698 field = TREE_CHAIN (field))
700 struct obstack hold_type_obstack;
701 bool field_ok;
703 if (TREE_CODE (type) == UNION_TYPE)
705 hold_type_obstack = container->type_obstack;
706 obstack_init (&container->type_obstack);
709 field_ok = true;
711 if (DECL_NAME (field) == NULL)
713 char buf[100];
715 obstack_grow (ob, "Godump_", 7);
716 snprintf (buf, sizeof buf, "%d", i);
717 obstack_grow (ob, buf, strlen (buf));
718 i++;
720 else
722 const char *var_name;
723 void **slot;
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));
733 obstack_1grow (ob, ' ');
734 if (DECL_BIT_FIELD (field))
736 obstack_grow (ob, "INVALID-bit-field", 17);
737 field_ok = false;
739 else
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))))
749 tree name;
750 void **slot;
752 name = TYPE_NAME (TREE_TYPE (field));
753 if (TREE_CODE (name) == TYPE_DECL)
754 name = DECL_NAME (name);
756 slot = htab_find_slot (container->invalid_hash,
757 IDENTIFIER_POINTER (name),
758 NO_INSERT);
759 if (slot != NULL)
760 field_ok = false;
762 obstack_1grow (ob, '_');
763 go_append_string (ob, name);
765 else
767 if (!go_format_type (container, TREE_TYPE (field), true,
768 false))
769 field_ok = false;
772 obstack_grow (ob, "; ", 2);
774 /* Only output the first successful field of a union, and
775 hope for the best. */
776 if (TREE_CODE (type) == UNION_TYPE)
778 if (!field_ok && TREE_CHAIN (field) == NULL_TREE)
780 field_ok = true;
781 ret = false;
783 if (field_ok)
785 unsigned int sz;
787 sz = obstack_object_size (&container->type_obstack);
788 obstack_grow (&hold_type_obstack,
789 obstack_base (&container->type_obstack),
790 sz);
792 obstack_free (&container->type_obstack, NULL);
793 container->type_obstack = hold_type_obstack;
794 if (field_ok)
795 break;
797 else
799 if (!field_ok)
800 ret = false;
803 obstack_1grow (ob, '}');
805 break;
807 case FUNCTION_TYPE:
809 tree arg_type;
810 bool is_varargs;
811 tree result;
812 function_args_iterator iter;
813 bool seen_arg;
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)
819 obstack_grow (ob, "func*", 5);
820 ret = false;
823 obstack_1grow (ob, '(');
824 is_varargs = stdarg_p (type);
825 seen_arg = false;
826 FOREACH_FUNCTION_ARGS (type, arg_type, iter)
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;
836 if (is_varargs)
838 if (prototype_p (type))
839 obstack_grow (ob, ", ", 2);
840 obstack_grow (ob, "...interface{}", 14);
842 obstack_1grow (ob, ')');
844 result = TREE_TYPE (type);
845 if (!VOID_TYPE_P (result))
847 obstack_1grow (ob, ' ');
848 if (!go_format_type (container, result, use_type_name, false))
849 ret = false;
852 break;
854 default:
855 obstack_grow (ob, "INVALID-type", 12);
856 ret = false;
857 break;
860 return ret;
863 /* Output the type which was built on the type obstack, and then free
864 it. */
866 static void
867 go_output_type (struct godump_container *container)
869 struct obstack *ob;
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));
877 /* Output a function declaration. */
879 static void
880 go_output_fndecl (struct godump_container *container, tree decl)
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)));
891 /* Output a typedef or something like a struct definition. */
893 static void
894 go_output_typedef (struct godump_container *container, tree decl)
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)))))
905 tree element;
907 for (element = TYPE_VALUES (TREE_TYPE (decl));
908 element != NULL_TREE;
909 element = TREE_CHAIN (element))
911 const char *name;
912 void **slot;
914 name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
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)
922 *slot = CONST_CAST (char *, name);
923 fprintf (go_dump_file,
924 "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
925 name, tree_low_cst (TREE_VALUE (element), 0));
928 pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
929 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
930 pointer_set_insert (container->decls_seen,
931 TYPE_CANONICAL (TREE_TYPE (decl)));
934 if (DECL_NAME (decl) != NULL_TREE)
936 void **slot;
937 const char *type;
939 type = IDENTIFIER_POINTER (DECL_NAME (decl));
940 /* If type defined already, skip. */
941 slot = htab_find_slot (container->type_hash, type, INSERT);
942 if (*slot != NULL)
943 return;
944 *slot = CONST_CAST (void *, (const void *) type);
946 if (!go_format_type (container, TREE_TYPE (decl), false, false))
948 fprintf (go_dump_file, "// ");
949 slot = htab_find_slot (container->invalid_hash, type, INSERT);
950 *slot = CONST_CAST (void *, (const void *) type);
952 fprintf (go_dump_file, "type _%s ",
953 IDENTIFIER_POINTER (DECL_NAME (decl)));
954 go_output_type (container);
955 pointer_set_insert (container->decls_seen, decl);
957 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
959 void **slot;
960 const char *type;
962 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
963 /* If type defined already, skip. */
964 slot = htab_find_slot (container->type_hash, type, INSERT);
965 if (*slot != NULL)
966 return;
967 *slot = CONST_CAST (void *, (const void *) type);
969 if (!go_format_type (container, TREE_TYPE (decl), false, false))
971 fprintf (go_dump_file, "// ");
972 slot = htab_find_slot (container->invalid_hash, type, INSERT);
973 *slot = CONST_CAST (void *, (const void *) type);
975 fprintf (go_dump_file, "type _%s ",
976 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
977 go_output_type (container);
979 else
980 return;
982 fprintf (go_dump_file, "\n");
985 /* Output a variable. */
987 static void
988 go_output_var (struct godump_container *container, tree decl)
990 bool is_valid;
992 if (pointer_set_contains (container->decls_seen, decl)
993 || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
994 return;
995 pointer_set_insert (container->decls_seen, decl);
996 pointer_set_insert (container->decls_seen, DECL_NAME (decl));
998 is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
999 if (is_valid
1000 && htab_find_slot (container->type_hash,
1001 IDENTIFIER_POINTER (DECL_NAME (decl)),
1002 NO_INSERT) != NULL)
1004 /* There is already a type with this name, probably from a
1005 struct tag. Prefer the type to the variable. */
1006 is_valid = false;
1008 if (!is_valid)
1009 fprintf (go_dump_file, "// ");
1011 fprintf (go_dump_file, "var _%s ",
1012 IDENTIFIER_POINTER (DECL_NAME (decl)));
1013 go_output_type (container);
1014 fprintf (go_dump_file, "\n");
1016 /* Sometimes an extern variable is declared with an unknown struct
1017 type. */
1018 if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
1019 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1021 tree type_name = TYPE_NAME (TREE_TYPE (decl));
1022 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1023 pointer_set_insert (container->pot_dummy_types,
1024 IDENTIFIER_POINTER (type_name));
1025 else if (TREE_CODE (type_name) == TYPE_DECL)
1026 pointer_set_insert (container->pot_dummy_types,
1027 IDENTIFIER_POINTER (DECL_NAME (type_name)));
1031 /* Build a hash table with the Go keywords. */
1033 static const char * const keywords[] = {
1034 "__asm__", "break", "case", "chan", "const", "continue", "default",
1035 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1036 "import", "interface", "map", "package", "range", "return", "select",
1037 "struct", "switch", "type", "var"
1040 static void
1041 keyword_hash_init (struct godump_container *container)
1043 size_t i;
1044 size_t count = sizeof (keywords) / sizeof (keywords[0]);
1045 void **slot;
1047 for (i = 0; i < count; i++)
1049 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1050 *slot = CONST_CAST (void *, (const void *) keywords[i]);
1054 /* Traversing the pot_dummy_types and seeing which types are present
1055 in the global types hash table and creating dummy definitions if
1056 not found. This function is invoked by pointer_set_traverse. */
1058 static bool
1059 find_dummy_types (const void *ptr, void *adata)
1061 struct godump_container *data = (struct godump_container *) adata;
1062 const char *type = (const char *) ptr;
1063 void **slot;
1065 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1066 if (slot == NULL)
1067 fprintf (go_dump_file, "type _%s struct {}\n", type);
1068 return true;
1071 /* Output symbols. */
1073 static void
1074 go_finish (const char *filename)
1076 struct godump_container container;
1077 unsigned int ix;
1078 tree decl;
1080 real_debug_hooks->finish (filename);
1082 container.decls_seen = pointer_set_create ();
1083 container.pot_dummy_types = pointer_set_create ();
1084 container.type_hash = htab_create (100, htab_hash_string,
1085 string_hash_eq, NULL);
1086 container.invalid_hash = htab_create (10, htab_hash_string,
1087 string_hash_eq, NULL);
1088 container.keyword_hash = htab_create (50, htab_hash_string,
1089 string_hash_eq, NULL);
1090 obstack_init (&container.type_obstack);
1092 keyword_hash_init (&container);
1094 FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1096 switch (TREE_CODE (decl))
1098 case FUNCTION_DECL:
1099 go_output_fndecl (&container, decl);
1100 break;
1102 case TYPE_DECL:
1103 go_output_typedef (&container, decl);
1104 break;
1106 case VAR_DECL:
1107 go_output_var (&container, decl);
1108 break;
1110 default:
1111 gcc_unreachable();
1115 /* To emit dummy definitions. */
1116 pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1117 (void *) &container);
1119 pointer_set_destroy (container.decls_seen);
1120 pointer_set_destroy (container.pot_dummy_types);
1121 htab_delete (container.type_hash);
1122 htab_delete (container.invalid_hash);
1123 htab_delete (container.keyword_hash);
1124 obstack_free (&container.type_obstack, NULL);
1126 queue = NULL;
1128 if (fclose (go_dump_file) != 0)
1129 error ("could not close Go dump file: %m");
1130 go_dump_file = NULL;
1133 /* Set up our hooks. */
1135 const struct gcc_debug_hooks *
1136 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1138 go_dump_file = fopen (filename, "w");
1139 if (go_dump_file == NULL)
1141 error ("could not open Go dump file %qs: %m", filename);
1142 return hooks;
1145 go_debug_hooks = *hooks;
1146 real_debug_hooks = hooks;
1148 go_debug_hooks.finish = go_finish;
1149 go_debug_hooks.define = go_define;
1150 go_debug_hooks.undef = go_undef;
1151 go_debug_hooks.function_decl = go_function_decl;
1152 go_debug_hooks.global_decl = go_global_decl;
1153 go_debug_hooks.type_decl = go_type_decl;
1155 macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1157 return &go_debug_hooks;
1160 #include "gt-godump.h"