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
, "_f", 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
, '}');
748 /* Go has no way to write a type which is a function but not a
749 pointer to a function. */
752 obstack_grow (ob
, "func*", 5);
756 obstack_1grow (ob
, '(');
758 for (args
= TYPE_ARG_TYPES (type
);
760 args
= TREE_CHAIN (args
))
762 if (VOID_TYPE_P (TREE_VALUE (args
)))
764 gcc_assert (TREE_CHAIN (args
) == NULL
);
768 if (args
!= TYPE_ARG_TYPES (type
))
769 obstack_grow (ob
, ", ", 2);
770 if (!go_format_type (container
, TREE_VALUE (args
), true, false))
775 if (TYPE_ARG_TYPES (type
) != NULL_TREE
)
776 obstack_grow (ob
, ", ", 2);
777 obstack_grow (ob
, "...interface{}", 14);
779 obstack_1grow (ob
, ')');
781 result
= TREE_TYPE (type
);
782 if (!VOID_TYPE_P (result
))
784 obstack_1grow (ob
, ' ');
785 if (!go_format_type (container
, result
, use_type_name
, false))
792 obstack_grow (ob
, "INVALID-type", 12);
800 /* Output the type which was built on the type obstack, and then free
804 go_output_type (struct godump_container
*container
)
808 ob
= &container
->type_obstack
;
809 obstack_1grow (ob
, '\0');
810 fputs (obstack_base (ob
), go_dump_file
);
811 obstack_free (ob
, obstack_base (ob
));
814 /* Output a function declaration. */
817 go_output_fndecl (struct godump_container
*container
, tree decl
)
819 if (!go_format_type (container
, TREE_TYPE (decl
), false, true))
820 fprintf (go_dump_file
, "// ");
821 fprintf (go_dump_file
, "func _%s ",
822 IDENTIFIER_POINTER (DECL_NAME (decl
)));
823 go_output_type (container
);
824 fprintf (go_dump_file
, " __asm__(\"%s\")\n",
825 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
)));
828 /* Output a typedef or something like a struct definition. */
831 go_output_typedef (struct godump_container
*container
, tree decl
)
833 /* If we have an enum type, output the enum constants
835 if (TREE_CODE (TREE_TYPE (decl
)) == ENUMERAL_TYPE
836 && TYPE_SIZE (TREE_TYPE (decl
)) != 0
837 && !pointer_set_contains (container
->decls_seen
, TREE_TYPE (decl
))
838 && (TYPE_CANONICAL (TREE_TYPE (decl
)) == NULL_TREE
839 || !pointer_set_contains (container
->decls_seen
,
840 TYPE_CANONICAL (TREE_TYPE (decl
)))))
844 for (element
= TYPE_VALUES (TREE_TYPE (decl
));
845 element
!= NULL_TREE
;
846 element
= TREE_CHAIN (element
))
847 fprintf (go_dump_file
, "const _%s = " HOST_WIDE_INT_PRINT_DEC
"\n",
848 IDENTIFIER_POINTER (TREE_PURPOSE (element
)),
849 tree_low_cst (TREE_VALUE (element
), 0));
850 pointer_set_insert (container
->decls_seen
, TREE_TYPE (decl
));
851 if (TYPE_CANONICAL (TREE_TYPE (decl
)) != NULL_TREE
)
852 pointer_set_insert (container
->decls_seen
,
853 TYPE_CANONICAL (TREE_TYPE (decl
)));
856 if (DECL_NAME (decl
) != NULL_TREE
)
861 type
= IDENTIFIER_POINTER (DECL_NAME (decl
));
862 /* If type defined already, skip. */
863 slot
= htab_find_slot (container
->type_hash
, type
, INSERT
);
866 *slot
= CONST_CAST (void *, (const void *) type
);
868 if (!go_format_type (container
, TREE_TYPE (decl
), false, false))
869 fprintf (go_dump_file
, "// ");
870 fprintf (go_dump_file
, "type _%s ",
871 IDENTIFIER_POINTER (DECL_NAME (decl
)));
872 go_output_type (container
);
873 pointer_set_insert (container
->decls_seen
, decl
);
875 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl
)))
880 type
= IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl
))));
881 /* If type defined already, skip. */
882 slot
= htab_find_slot (container
->type_hash
, type
, INSERT
);
885 *slot
= CONST_CAST (void *, (const void *) type
);
887 if (!go_format_type (container
, TREE_TYPE (decl
), false, false))
888 fprintf (go_dump_file
, "// ");
889 fprintf (go_dump_file
, "type _%s ",
890 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl
))));
891 go_output_type (container
);
896 fprintf (go_dump_file
, "\n");
899 /* Output a variable. */
902 go_output_var (struct godump_container
*container
, tree decl
)
906 if (pointer_set_contains (container
->decls_seen
, decl
)
907 || pointer_set_contains (container
->decls_seen
, DECL_NAME (decl
)))
909 pointer_set_insert (container
->decls_seen
, decl
);
910 pointer_set_insert (container
->decls_seen
, DECL_NAME (decl
));
912 is_valid
= go_format_type (container
, TREE_TYPE (decl
), true, false);
914 && htab_find_slot (container
->type_hash
,
915 IDENTIFIER_POINTER (DECL_NAME (decl
)),
918 /* There is already a type with this name, probably from a
919 struct tag. Prefer the type to the variable. */
923 fprintf (go_dump_file
, "// ");
925 fprintf (go_dump_file
, "var _%s ",
926 IDENTIFIER_POINTER (DECL_NAME (decl
)));
927 go_output_type (container
);
928 fprintf (go_dump_file
, "\n");
930 /* Sometimes an extern variable is declared with an unknown struct
932 if (TYPE_NAME (TREE_TYPE (decl
)) != NULL_TREE
933 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl
)))
935 tree type_name
= TYPE_NAME (TREE_TYPE (decl
));
936 if (TREE_CODE (type_name
) == IDENTIFIER_NODE
)
937 pointer_set_insert (container
->pot_dummy_types
,
938 IDENTIFIER_POINTER (type_name
));
939 else if (TREE_CODE (type_name
) == TYPE_DECL
)
940 pointer_set_insert (container
->pot_dummy_types
,
941 IDENTIFIER_POINTER (DECL_NAME (type_name
)));
945 /* Build a hash table with the Go keywords. */
947 static const char * const keywords
[] = {
948 "__asm__", "break", "case", "chan", "const", "continue", "default",
949 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
950 "import", "interface", "map", "package", "range", "return", "select",
951 "struct", "switch", "type", "var"
955 keyword_hash_init (struct godump_container
*container
)
958 size_t count
= sizeof (keywords
) / sizeof (keywords
[0]);
961 for (i
= 0; i
< count
; i
++)
963 slot
= htab_find_slot (container
->keyword_hash
, keywords
[i
], INSERT
);
964 *slot
= CONST_CAST (void *, (const void *) keywords
[i
]);
968 /* Traversing the pot_dummy_types and seeing which types are present
969 in the global types hash table and creating dummy definitions if
970 not found. This function is invoked by pointer_set_traverse. */
973 find_dummy_types (const void *ptr
, void *adata
)
975 struct godump_container
*data
= (struct godump_container
*) adata
;
976 const char *type
= (const char *) ptr
;
979 slot
= htab_find_slot (data
->type_hash
, type
, NO_INSERT
);
981 fprintf (go_dump_file
, "type _%s struct {}\n", type
);
985 /* Output symbols. */
988 go_finish (const char *filename
)
990 struct godump_container container
;
994 real_debug_hooks
->finish (filename
);
996 container
.decls_seen
= pointer_set_create ();
997 container
.pot_dummy_types
= pointer_set_create ();
998 container
.type_hash
= htab_create (100, htab_hash_string
,
999 string_hash_eq
, NULL
);
1000 container
.keyword_hash
= htab_create (50, htab_hash_string
,
1001 string_hash_eq
, NULL
);
1002 obstack_init (&container
.type_obstack
);
1004 keyword_hash_init (&container
);
1006 FOR_EACH_VEC_ELT (tree
, queue
, ix
, decl
)
1008 switch (TREE_CODE (decl
))
1011 go_output_fndecl (&container
, decl
);
1015 go_output_typedef (&container
, decl
);
1019 go_output_var (&container
, decl
);
1027 /* To emit dummy definitions. */
1028 pointer_set_traverse (container
.pot_dummy_types
, find_dummy_types
,
1029 (void *) &container
);
1031 pointer_set_destroy (container
.decls_seen
);
1032 pointer_set_destroy (container
.pot_dummy_types
);
1033 htab_delete (container
.type_hash
);
1034 htab_delete (container
.keyword_hash
);
1035 obstack_free (&container
.type_obstack
, NULL
);
1039 if (fclose (go_dump_file
) != 0)
1040 error ("could not close Go dump file: %m");
1041 go_dump_file
= NULL
;
1044 /* Set up our hooks. */
1046 const struct gcc_debug_hooks
*
1047 dump_go_spec_init (const char *filename
, const struct gcc_debug_hooks
*hooks
)
1049 go_dump_file
= fopen (filename
, "w");
1050 if (go_dump_file
== NULL
)
1052 error ("could not open Go dump file %qs: %m", filename
);
1056 go_debug_hooks
= *hooks
;
1057 real_debug_hooks
= hooks
;
1059 go_debug_hooks
.finish
= go_finish
;
1060 go_debug_hooks
.define
= go_define
;
1061 go_debug_hooks
.undef
= go_undef
;
1062 go_debug_hooks
.function_decl
= go_function_decl
;
1063 go_debug_hooks
.global_decl
= go_global_decl
;
1064 go_debug_hooks
.type_decl
= go_type_decl
;
1066 macro_hash
= htab_create (100, htab_hash_string
, string_hash_eq
, NULL
);
1068 return &go_debug_hooks
;
1071 #include "gt-godump.h"