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
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
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
27 All global names are output with a leading underscore, so that they
28 are all hidden in Go. */
32 #include "coretypes.h"
33 #include "diagnostic-core.h"
36 #include "pointer-set.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. */
68 string_hash_eq (const void *y1
, const void *y2
)
70 return strcmp ((const char *) y1
, (const char *) y2
) == 0;
73 /* A macro definition. */
76 go_define (unsigned int lineno
, const char *buffer
)
88 real_debug_hooks
->define (lineno
, buffer
);
90 /* Skip macro functions. */
91 for (p
= buffer
; *p
!= '\0' && *p
!= ' '; ++p
)
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
);
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);
121 need_operand
= false;
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':
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':
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. */
149 while (ISALNUM (*p
) || *p
== '_')
151 n
= XALLOCAVEC (char, p
- start
+ 1);
152 memcpy (n
, start
, p
- start
);
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
163 memcpy (q
, start
, p
- start
);
167 need_operand
= false;
175 case '0': case '1': case '2': case '3': case '4':
176 case '5': case '6': case '7': case '8': case '9':
183 if (*p
== '0' && (p
[1] == 'x' || p
[1] == 'X'))
188 while (ISDIGIT (*p
) || *p
== '.' || *p
== 'e' || *p
== 'E'
190 && ((*p
>= 'a' && *p
<= 'f')
191 || (*p
>= 'A' && *p
<= 'F'))))
193 memcpy (q
, start
, 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
204 /* We'll pick up the exponent, if any, as an
208 need_operand
= false;
217 /* Always OK, not part of an operand, presumed to start an
221 need_operand
= false;
225 /* OK if we don't need an operand, and presumed to indicate
234 /* Always OK, but not part of an operand. */
239 case '*': case '/': case '%': case '|': case '&': case '^':
240 /* Must be a binary operator. */
252 /* Must be a binary operator. */
264 /* Must be a binary operator. */
273 /* Must be a unary operator. */
281 /* Must be a binary operand, may be << or >> or <= or >=. */
285 if (*p
== *(p
- 1) || *p
== '=')
292 /* Must be a unary operand, must be translated for Go. */
321 case '0': case '1': case '2': case '3':
322 case '4': case '5': case '6': case '7':
324 while (*p
>= '0' && *p
<= '7')
329 /* Go octal characters are always 3
338 while (ISXDIGIT (*p
))
343 /* Go hex characters are always 2 digits. */
348 case 'a': case 'b': case 'f': case 'n': case 'r':
349 case 't': case 'v': case '\\': case '\'': case '"':
371 slot
= htab_find_slot_with_hash (macro_hash
, copy
, hashval
, INSERT
);
374 fprintf (go_dump_file
, "const _%s = %s\n", copy
, out_buffer
);
376 XDELETEVEC (out_buffer
);
380 fprintf (go_dump_file
, "// unknowndefine %s\n", buffer
);
381 XDELETEVEC (out_buffer
);
388 go_undef (unsigned int lineno
, const char *buffer
)
392 real_debug_hooks
->undef (lineno
, buffer
);
394 slot
= htab_find_slot (macro_hash
, buffer
, NO_INSERT
);
397 fprintf (go_dump_file
, "// undef _%s\n", buffer
);
398 /* We don't delete the slot from the hash table because that will
399 cause a duplicate const definition. */
402 /* A function or variable decl. */
407 if (!TREE_PUBLIC (decl
)
408 || DECL_IS_BUILTIN (decl
)
409 || DECL_NAME (decl
) == NULL_TREE
)
411 VEC_safe_push (tree
, gc
, queue
, decl
);
414 /* A function decl. */
417 go_function_decl (tree decl
)
419 real_debug_hooks
->function_decl (decl
);
423 /* A global variable decl. */
426 go_global_decl (tree decl
)
428 real_debug_hooks
->global_decl (decl
);
432 /* A type declaration. */
435 go_type_decl (tree decl
, int local
)
437 real_debug_hooks
->type_decl (decl
, local
);
439 if (local
|| DECL_IS_BUILTIN (decl
))
441 if (DECL_NAME (decl
) == NULL_TREE
442 && (TYPE_NAME (TREE_TYPE (decl
)) == NULL_TREE
443 || TREE_CODE (TYPE_NAME (TREE_TYPE (decl
))) != IDENTIFIER_NODE
)
444 && TREE_CODE (TREE_TYPE (decl
)) != ENUMERAL_TYPE
)
446 VEC_safe_push (tree
, gc
, queue
, decl
);
449 /* A container for the data we pass around when generating information
450 at the end of the compilation. */
452 struct godump_container
454 /* DECLs that we have already seen. */
455 struct pointer_set_t
*decls_seen
;
457 /* Types which may potentially have to be defined as dummy
459 struct pointer_set_t
*pot_dummy_types
;
464 /* Global type definitions. */
467 /* Obstack used to write out a type definition. */
468 struct obstack type_obstack
;
471 /* Append an IDENTIFIER_NODE to OB. */
474 go_append_string (struct obstack
*ob
, tree id
)
476 obstack_grow (ob
, IDENTIFIER_POINTER (id
), IDENTIFIER_LENGTH (id
));
479 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
480 USE_TYPE_NAME is true if we can simply use a type name here without
481 needing to define it. IS_FUNC_OK is true if we can output a func
482 type here; the "func" keyword will already have been added. Return
483 true if the type can be represented in Go, false otherwise. */
486 go_format_type (struct godump_container
*container
, tree type
,
487 bool use_type_name
, bool is_func_ok
)
493 ob
= &container
->type_obstack
;
495 if (TYPE_NAME (type
) != NULL_TREE
496 && (pointer_set_contains (container
->decls_seen
, type
)
497 || pointer_set_contains (container
->decls_seen
, TYPE_NAME (type
)))
498 && (AGGREGATE_TYPE_P (type
)
499 || POINTER_TYPE_P (type
)
500 || TREE_CODE (type
) == FUNCTION_TYPE
))
504 name
= TYPE_NAME (type
);
505 if (TREE_CODE (name
) == IDENTIFIER_NODE
)
507 obstack_1grow (ob
, '_');
508 go_append_string (ob
, name
);
511 else if (TREE_CODE (name
) == TYPE_DECL
)
513 obstack_1grow (ob
, '_');
514 go_append_string (ob
, DECL_NAME (name
));
519 pointer_set_insert (container
->decls_seen
, type
);
521 switch (TREE_CODE (type
))
524 obstack_grow (ob
, "int", 3);
528 obstack_1grow (ob
, '_');
529 go_append_string (ob
, DECL_NAME (type
));
537 switch (TYPE_PRECISION (type
))
540 s
= TYPE_UNSIGNED (type
) ? "uint8" : "int8";
543 s
= TYPE_UNSIGNED (type
) ? "uint16" : "int16";
546 s
= TYPE_UNSIGNED (type
) ? "uint32" : "int32";
549 s
= TYPE_UNSIGNED (type
) ? "uint64" : "int64";
552 snprintf (buf
, sizeof buf
, "INVALID-int-%u%s",
553 TYPE_PRECISION (type
),
554 TYPE_UNSIGNED (type
) ? "u" : "");
559 obstack_grow (ob
, s
, strlen (s
));
568 switch (TYPE_PRECISION (type
))
577 snprintf (buf
, sizeof buf
, "INVALID-float-%u",
578 TYPE_PRECISION (type
));
583 obstack_grow (ob
, s
, strlen (s
));
588 obstack_grow (ob
, "bool", 4);
593 && TYPE_NAME (TREE_TYPE (type
)) != NULL_TREE
594 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type
))
595 || (POINTER_TYPE_P (TREE_TYPE (type
))
596 && (TREE_CODE (TREE_TYPE (TREE_TYPE (type
)))
601 name
= TYPE_NAME (TREE_TYPE (type
));
602 if (TREE_CODE (name
) == IDENTIFIER_NODE
)
604 obstack_grow (ob
, "*_", 2);
605 go_append_string (ob
, name
);
607 /* The pointer here can be used without the struct or
608 union definition. So this struct or union is a a
609 potential dummy type. */
610 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type
)))
611 pointer_set_insert (container
->pot_dummy_types
,
612 IDENTIFIER_POINTER (name
));
616 else if (TREE_CODE (name
) == TYPE_DECL
)
618 obstack_grow (ob
, "*_", 2);
619 go_append_string (ob
, DECL_NAME (name
));
620 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type
)))
621 pointer_set_insert (container
->pot_dummy_types
,
622 IDENTIFIER_POINTER (DECL_NAME (name
)));
626 if (TREE_CODE (TREE_TYPE (type
)) == FUNCTION_TYPE
)
627 obstack_grow (ob
, "func", 4);
629 obstack_1grow (ob
, '*');
630 if (VOID_TYPE_P (TREE_TYPE (type
)))
631 obstack_grow (ob
, "byte", 4);
634 if (!go_format_type (container
, TREE_TYPE (type
), use_type_name
,
641 obstack_1grow (ob
, '[');
642 if (TYPE_DOMAIN (type
) != NULL_TREE
643 && TREE_CODE (TYPE_DOMAIN (type
)) == INTEGER_TYPE
644 && TYPE_MIN_VALUE (TYPE_DOMAIN (type
)) != NULL_TREE
645 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type
))) == INTEGER_CST
646 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type
))) == 0
647 && TYPE_MAX_VALUE (TYPE_DOMAIN (type
)) != NULL_TREE
648 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type
))) == INTEGER_CST
649 && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type
)), 0))
653 snprintf (buf
, sizeof buf
, HOST_WIDE_INT_PRINT_DEC
"+1",
654 tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type
)), 0));
655 obstack_grow (ob
, buf
, strlen (buf
));
657 obstack_1grow (ob
, ']');
658 if (!go_format_type (container
, TREE_TYPE (type
), use_type_name
, false))
668 obstack_grow (ob
, "struct { ", 9);
670 for (field
= TYPE_FIELDS (type
);
672 field
= TREE_CHAIN (field
))
674 if (DECL_NAME (field
) == NULL
)
678 obstack_grow (ob
, "Godump_", 2);
679 snprintf (buf
, sizeof buf
, "%d", i
);
680 obstack_grow (ob
, buf
, strlen (buf
));
685 const char *var_name
;
688 /* Start variable name with an underscore if a keyword. */
689 var_name
= IDENTIFIER_POINTER (DECL_NAME (field
));
690 slot
= htab_find_slot (container
->keyword_hash
, var_name
,
693 obstack_1grow (ob
, '_');
694 go_append_string (ob
, DECL_NAME (field
));
696 obstack_1grow (ob
, ' ');
697 if (DECL_BIT_FIELD (field
))
699 obstack_grow (ob
, "INVALID-bit-field", 17);
704 /* Do not expand type if a record or union type or a
706 if (TYPE_NAME (TREE_TYPE (field
)) != NULL_TREE
707 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field
))
708 || (POINTER_TYPE_P (TREE_TYPE (field
))
709 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field
)))
712 tree name
= TYPE_NAME (TREE_TYPE (field
));
713 if (TREE_CODE (name
) == IDENTIFIER_NODE
)
715 obstack_1grow (ob
, '_');
716 go_append_string (ob
, name
);
718 else if (TREE_CODE (name
) == TYPE_DECL
)
720 obstack_1grow (ob
, '_');
721 go_append_string (ob
, DECL_NAME (name
));
726 if (!go_format_type (container
, TREE_TYPE (field
), true,
731 obstack_grow (ob
, "; ", 2);
733 /* Only output the first field of a union, and hope for
735 if (TREE_CODE (type
) == UNION_TYPE
)
738 obstack_1grow (ob
, '}');
747 function_args_iterator iter
;
750 /* Go has no way to write a type which is a function but not a
751 pointer to a function. */
754 obstack_grow (ob
, "func*", 5);
758 obstack_1grow (ob
, '(');
759 is_varargs
= stdarg_p (type
);
761 FOREACH_FUNCTION_ARGS (type
, arg_type
, iter
)
763 if (VOID_TYPE_P (arg_type
))
766 obstack_grow (ob
, ", ", 2);
767 if (!go_format_type (container
, arg_type
, true, false))
773 if (prototype_p (type
))
774 obstack_grow (ob
, ", ", 2);
775 obstack_grow (ob
, "...interface{}", 14);
777 obstack_1grow (ob
, ')');
779 result
= TREE_TYPE (type
);
780 if (!VOID_TYPE_P (result
))
782 obstack_1grow (ob
, ' ');
783 if (!go_format_type (container
, result
, use_type_name
, false))
790 obstack_grow (ob
, "INVALID-type", 12);
798 /* Output the type which was built on the type obstack, and then free
802 go_output_type (struct godump_container
*container
)
806 ob
= &container
->type_obstack
;
807 obstack_1grow (ob
, '\0');
808 fputs (obstack_base (ob
), go_dump_file
);
809 obstack_free (ob
, obstack_base (ob
));
812 /* Output a function declaration. */
815 go_output_fndecl (struct godump_container
*container
, tree decl
)
817 if (!go_format_type (container
, TREE_TYPE (decl
), false, true))
818 fprintf (go_dump_file
, "// ");
819 fprintf (go_dump_file
, "func _%s ",
820 IDENTIFIER_POINTER (DECL_NAME (decl
)));
821 go_output_type (container
);
822 fprintf (go_dump_file
, " __asm__(\"%s\")\n",
823 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
)));
826 /* Output a typedef or something like a struct definition. */
829 go_output_typedef (struct godump_container
*container
, tree decl
)
831 /* If we have an enum type, output the enum constants
833 if (TREE_CODE (TREE_TYPE (decl
)) == ENUMERAL_TYPE
834 && TYPE_SIZE (TREE_TYPE (decl
)) != 0
835 && !pointer_set_contains (container
->decls_seen
, TREE_TYPE (decl
))
836 && (TYPE_CANONICAL (TREE_TYPE (decl
)) == NULL_TREE
837 || !pointer_set_contains (container
->decls_seen
,
838 TYPE_CANONICAL (TREE_TYPE (decl
)))))
842 for (element
= TYPE_VALUES (TREE_TYPE (decl
));
843 element
!= NULL_TREE
;
844 element
= TREE_CHAIN (element
))
849 name
= IDENTIFIER_POINTER (TREE_PURPOSE (element
));
851 /* Sometimes a name will be defined as both an enum constant
852 and a macro. Avoid duplicate definition errors by
853 treating enum constants as macros. */
854 slot
= htab_find_slot (macro_hash
, name
, INSERT
);
857 *slot
= CONST_CAST (char *, name
);
858 fprintf (go_dump_file
,
859 "const _%s = " HOST_WIDE_INT_PRINT_DEC
"\n",
860 name
, tree_low_cst (TREE_VALUE (element
), 0));
863 pointer_set_insert (container
->decls_seen
, TREE_TYPE (decl
));
864 if (TYPE_CANONICAL (TREE_TYPE (decl
)) != NULL_TREE
)
865 pointer_set_insert (container
->decls_seen
,
866 TYPE_CANONICAL (TREE_TYPE (decl
)));
869 if (DECL_NAME (decl
) != NULL_TREE
)
874 type
= IDENTIFIER_POINTER (DECL_NAME (decl
));
875 /* If type defined already, skip. */
876 slot
= htab_find_slot (container
->type_hash
, type
, INSERT
);
879 *slot
= CONST_CAST (void *, (const void *) type
);
881 if (!go_format_type (container
, TREE_TYPE (decl
), false, false))
882 fprintf (go_dump_file
, "// ");
883 fprintf (go_dump_file
, "type _%s ",
884 IDENTIFIER_POINTER (DECL_NAME (decl
)));
885 go_output_type (container
);
886 pointer_set_insert (container
->decls_seen
, decl
);
888 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl
)))
893 type
= IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl
))));
894 /* If type defined already, skip. */
895 slot
= htab_find_slot (container
->type_hash
, type
, INSERT
);
898 *slot
= CONST_CAST (void *, (const void *) type
);
900 if (!go_format_type (container
, TREE_TYPE (decl
), false, false))
901 fprintf (go_dump_file
, "// ");
902 fprintf (go_dump_file
, "type _%s ",
903 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl
))));
904 go_output_type (container
);
909 fprintf (go_dump_file
, "\n");
912 /* Output a variable. */
915 go_output_var (struct godump_container
*container
, tree decl
)
919 if (pointer_set_contains (container
->decls_seen
, decl
)
920 || pointer_set_contains (container
->decls_seen
, DECL_NAME (decl
)))
922 pointer_set_insert (container
->decls_seen
, decl
);
923 pointer_set_insert (container
->decls_seen
, DECL_NAME (decl
));
925 is_valid
= go_format_type (container
, TREE_TYPE (decl
), true, false);
927 && htab_find_slot (container
->type_hash
,
928 IDENTIFIER_POINTER (DECL_NAME (decl
)),
931 /* There is already a type with this name, probably from a
932 struct tag. Prefer the type to the variable. */
936 fprintf (go_dump_file
, "// ");
938 fprintf (go_dump_file
, "var _%s ",
939 IDENTIFIER_POINTER (DECL_NAME (decl
)));
940 go_output_type (container
);
941 fprintf (go_dump_file
, "\n");
943 /* Sometimes an extern variable is declared with an unknown struct
945 if (TYPE_NAME (TREE_TYPE (decl
)) != NULL_TREE
946 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl
)))
948 tree type_name
= TYPE_NAME (TREE_TYPE (decl
));
949 if (TREE_CODE (type_name
) == IDENTIFIER_NODE
)
950 pointer_set_insert (container
->pot_dummy_types
,
951 IDENTIFIER_POINTER (type_name
));
952 else if (TREE_CODE (type_name
) == TYPE_DECL
)
953 pointer_set_insert (container
->pot_dummy_types
,
954 IDENTIFIER_POINTER (DECL_NAME (type_name
)));
958 /* Build a hash table with the Go keywords. */
960 static const char * const keywords
[] = {
961 "__asm__", "break", "case", "chan", "const", "continue", "default",
962 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
963 "import", "interface", "map", "package", "range", "return", "select",
964 "struct", "switch", "type", "var"
968 keyword_hash_init (struct godump_container
*container
)
971 size_t count
= sizeof (keywords
) / sizeof (keywords
[0]);
974 for (i
= 0; i
< count
; i
++)
976 slot
= htab_find_slot (container
->keyword_hash
, keywords
[i
], INSERT
);
977 *slot
= CONST_CAST (void *, (const void *) keywords
[i
]);
981 /* Traversing the pot_dummy_types and seeing which types are present
982 in the global types hash table and creating dummy definitions if
983 not found. This function is invoked by pointer_set_traverse. */
986 find_dummy_types (const void *ptr
, void *adata
)
988 struct godump_container
*data
= (struct godump_container
*) adata
;
989 const char *type
= (const char *) ptr
;
992 slot
= htab_find_slot (data
->type_hash
, type
, NO_INSERT
);
994 fprintf (go_dump_file
, "type _%s struct {}\n", type
);
998 /* Output symbols. */
1001 go_finish (const char *filename
)
1003 struct godump_container container
;
1007 real_debug_hooks
->finish (filename
);
1009 container
.decls_seen
= pointer_set_create ();
1010 container
.pot_dummy_types
= pointer_set_create ();
1011 container
.type_hash
= htab_create (100, htab_hash_string
,
1012 string_hash_eq
, NULL
);
1013 container
.keyword_hash
= htab_create (50, htab_hash_string
,
1014 string_hash_eq
, NULL
);
1015 obstack_init (&container
.type_obstack
);
1017 keyword_hash_init (&container
);
1019 FOR_EACH_VEC_ELT (tree
, queue
, ix
, decl
)
1021 switch (TREE_CODE (decl
))
1024 go_output_fndecl (&container
, decl
);
1028 go_output_typedef (&container
, decl
);
1032 go_output_var (&container
, decl
);
1040 /* To emit dummy definitions. */
1041 pointer_set_traverse (container
.pot_dummy_types
, find_dummy_types
,
1042 (void *) &container
);
1044 pointer_set_destroy (container
.decls_seen
);
1045 pointer_set_destroy (container
.pot_dummy_types
);
1046 htab_delete (container
.type_hash
);
1047 htab_delete (container
.keyword_hash
);
1048 obstack_free (&container
.type_obstack
, NULL
);
1052 if (fclose (go_dump_file
) != 0)
1053 error ("could not close Go dump file: %m");
1054 go_dump_file
= NULL
;
1057 /* Set up our hooks. */
1059 const struct gcc_debug_hooks
*
1060 dump_go_spec_init (const char *filename
, const struct gcc_debug_hooks
*hooks
)
1062 go_dump_file
= fopen (filename
, "w");
1063 if (go_dump_file
== NULL
)
1065 error ("could not open Go dump file %qs: %m", filename
);
1069 go_debug_hooks
= *hooks
;
1070 real_debug_hooks
= hooks
;
1072 go_debug_hooks
.finish
= go_finish
;
1073 go_debug_hooks
.define
= go_define
;
1074 go_debug_hooks
.undef
= go_undef
;
1075 go_debug_hooks
.function_decl
= go_function_decl
;
1076 go_debug_hooks
.global_decl
= go_global_decl
;
1077 go_debug_hooks
.type_decl
= go_type_decl
;
1079 macro_hash
= htab_create (100, htab_hash_string
, string_hash_eq
, NULL
);
1081 return &go_debug_hooks
;
1084 #include "gt-godump.h"