PR tree-optimization/47427
[official-gcc.git] / gcc / godump.c
blob4ec41f041567adb6b9074f78b063b1cbd1317548
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 char *copy;
83 hashval_t hashval;
84 void **slot;
86 real_debug_hooks->define (lineno, buffer);
88 /* Skip macro functions. */
89 for (p = buffer; *p != '\0' && *p != ' '; ++p)
90 if (*p == '(')
91 return;
93 if (*p == '\0')
94 return;
96 name_end = p;
98 ++p;
99 if (*p == '\0')
100 return;
102 copy = XNEWVEC (char, name_end - buffer + 1);
103 memcpy (copy, buffer, name_end - buffer);
104 copy[name_end - buffer] = '\0';
106 hashval = htab_hash_string (copy);
107 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
108 if (slot != NULL)
110 XDELETEVEC (copy);
111 return;
114 /* For simplicity, we force all names to be hidden by adding an
115 initial underscore, and let the user undo this as needed. */
116 out_buffer = XNEWVEC (char, strlen (p) * 2 + 1);
117 q = out_buffer;
118 while (*p != '\0')
120 if (ISALPHA (*p) || *p == '_')
122 const char *start;
123 char *n;
125 start = p;
126 while (ISALNUM (*p) || *p == '_')
127 ++p;
128 n = XALLOCAVEC (char, p - start + 1);
129 memcpy (n, start, p - start);
130 n[p - start] = '\0';
131 slot = htab_find_slot (macro_hash, n, NO_INSERT);
132 if (slot == NULL || *slot == NULL)
134 /* This is a reference to a name which was not defined
135 as a macro. */
136 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
137 return;
140 *q++ = '_';
141 memcpy (q, start, p - start);
142 q += p - start;
144 else if (ISDIGIT (*p)
145 || (*p == '.' && ISDIGIT (p[1])))
147 const char *start;
148 bool is_hex;
150 start = p;
151 is_hex = false;
152 if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
154 p += 2;
155 is_hex = true;
157 while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
158 || (is_hex
159 && ((*p >= 'a' && *p <= 'f')
160 || (*p >= 'A' && *p <= 'F'))))
161 ++p;
162 memcpy (q, start, p - start);
163 q += p - start;
164 while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
165 || *p == 'f' || *p == 'F'
166 || *p == 'd' || *p == 'D')
168 /* Go doesn't use any of these trailing type
169 modifiers. */
170 ++p;
173 else if (ISSPACE (*p)
174 || *p == '+' || *p == '-'
175 || *p == '*' || *p == '/' || *p == '%'
176 || *p == '|' || *p == '&'
177 || *p == '>' || *p == '<'
178 || *p == '!'
179 || *p == '(' || *p == ')'
180 || *p == '"' || *p == '\'')
181 *q++ = *p++;
182 else
184 /* Something we don't recognize. */
185 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
186 return;
189 *q = '\0';
191 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
192 *slot = copy;
194 fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
196 XDELETEVEC (out_buffer);
199 /* A macro undef. */
201 static void
202 go_undef (unsigned int lineno, const char *buffer)
204 void **slot;
206 real_debug_hooks->undef (lineno, buffer);
208 slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
209 if (slot == NULL)
210 return;
211 fprintf (go_dump_file, "// undef _%s\n", buffer);
212 /* We don't delete the slot from the hash table because that will
213 cause a duplicate const definition. */
216 /* A function or variable decl. */
218 static void
219 go_decl (tree decl)
221 if (!TREE_PUBLIC (decl)
222 || DECL_IS_BUILTIN (decl)
223 || DECL_NAME (decl) == NULL_TREE)
224 return;
225 VEC_safe_push (tree, gc, queue, decl);
228 /* A function decl. */
230 static void
231 go_function_decl (tree decl)
233 real_debug_hooks->function_decl (decl);
234 go_decl (decl);
237 /* A global variable decl. */
239 static void
240 go_global_decl (tree decl)
242 real_debug_hooks->global_decl (decl);
243 go_decl (decl);
246 /* A type declaration. */
248 static void
249 go_type_decl (tree decl, int local)
251 real_debug_hooks->type_decl (decl, local);
253 if (local || DECL_IS_BUILTIN (decl))
254 return;
255 if (DECL_NAME (decl) == NULL_TREE
256 && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
257 || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
258 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
259 return;
260 VEC_safe_push (tree, gc, queue, decl);
263 /* A container for the data we pass around when generating information
264 at the end of the compilation. */
266 struct godump_container
268 /* DECLs that we have already seen. */
269 struct pointer_set_t *decls_seen;
271 /* Types which may potentially have to be defined as dummy
272 types. */
273 struct pointer_set_t *pot_dummy_types;
275 /* Go keywords. */
276 htab_t keyword_hash;
278 /* Global type definitions. */
279 htab_t type_hash;
281 /* Obstack used to write out a type definition. */
282 struct obstack type_obstack;
285 /* Append an IDENTIFIER_NODE to OB. */
287 static void
288 go_append_string (struct obstack *ob, tree id)
290 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
293 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
294 USE_TYPE_NAME is true if we can simply use a type name here without
295 needing to define it. IS_FUNC_OK is true if we can output a func
296 type here; the "func" keyword will already have been added. Return
297 true if the type can be represented in Go, false otherwise. */
299 static bool
300 go_format_type (struct godump_container *container, tree type,
301 bool use_type_name, bool is_func_ok)
303 bool ret;
304 struct obstack *ob;
306 ret = true;
307 ob = &container->type_obstack;
309 if (TYPE_NAME (type) != NULL_TREE
310 && (pointer_set_contains (container->decls_seen, type)
311 || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
312 && (AGGREGATE_TYPE_P (type)
313 || POINTER_TYPE_P (type)
314 || TREE_CODE (type) == FUNCTION_TYPE))
316 tree name;
318 name = TYPE_NAME (type);
319 if (TREE_CODE (name) == IDENTIFIER_NODE)
321 obstack_1grow (ob, '_');
322 go_append_string (ob, name);
323 return ret;
325 else if (TREE_CODE (name) == TYPE_DECL)
327 obstack_1grow (ob, '_');
328 go_append_string (ob, DECL_NAME (name));
329 return ret;
333 pointer_set_insert (container->decls_seen, type);
335 switch (TREE_CODE (type))
337 case ENUMERAL_TYPE:
338 obstack_grow (ob, "int", 3);
339 break;
341 case TYPE_DECL:
342 obstack_1grow (ob, '_');
343 go_append_string (ob, DECL_NAME (type));
344 break;
346 case INTEGER_TYPE:
348 const char *s;
349 char buf[100];
351 switch (TYPE_PRECISION (type))
353 case 8:
354 s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
355 break;
356 case 16:
357 s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
358 break;
359 case 32:
360 s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
361 break;
362 case 64:
363 s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
364 break;
365 default:
366 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
367 TYPE_PRECISION (type),
368 TYPE_UNSIGNED (type) ? "u" : "");
369 s = buf;
370 ret = false;
371 break;
373 obstack_grow (ob, s, strlen (s));
375 break;
377 case REAL_TYPE:
379 const char *s;
380 char buf[100];
382 switch (TYPE_PRECISION (type))
384 case 32:
385 s = "float32";
386 break;
387 case 64:
388 s = "float64";
389 break;
390 default:
391 snprintf (buf, sizeof buf, "INVALID-float-%u",
392 TYPE_PRECISION (type));
393 s = buf;
394 ret = false;
395 break;
397 obstack_grow (ob, s, strlen (s));
399 break;
401 case BOOLEAN_TYPE:
402 obstack_grow (ob, "bool", 4);
403 break;
405 case POINTER_TYPE:
406 if (use_type_name
407 && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
408 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
409 || (POINTER_TYPE_P (TREE_TYPE (type))
410 && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
411 == FUNCTION_TYPE))))
413 tree name;
415 name = TYPE_NAME (TREE_TYPE (type));
416 if (TREE_CODE (name) == IDENTIFIER_NODE)
418 obstack_grow (ob, "*_", 2);
419 go_append_string (ob, name);
421 /* The pointer here can be used without the struct or
422 union definition. So this struct or union is a a
423 potential dummy type. */
424 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
425 pointer_set_insert (container->pot_dummy_types,
426 IDENTIFIER_POINTER (name));
428 return ret;
430 else if (TREE_CODE (name) == TYPE_DECL)
432 obstack_grow (ob, "*_", 2);
433 go_append_string (ob, DECL_NAME (name));
434 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
435 pointer_set_insert (container->pot_dummy_types,
436 IDENTIFIER_POINTER (DECL_NAME (name)));
437 return ret;
440 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
441 obstack_grow (ob, "func", 4);
442 else
443 obstack_1grow (ob, '*');
444 if (VOID_TYPE_P (TREE_TYPE (type)))
445 obstack_grow (ob, "byte", 4);
446 else
448 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
449 true))
450 ret = false;
452 break;
454 case ARRAY_TYPE:
455 obstack_1grow (ob, '[');
456 if (TYPE_DOMAIN (type) != NULL_TREE
457 && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
458 && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
459 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
460 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
461 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
462 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
463 && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
465 char buf[100];
467 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
468 tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
469 obstack_grow (ob, buf, strlen (buf));
471 obstack_1grow (ob, ']');
472 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
473 ret = false;
474 break;
476 case UNION_TYPE:
477 case RECORD_TYPE:
479 tree field;
480 int i;
482 obstack_grow (ob, "struct { ", 9);
483 i = 0;
484 for (field = TYPE_FIELDS (type);
485 field != NULL_TREE;
486 field = TREE_CHAIN (field))
488 if (DECL_NAME (field) == NULL)
490 char buf[100];
492 obstack_grow (ob, "_f", 2);
493 snprintf (buf, sizeof buf, "%d", i);
494 obstack_grow (ob, buf, strlen (buf));
495 i++;
497 else
499 const char *var_name;
500 void **slot;
502 /* Start variable name with an underscore if a keyword. */
503 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
504 slot = htab_find_slot (container->keyword_hash, var_name,
505 NO_INSERT);
506 if (slot != NULL)
507 obstack_1grow (ob, '_');
508 go_append_string (ob, DECL_NAME (field));
510 obstack_1grow (ob, ' ');
511 if (DECL_BIT_FIELD (field))
513 obstack_grow (ob, "INVALID-bit-field", 17);
514 ret = false;
516 else
518 /* Do not expand type if a record or union type or a
519 function pointer. */
520 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
521 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
522 || (POINTER_TYPE_P (TREE_TYPE (field))
523 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
524 == FUNCTION_TYPE))))
526 tree name = TYPE_NAME (TREE_TYPE (field));
527 if (TREE_CODE (name) == IDENTIFIER_NODE)
529 obstack_1grow (ob, '_');
530 go_append_string (ob, name);
532 else if (TREE_CODE (name) == TYPE_DECL)
534 obstack_1grow (ob, '_');
535 go_append_string (ob, DECL_NAME (name));
538 else
540 if (!go_format_type (container, TREE_TYPE (field), true,
541 false))
542 ret = false;
545 obstack_grow (ob, "; ", 2);
547 /* Only output the first field of a union, and hope for
548 the best. */
549 if (TREE_CODE (type) == UNION_TYPE)
550 break;
552 obstack_1grow (ob, '}');
554 break;
556 case FUNCTION_TYPE:
558 tree args;
559 bool is_varargs;
560 tree result;
562 /* Go has no way to write a type which is a function but not a
563 pointer to a function. */
564 if (!is_func_ok)
566 obstack_grow (ob, "func*", 5);
567 ret = false;
570 obstack_1grow (ob, '(');
571 is_varargs = true;
572 for (args = TYPE_ARG_TYPES (type);
573 args != NULL_TREE;
574 args = TREE_CHAIN (args))
576 if (VOID_TYPE_P (TREE_VALUE (args)))
578 gcc_assert (TREE_CHAIN (args) == NULL);
579 is_varargs = false;
580 break;
582 if (args != TYPE_ARG_TYPES (type))
583 obstack_grow (ob, ", ", 2);
584 if (!go_format_type (container, TREE_VALUE (args), true, false))
585 ret = false;
587 if (is_varargs)
589 if (TYPE_ARG_TYPES (type) != NULL_TREE)
590 obstack_grow (ob, ", ", 2);
591 obstack_grow (ob, "...interface{}", 14);
593 obstack_1grow (ob, ')');
595 result = TREE_TYPE (type);
596 if (!VOID_TYPE_P (result))
598 obstack_1grow (ob, ' ');
599 if (!go_format_type (container, result, use_type_name, false))
600 ret = false;
603 break;
605 default:
606 obstack_grow (ob, "INVALID-type", 12);
607 ret = false;
608 break;
611 return ret;
614 /* Output the type which was built on the type obstack, and then free
615 it. */
617 static void
618 go_output_type (struct godump_container *container)
620 struct obstack *ob;
622 ob = &container->type_obstack;
623 obstack_1grow (ob, '\0');
624 fputs (obstack_base (ob), go_dump_file);
625 obstack_free (ob, obstack_base (ob));
628 /* Output a function declaration. */
630 static void
631 go_output_fndecl (struct godump_container *container, tree decl)
633 if (!go_format_type (container, TREE_TYPE (decl), false, true))
634 fprintf (go_dump_file, "// ");
635 fprintf (go_dump_file, "func _%s ",
636 IDENTIFIER_POINTER (DECL_NAME (decl)));
637 go_output_type (container);
638 fprintf (go_dump_file, " __asm__(\"%s\")\n",
639 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
642 /* Output a typedef or something like a struct definition. */
644 static void
645 go_output_typedef (struct godump_container *container, tree decl)
647 /* If we have an enum type, output the enum constants
648 separately. */
649 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
650 && TYPE_SIZE (TREE_TYPE (decl)) != 0
651 && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
652 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
653 || !pointer_set_contains (container->decls_seen,
654 TYPE_CANONICAL (TREE_TYPE (decl)))))
656 tree element;
658 for (element = TYPE_VALUES (TREE_TYPE (decl));
659 element != NULL_TREE;
660 element = TREE_CHAIN (element))
661 fprintf (go_dump_file, "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
662 IDENTIFIER_POINTER (TREE_PURPOSE (element)),
663 tree_low_cst (TREE_VALUE (element), 0));
664 pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
665 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
666 pointer_set_insert (container->decls_seen,
667 TYPE_CANONICAL (TREE_TYPE (decl)));
670 if (DECL_NAME (decl) != NULL_TREE)
672 void **slot;
673 const char *type;
675 type = IDENTIFIER_POINTER (DECL_NAME (decl));
676 /* If type defined already, skip. */
677 slot = htab_find_slot (container->type_hash, type, INSERT);
678 if (*slot != NULL)
679 return;
680 *slot = CONST_CAST (void *, (const void *) type);
682 if (!go_format_type (container, TREE_TYPE (decl), false, false))
683 fprintf (go_dump_file, "// ");
684 fprintf (go_dump_file, "type _%s ",
685 IDENTIFIER_POINTER (DECL_NAME (decl)));
686 go_output_type (container);
687 pointer_set_insert (container->decls_seen, decl);
689 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
691 void **slot;
692 const char *type;
694 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
695 /* If type defined already, skip. */
696 slot = htab_find_slot (container->type_hash, type, INSERT);
697 if (*slot != NULL)
698 return;
699 *slot = CONST_CAST (void *, (const void *) type);
701 if (!go_format_type (container, TREE_TYPE (decl), false, false))
702 fprintf (go_dump_file, "// ");
703 fprintf (go_dump_file, "type _%s ",
704 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
705 go_output_type (container);
707 else
708 return;
710 fprintf (go_dump_file, "\n");
713 /* Output a variable. */
715 static void
716 go_output_var (struct godump_container *container, tree decl)
718 bool is_valid;
720 if (pointer_set_contains (container->decls_seen, decl)
721 || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
722 return;
723 pointer_set_insert (container->decls_seen, decl);
724 pointer_set_insert (container->decls_seen, DECL_NAME (decl));
726 is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
727 if (is_valid
728 && htab_find_slot (container->type_hash,
729 IDENTIFIER_POINTER (DECL_NAME (decl)),
730 NO_INSERT) != NULL)
732 /* There is already a type with this name, probably from a
733 struct tag. Prefer the type to the variable. */
734 is_valid = false;
736 if (!is_valid)
737 fprintf (go_dump_file, "// ");
739 fprintf (go_dump_file, "var _%s ",
740 IDENTIFIER_POINTER (DECL_NAME (decl)));
741 go_output_type (container);
742 fprintf (go_dump_file, "\n");
744 /* Sometimes an extern variable is declared with an unknown struct
745 type. */
746 if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
747 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
749 tree type_name = TYPE_NAME (TREE_TYPE (decl));
750 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
751 pointer_set_insert (container->pot_dummy_types,
752 IDENTIFIER_POINTER (type_name));
753 else if (TREE_CODE (type_name) == TYPE_DECL)
754 pointer_set_insert (container->pot_dummy_types,
755 IDENTIFIER_POINTER (DECL_NAME (type_name)));
759 /* Build a hash table with the Go keywords. */
761 static const char * const keywords[] = {
762 "__asm__", "break", "case", "chan", "const", "continue", "default",
763 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
764 "import", "interface", "map", "package", "range", "return", "select",
765 "struct", "switch", "type", "var"
768 static void
769 keyword_hash_init (struct godump_container *container)
771 size_t i;
772 size_t count = sizeof (keywords) / sizeof (keywords[0]);
773 void **slot;
775 for (i = 0; i < count; i++)
777 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
778 *slot = CONST_CAST (void *, (const void *) keywords[i]);
782 /* Traversing the pot_dummy_types and seeing which types are present
783 in the global types hash table and creating dummy definitions if
784 not found. This function is invoked by pointer_set_traverse. */
786 static bool
787 find_dummy_types (const void *ptr, void *adata)
789 struct godump_container *data = (struct godump_container *) adata;
790 const char *type = (const char *) ptr;
791 void **slot;
793 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
794 if (slot == NULL)
795 fprintf (go_dump_file, "type _%s struct {}\n", type);
796 return true;
799 /* Output symbols. */
801 static void
802 go_finish (const char *filename)
804 struct godump_container container;
805 unsigned int ix;
806 tree decl;
808 real_debug_hooks->finish (filename);
810 container.decls_seen = pointer_set_create ();
811 container.pot_dummy_types = pointer_set_create ();
812 container.type_hash = htab_create (100, htab_hash_string,
813 string_hash_eq, NULL);
814 container.keyword_hash = htab_create (50, htab_hash_string,
815 string_hash_eq, NULL);
816 obstack_init (&container.type_obstack);
818 keyword_hash_init (&container);
820 FOR_EACH_VEC_ELT (tree, queue, ix, decl)
822 switch (TREE_CODE (decl))
824 case FUNCTION_DECL:
825 go_output_fndecl (&container, decl);
826 break;
828 case TYPE_DECL:
829 go_output_typedef (&container, decl);
830 break;
832 case VAR_DECL:
833 go_output_var (&container, decl);
834 break;
836 default:
837 gcc_unreachable();
841 /* To emit dummy definitions. */
842 pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
843 (void *) &container);
845 pointer_set_destroy (container.decls_seen);
846 pointer_set_destroy (container.pot_dummy_types);
847 htab_delete (container.type_hash);
848 htab_delete (container.keyword_hash);
849 obstack_free (&container.type_obstack, NULL);
851 queue = NULL;
853 if (fclose (go_dump_file) != 0)
854 error ("could not close Go dump file: %m");
855 go_dump_file = NULL;
858 /* Set up our hooks. */
860 const struct gcc_debug_hooks *
861 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
863 go_dump_file = fopen (filename, "w");
864 if (go_dump_file == NULL)
866 error ("could not open Go dump file %qs: %m", filename);
867 return hooks;
870 go_debug_hooks = *hooks;
871 real_debug_hooks = hooks;
873 go_debug_hooks.finish = go_finish;
874 go_debug_hooks.define = go_define;
875 go_debug_hooks.undef = go_undef;
876 go_debug_hooks.function_decl = go_function_decl;
877 go_debug_hooks.global_decl = go_global_decl;
878 go_debug_hooks.type_decl = go_type_decl;
880 macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
882 return &go_debug_hooks;
885 #include "gt-godump.h"