2011-08-19 Andrew Stubbs <ams@codesourcery.com>
[official-gcc.git] / gcc / godump.c
blob3f78eead279446ab84e84d50430337a1a92b5c20
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;
305 if (saw_operand)
306 goto unknown;
307 quote = *p;
308 *q++ = *p++;
309 while (*p != quote)
311 int c;
313 if (*p == '\0')
314 goto unknown;
316 if (*p != '\\')
318 *q++ = *p++;
319 continue;
322 *q++ = *p++;
323 switch (*p)
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')
330 *q++ = *p++;
331 ++c;
333 /* Go octal characters are always 3
334 digits. */
335 if (c != 3)
336 goto unknown;
337 break;
339 case 'x':
340 *q++ = *p++;
341 c = 0;
342 while (ISXDIGIT (*p))
344 *q++ = *p++;
345 ++c;
347 /* Go hex characters are always 2 digits. */
348 if (c != 2)
349 goto unknown;
350 break;
352 case 'a': case 'b': case 'f': case 'n': case 'r':
353 case 't': case 'v': case '\\': case '\'': case '"':
354 *q++ = *p++;
355 break;
357 default:
358 goto unknown;
361 *q++ = *p++;
362 break;
365 default:
366 goto unknown;
370 if (need_operand)
371 goto unknown;
373 *q = '\0';
375 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
376 *slot = copy;
378 fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
380 XDELETEVEC (out_buffer);
381 return;
383 unknown:
384 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
385 XDELETEVEC (out_buffer);
386 XDELETEVEC (copy);
389 /* A macro undef. */
391 static void
392 go_undef (unsigned int lineno, const char *buffer)
394 void **slot;
396 real_debug_hooks->undef (lineno, buffer);
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. */
406 /* A function or variable decl. */
408 static void
409 go_decl (tree decl)
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);
418 /* A function decl. */
420 static void
421 go_function_decl (tree decl)
423 real_debug_hooks->function_decl (decl);
424 go_decl (decl);
427 /* A global variable decl. */
429 static void
430 go_global_decl (tree decl)
432 real_debug_hooks->global_decl (decl);
433 go_decl (decl);
436 /* A type declaration. */
438 static void
439 go_type_decl (tree decl, int local)
441 real_debug_hooks->type_decl (decl, local);
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);
453 /* A container for the data we pass around when generating information
454 at the end of the compilation. */
456 struct godump_container
458 /* DECLs that we have already seen. */
459 struct pointer_set_t *decls_seen;
461 /* Types which may potentially have to be defined as dummy
462 types. */
463 struct pointer_set_t *pot_dummy_types;
465 /* Go keywords. */
466 htab_t keyword_hash;
468 /* Global type definitions. */
469 htab_t type_hash;
471 /* Invalid types. */
472 htab_t invalid_hash;
474 /* Obstack used to write out a type definition. */
475 struct obstack type_obstack;
478 /* Append an IDENTIFIER_NODE to OB. */
480 static void
481 go_append_string (struct obstack *ob, tree id)
483 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
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. */
492 static bool
493 go_format_type (struct godump_container *container, tree type,
494 bool use_type_name, bool is_func_ok)
496 bool ret;
497 struct obstack *ob;
499 ret = true;
500 ob = &container->type_obstack;
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))
509 tree name;
510 void **slot;
512 name = TYPE_NAME (type);
513 if (TREE_CODE (name) == TYPE_DECL)
514 name = DECL_NAME (name);
516 slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
517 NO_INSERT);
518 if (slot != NULL)
519 ret = false;
521 obstack_1grow (ob, '_');
522 go_append_string (ob, name);
523 return ret;
526 pointer_set_insert (container->decls_seen, type);
528 switch (TREE_CODE (type))
530 case ENUMERAL_TYPE:
531 obstack_grow (ob, "int", 3);
532 break;
534 case TYPE_DECL:
536 void **slot;
538 slot = htab_find_slot (container->invalid_hash,
539 IDENTIFIER_POINTER (DECL_NAME (type)),
540 NO_INSERT);
541 if (slot != NULL)
542 ret = false;
544 obstack_1grow (ob, '_');
545 go_append_string (ob, DECL_NAME (type));
547 break;
549 case INTEGER_TYPE:
551 const char *s;
552 char buf[100];
554 switch (TYPE_PRECISION (type))
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;
576 obstack_grow (ob, s, strlen (s));
578 break;
580 case REAL_TYPE:
582 const char *s;
583 char buf[100];
585 switch (TYPE_PRECISION (type))
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;
600 obstack_grow (ob, s, strlen (s));
602 break;
604 case BOOLEAN_TYPE:
605 obstack_grow (ob, "bool", 4);
606 break;
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))))
616 tree name;
617 void **slot;
619 name = TYPE_NAME (TREE_TYPE (type));
620 if (TREE_CODE (name) == TYPE_DECL)
621 name = DECL_NAME (name);
623 slot = htab_find_slot (container->invalid_hash,
624 IDENTIFIER_POINTER (name), NO_INSERT);
625 if (slot != NULL)
626 ret = false;
628 obstack_grow (ob, "*_", 2);
629 go_append_string (ob, name);
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));
638 return ret;
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
648 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
649 true))
650 ret = false;
652 break;
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))
665 char buf[100];
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));
671 obstack_1grow (ob, ']');
672 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
673 ret = false;
674 break;
676 case UNION_TYPE:
677 case RECORD_TYPE:
679 tree field;
680 int i;
682 obstack_grow (ob, "struct { ", 9);
683 i = 0;
684 for (field = TYPE_FIELDS (type);
685 field != NULL_TREE;
686 field = TREE_CHAIN (field))
688 struct obstack hold_type_obstack;
689 bool field_ok;
691 if (TREE_CODE (type) == UNION_TYPE)
693 hold_type_obstack = container->type_obstack;
694 obstack_init (&container->type_obstack);
697 field_ok = true;
699 if (DECL_NAME (field) == NULL)
701 char buf[100];
703 obstack_grow (ob, "Godump_", 7);
704 snprintf (buf, sizeof buf, "%d", i);
705 obstack_grow (ob, buf, strlen (buf));
706 i++;
708 else
710 const char *var_name;
711 void **slot;
713 /* Start variable name with an underscore if a keyword. */
714 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
715 slot = htab_find_slot (container->keyword_hash, var_name,
716 NO_INSERT);
717 if (slot != NULL)
718 obstack_1grow (ob, '_');
719 go_append_string (ob, DECL_NAME (field));
721 obstack_1grow (ob, ' ');
722 if (DECL_BIT_FIELD (field))
724 obstack_grow (ob, "INVALID-bit-field", 17);
725 field_ok = false;
727 else
729 /* Do not expand type if a record or union type or a
730 function pointer. */
731 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
732 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
733 || (POINTER_TYPE_P (TREE_TYPE (field))
734 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
735 == FUNCTION_TYPE))))
737 tree name;
738 void **slot;
740 name = TYPE_NAME (TREE_TYPE (field));
741 if (TREE_CODE (name) == TYPE_DECL)
742 name = DECL_NAME (name);
744 slot = htab_find_slot (container->invalid_hash,
745 IDENTIFIER_POINTER (name),
746 NO_INSERT);
747 if (slot != NULL)
748 field_ok = false;
750 obstack_1grow (ob, '_');
751 go_append_string (ob, name);
753 else
755 if (!go_format_type (container, TREE_TYPE (field), true,
756 false))
757 field_ok = false;
760 obstack_grow (ob, "; ", 2);
762 /* Only output the first successful field of a union, and
763 hope for the best. */
764 if (TREE_CODE (type) == UNION_TYPE)
766 if (!field_ok && TREE_CHAIN (field) == NULL_TREE)
768 field_ok = true;
769 ret = false;
771 if (field_ok)
773 unsigned int sz;
775 sz = obstack_object_size (&container->type_obstack);
776 obstack_grow (&hold_type_obstack,
777 obstack_base (&container->type_obstack),
778 sz);
780 obstack_free (&container->type_obstack, NULL);
781 container->type_obstack = hold_type_obstack;
782 if (field_ok)
783 break;
785 else
787 if (!field_ok)
788 ret = false;
791 obstack_1grow (ob, '}');
793 break;
795 case FUNCTION_TYPE:
797 tree arg_type;
798 bool is_varargs;
799 tree result;
800 function_args_iterator iter;
801 bool seen_arg;
803 /* Go has no way to write a type which is a function but not a
804 pointer to a function. */
805 if (!is_func_ok)
807 obstack_grow (ob, "func*", 5);
808 ret = false;
811 obstack_1grow (ob, '(');
812 is_varargs = stdarg_p (type);
813 seen_arg = false;
814 FOREACH_FUNCTION_ARGS (type, arg_type, iter)
816 if (VOID_TYPE_P (arg_type))
817 break;
818 if (seen_arg)
819 obstack_grow (ob, ", ", 2);
820 if (!go_format_type (container, arg_type, true, false))
821 ret = false;
822 seen_arg = true;
824 if (is_varargs)
826 if (prototype_p (type))
827 obstack_grow (ob, ", ", 2);
828 obstack_grow (ob, "...interface{}", 14);
830 obstack_1grow (ob, ')');
832 result = TREE_TYPE (type);
833 if (!VOID_TYPE_P (result))
835 obstack_1grow (ob, ' ');
836 if (!go_format_type (container, result, use_type_name, false))
837 ret = false;
840 break;
842 default:
843 obstack_grow (ob, "INVALID-type", 12);
844 ret = false;
845 break;
848 return ret;
851 /* Output the type which was built on the type obstack, and then free
852 it. */
854 static void
855 go_output_type (struct godump_container *container)
857 struct obstack *ob;
859 ob = &container->type_obstack;
860 obstack_1grow (ob, '\0');
861 fputs (obstack_base (ob), go_dump_file);
862 obstack_free (ob, obstack_base (ob));
865 /* Output a function declaration. */
867 static void
868 go_output_fndecl (struct godump_container *container, tree decl)
870 if (!go_format_type (container, TREE_TYPE (decl), false, true))
871 fprintf (go_dump_file, "// ");
872 fprintf (go_dump_file, "func _%s ",
873 IDENTIFIER_POINTER (DECL_NAME (decl)));
874 go_output_type (container);
875 fprintf (go_dump_file, " __asm__(\"%s\")\n",
876 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
879 /* Output a typedef or something like a struct definition. */
881 static void
882 go_output_typedef (struct godump_container *container, tree decl)
884 /* If we have an enum type, output the enum constants
885 separately. */
886 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
887 && TYPE_SIZE (TREE_TYPE (decl)) != 0
888 && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
889 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
890 || !pointer_set_contains (container->decls_seen,
891 TYPE_CANONICAL (TREE_TYPE (decl)))))
893 tree element;
895 for (element = TYPE_VALUES (TREE_TYPE (decl));
896 element != NULL_TREE;
897 element = TREE_CHAIN (element))
899 const char *name;
900 void **slot;
902 name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
904 /* Sometimes a name will be defined as both an enum constant
905 and a macro. Avoid duplicate definition errors by
906 treating enum constants as macros. */
907 slot = htab_find_slot (macro_hash, name, INSERT);
908 if (*slot == NULL)
910 *slot = CONST_CAST (char *, name);
911 fprintf (go_dump_file,
912 "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
913 name, tree_low_cst (TREE_VALUE (element), 0));
916 pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
917 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
918 pointer_set_insert (container->decls_seen,
919 TYPE_CANONICAL (TREE_TYPE (decl)));
922 if (DECL_NAME (decl) != NULL_TREE)
924 void **slot;
925 const char *type;
927 type = IDENTIFIER_POINTER (DECL_NAME (decl));
928 /* If type defined already, skip. */
929 slot = htab_find_slot (container->type_hash, type, INSERT);
930 if (*slot != NULL)
931 return;
932 *slot = CONST_CAST (void *, (const void *) type);
934 if (!go_format_type (container, TREE_TYPE (decl), false, false))
936 fprintf (go_dump_file, "// ");
937 slot = htab_find_slot (container->invalid_hash, type, INSERT);
938 *slot = CONST_CAST (void *, (const void *) type);
940 fprintf (go_dump_file, "type _%s ",
941 IDENTIFIER_POINTER (DECL_NAME (decl)));
942 go_output_type (container);
943 pointer_set_insert (container->decls_seen, decl);
945 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
947 void **slot;
948 const char *type;
950 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
951 /* If type defined already, skip. */
952 slot = htab_find_slot (container->type_hash, type, INSERT);
953 if (*slot != NULL)
954 return;
955 *slot = CONST_CAST (void *, (const void *) type);
957 if (!go_format_type (container, TREE_TYPE (decl), false, false))
959 fprintf (go_dump_file, "// ");
960 slot = htab_find_slot (container->invalid_hash, type, INSERT);
961 *slot = CONST_CAST (void *, (const void *) type);
963 fprintf (go_dump_file, "type _%s ",
964 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
965 go_output_type (container);
967 else
968 return;
970 fprintf (go_dump_file, "\n");
973 /* Output a variable. */
975 static void
976 go_output_var (struct godump_container *container, tree decl)
978 bool is_valid;
980 if (pointer_set_contains (container->decls_seen, decl)
981 || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
982 return;
983 pointer_set_insert (container->decls_seen, decl);
984 pointer_set_insert (container->decls_seen, DECL_NAME (decl));
986 is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
987 if (is_valid
988 && htab_find_slot (container->type_hash,
989 IDENTIFIER_POINTER (DECL_NAME (decl)),
990 NO_INSERT) != NULL)
992 /* There is already a type with this name, probably from a
993 struct tag. Prefer the type to the variable. */
994 is_valid = false;
996 if (!is_valid)
997 fprintf (go_dump_file, "// ");
999 fprintf (go_dump_file, "var _%s ",
1000 IDENTIFIER_POINTER (DECL_NAME (decl)));
1001 go_output_type (container);
1002 fprintf (go_dump_file, "\n");
1004 /* Sometimes an extern variable is declared with an unknown struct
1005 type. */
1006 if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
1007 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1009 tree type_name = TYPE_NAME (TREE_TYPE (decl));
1010 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1011 pointer_set_insert (container->pot_dummy_types,
1012 IDENTIFIER_POINTER (type_name));
1013 else if (TREE_CODE (type_name) == TYPE_DECL)
1014 pointer_set_insert (container->pot_dummy_types,
1015 IDENTIFIER_POINTER (DECL_NAME (type_name)));
1019 /* Build a hash table with the Go keywords. */
1021 static const char * const keywords[] = {
1022 "__asm__", "break", "case", "chan", "const", "continue", "default",
1023 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1024 "import", "interface", "map", "package", "range", "return", "select",
1025 "struct", "switch", "type", "var"
1028 static void
1029 keyword_hash_init (struct godump_container *container)
1031 size_t i;
1032 size_t count = sizeof (keywords) / sizeof (keywords[0]);
1033 void **slot;
1035 for (i = 0; i < count; i++)
1037 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1038 *slot = CONST_CAST (void *, (const void *) keywords[i]);
1042 /* Traversing the pot_dummy_types and seeing which types are present
1043 in the global types hash table and creating dummy definitions if
1044 not found. This function is invoked by pointer_set_traverse. */
1046 static bool
1047 find_dummy_types (const void *ptr, void *adata)
1049 struct godump_container *data = (struct godump_container *) adata;
1050 const char *type = (const char *) ptr;
1051 void **slot;
1053 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1054 if (slot == NULL)
1055 fprintf (go_dump_file, "type _%s struct {}\n", type);
1056 return true;
1059 /* Output symbols. */
1061 static void
1062 go_finish (const char *filename)
1064 struct godump_container container;
1065 unsigned int ix;
1066 tree decl;
1068 real_debug_hooks->finish (filename);
1070 container.decls_seen = pointer_set_create ();
1071 container.pot_dummy_types = pointer_set_create ();
1072 container.type_hash = htab_create (100, htab_hash_string,
1073 string_hash_eq, NULL);
1074 container.invalid_hash = htab_create (10, htab_hash_string,
1075 string_hash_eq, NULL);
1076 container.keyword_hash = htab_create (50, htab_hash_string,
1077 string_hash_eq, NULL);
1078 obstack_init (&container.type_obstack);
1080 keyword_hash_init (&container);
1082 FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1084 switch (TREE_CODE (decl))
1086 case FUNCTION_DECL:
1087 go_output_fndecl (&container, decl);
1088 break;
1090 case TYPE_DECL:
1091 go_output_typedef (&container, decl);
1092 break;
1094 case VAR_DECL:
1095 go_output_var (&container, decl);
1096 break;
1098 default:
1099 gcc_unreachable();
1103 /* To emit dummy definitions. */
1104 pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1105 (void *) &container);
1107 pointer_set_destroy (container.decls_seen);
1108 pointer_set_destroy (container.pot_dummy_types);
1109 htab_delete (container.type_hash);
1110 htab_delete (container.invalid_hash);
1111 htab_delete (container.keyword_hash);
1112 obstack_free (&container.type_obstack, NULL);
1114 queue = NULL;
1116 if (fclose (go_dump_file) != 0)
1117 error ("could not close Go dump file: %m");
1118 go_dump_file = NULL;
1121 /* Set up our hooks. */
1123 const struct gcc_debug_hooks *
1124 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1126 go_dump_file = fopen (filename, "w");
1127 if (go_dump_file == NULL)
1129 error ("could not open Go dump file %qs: %m", filename);
1130 return hooks;
1133 go_debug_hooks = *hooks;
1134 real_debug_hooks = hooks;
1136 go_debug_hooks.finish = go_finish;
1137 go_debug_hooks.define = go_define;
1138 go_debug_hooks.undef = go_undef;
1139 go_debug_hooks.function_decl = go_function_decl;
1140 go_debug_hooks.global_decl = go_global_decl;
1141 go_debug_hooks.type_decl = go_type_decl;
1143 macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1145 return &go_debug_hooks;
1148 #include "gt-godump.h"