1 /* Output Go language descriptions of types.
2 Copyright (C) 2008, 2009, 2010 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
)
86 real_debug_hooks
->define (lineno
, buffer
);
88 /* Skip macro functions. */
89 for (p
= buffer
; *p
!= '\0' && *p
!= ' '; ++p
)
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
);
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);
120 if (ISALPHA (*p
) || *p
== '_')
126 while (ISALNUM (*p
) || *p
== '_')
128 n
= XALLOCAVEC (char, p
- start
+ 1);
129 memcpy (n
, start
, p
- start
);
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
136 fprintf (go_dump_file
, "// unknowndefine %s\n", buffer
);
141 memcpy (q
, start
, p
- start
);
144 else if (ISDIGIT (*p
)
145 || (*p
== '.' && ISDIGIT (p
[1])))
152 if (*p
== '0' && (p
[1] == 'x' || p
[1] == 'X'))
157 while (ISDIGIT (*p
) || *p
== '.' || *p
== 'e' || *p
== 'E'
159 && ((*p
>= 'a' && *p
<= 'f')
160 || (*p
>= 'A' && *p
<= 'F'))))
162 memcpy (q
, start
, 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
173 else if (ISSPACE (*p
)
174 || *p
== '+' || *p
== '-'
175 || *p
== '*' || *p
== '/' || *p
== '%'
176 || *p
== '|' || *p
== '&'
177 || *p
== '>' || *p
== '<'
179 || *p
== '(' || *p
== ')'
180 || *p
== '"' || *p
== '\'')
184 /* Something we don't recognize. */
185 fprintf (go_dump_file
, "// unknowndefine %s\n", buffer
);
191 slot
= htab_find_slot_with_hash (macro_hash
, copy
, hashval
, INSERT
);
194 fprintf (go_dump_file
, "const _%s = %s\n", copy
, out_buffer
);
196 XDELETEVEC (out_buffer
);
202 go_undef (unsigned int lineno
, const char *buffer
)
206 real_debug_hooks
->undef (lineno
, buffer
);
208 slot
= htab_find_slot (macro_hash
, buffer
, NO_INSERT
);
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. */
221 if (!TREE_PUBLIC (decl
)
222 || DECL_IS_BUILTIN (decl
)
223 || DECL_NAME (decl
) == NULL_TREE
)
225 VEC_safe_push (tree
, gc
, queue
, decl
);
228 /* A function decl. */
231 go_function_decl (tree decl
)
233 real_debug_hooks
->function_decl (decl
);
237 /* A global variable decl. */
240 go_global_decl (tree decl
)
242 real_debug_hooks
->global_decl (decl
);
246 /* A type declaration. */
249 go_type_decl (tree decl
, int local
)
251 real_debug_hooks
->type_decl (decl
, local
);
253 if (local
|| DECL_IS_BUILTIN (decl
))
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
)
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
273 struct pointer_set_t
*pot_dummy_types
;
278 /* Global type definitions. */
281 /* Obstack used to write out a type definition. */
282 struct obstack type_obstack
;
285 /* Append an IDENTIFIER_NODE to OB. */
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. */
300 go_format_type (struct godump_container
*container
, tree type
,
301 bool use_type_name
, bool is_func_ok
)
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
))
318 name
= TYPE_NAME (type
);
319 if (TREE_CODE (name
) == IDENTIFIER_NODE
)
321 obstack_1grow (ob
, '_');
322 go_append_string (ob
, name
);
325 else if (TREE_CODE (name
) == TYPE_DECL
)
327 obstack_1grow (ob
, '_');
328 go_append_string (ob
, DECL_NAME (name
));
333 pointer_set_insert (container
->decls_seen
, type
);
335 switch (TREE_CODE (type
))
338 obstack_grow (ob
, "int", 3);
342 obstack_1grow (ob
, '_');
343 go_append_string (ob
, DECL_NAME (type
));
351 switch (TYPE_PRECISION (type
))
354 s
= TYPE_UNSIGNED (type
) ? "uint8" : "int8";
357 s
= TYPE_UNSIGNED (type
) ? "uint16" : "int16";
360 s
= TYPE_UNSIGNED (type
) ? "uint32" : "int32";
363 s
= TYPE_UNSIGNED (type
) ? "uint64" : "int64";
366 snprintf (buf
, sizeof buf
, "INVALID-int-%u%s",
367 TYPE_PRECISION (type
),
368 TYPE_UNSIGNED (type
) ? "u" : "");
373 obstack_grow (ob
, s
, strlen (s
));
382 switch (TYPE_PRECISION (type
))
394 snprintf (buf
, sizeof buf
, "INVALID-float-%u",
395 TYPE_PRECISION (type
));
400 obstack_grow (ob
, s
, strlen (s
));
405 obstack_grow (ob
, "bool", 4);
410 && TYPE_NAME (TREE_TYPE (type
)) != NULL_TREE
411 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type
))
412 || (POINTER_TYPE_P (TREE_TYPE (type
))
413 && (TREE_CODE (TREE_TYPE (TREE_TYPE (type
)))
418 name
= TYPE_NAME (TREE_TYPE (type
));
419 if (TREE_CODE (name
) == IDENTIFIER_NODE
)
421 obstack_grow (ob
, "*_", 2);
422 go_append_string (ob
, name
);
424 /* The pointer here can be used without the struct or
425 union definition. So this struct or union is a a
426 potential dummy type. */
427 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type
)))
428 pointer_set_insert (container
->pot_dummy_types
,
429 IDENTIFIER_POINTER (name
));
433 else if (TREE_CODE (name
) == TYPE_DECL
)
435 obstack_grow (ob
, "*_", 2);
436 go_append_string (ob
, DECL_NAME (name
));
437 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type
)))
438 pointer_set_insert (container
->pot_dummy_types
,
439 IDENTIFIER_POINTER (DECL_NAME (name
)));
443 if (TREE_CODE (TREE_TYPE (type
)) == FUNCTION_TYPE
)
444 obstack_grow (ob
, "func", 4);
446 obstack_1grow (ob
, '*');
447 if (VOID_TYPE_P (TREE_TYPE (type
)))
448 obstack_grow (ob
, "byte", 4);
451 if (!go_format_type (container
, TREE_TYPE (type
), use_type_name
,
458 obstack_1grow (ob
, '[');
459 if (TYPE_DOMAIN (type
) != NULL_TREE
460 && TREE_CODE (TYPE_DOMAIN (type
)) == INTEGER_TYPE
461 && TYPE_MIN_VALUE (TYPE_DOMAIN (type
)) != NULL_TREE
462 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type
))) == INTEGER_CST
463 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type
))) == 0
464 && TYPE_MAX_VALUE (TYPE_DOMAIN (type
)) != NULL_TREE
465 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type
))) == INTEGER_CST
466 && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type
)), 0))
470 snprintf (buf
, sizeof buf
, HOST_WIDE_INT_PRINT_DEC
"+1",
471 tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type
)), 0));
472 obstack_grow (ob
, buf
, strlen (buf
));
474 obstack_1grow (ob
, ']');
475 if (!go_format_type (container
, TREE_TYPE (type
), use_type_name
, false))
485 obstack_grow (ob
, "struct { ", 9);
487 for (field
= TYPE_FIELDS (type
);
489 field
= TREE_CHAIN (field
))
491 if (DECL_NAME (field
) == NULL
)
495 obstack_grow (ob
, "_f", 2);
496 snprintf (buf
, sizeof buf
, "%d", i
);
497 obstack_grow (ob
, buf
, strlen (buf
));
502 const char *var_name
;
505 /* Start variable name with an underscore if a keyword. */
506 var_name
= IDENTIFIER_POINTER (DECL_NAME (field
));
507 slot
= htab_find_slot (container
->keyword_hash
, var_name
,
510 obstack_1grow (ob
, '_');
511 go_append_string (ob
, DECL_NAME (field
));
513 obstack_1grow (ob
, ' ');
514 if (DECL_BIT_FIELD (field
))
516 obstack_grow (ob
, "INVALID-bit-field", 17);
521 /* Do not expand type if a record or union type or a
523 if (TYPE_NAME (TREE_TYPE (field
)) != NULL_TREE
524 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field
))
525 || (POINTER_TYPE_P (TREE_TYPE (field
))
526 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field
)))
529 tree name
= TYPE_NAME (TREE_TYPE (field
));
530 if (TREE_CODE (name
) == IDENTIFIER_NODE
)
532 obstack_1grow (ob
, '_');
533 go_append_string (ob
, name
);
535 else if (TREE_CODE (name
) == TYPE_DECL
)
537 obstack_1grow (ob
, '_');
538 go_append_string (ob
, DECL_NAME (name
));
543 if (!go_format_type (container
, TREE_TYPE (field
), true,
548 obstack_grow (ob
, "; ", 2);
550 /* Only output the first field of a union, and hope for
552 if (TREE_CODE (type
) == UNION_TYPE
)
555 obstack_1grow (ob
, '}');
565 /* Go has no way to write a type which is a function but not a
566 pointer to a function. */
569 obstack_grow (ob
, "func*", 5);
573 obstack_1grow (ob
, '(');
575 for (args
= TYPE_ARG_TYPES (type
);
577 args
= TREE_CHAIN (args
))
579 if (VOID_TYPE_P (TREE_VALUE (args
)))
581 gcc_assert (TREE_CHAIN (args
) == NULL
);
585 if (args
!= TYPE_ARG_TYPES (type
))
586 obstack_grow (ob
, ", ", 2);
587 if (!go_format_type (container
, TREE_VALUE (args
), true, false))
592 if (TYPE_ARG_TYPES (type
) != NULL_TREE
)
593 obstack_grow (ob
, ", ", 2);
594 obstack_grow (ob
, "...interface{}", 14);
596 obstack_1grow (ob
, ')');
598 result
= TREE_TYPE (type
);
599 if (!VOID_TYPE_P (result
))
601 obstack_1grow (ob
, ' ');
602 if (!go_format_type (container
, result
, use_type_name
, false))
609 obstack_grow (ob
, "INVALID-type", 12);
617 /* Output the type which was built on the type obstack, and then free
621 go_output_type (struct godump_container
*container
)
625 ob
= &container
->type_obstack
;
626 obstack_1grow (ob
, '\0');
627 fputs (obstack_base (ob
), go_dump_file
);
628 obstack_free (ob
, obstack_base (ob
));
631 /* Output a function declaration. */
634 go_output_fndecl (struct godump_container
*container
, tree decl
)
636 if (!go_format_type (container
, TREE_TYPE (decl
), false, true))
637 fprintf (go_dump_file
, "// ");
638 fprintf (go_dump_file
, "func _%s ",
639 IDENTIFIER_POINTER (DECL_NAME (decl
)));
640 go_output_type (container
);
641 fprintf (go_dump_file
, " __asm__(\"%s\")\n",
642 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl
)));
645 /* Output a typedef or something like a struct definition. */
648 go_output_typedef (struct godump_container
*container
, tree decl
)
650 /* If we have an enum type, output the enum constants
652 if (TREE_CODE (TREE_TYPE (decl
)) == ENUMERAL_TYPE
653 && TYPE_SIZE (TREE_TYPE (decl
)) != 0
654 && !pointer_set_contains (container
->decls_seen
, TREE_TYPE (decl
))
655 && (TYPE_CANONICAL (TREE_TYPE (decl
)) == NULL_TREE
656 || !pointer_set_contains (container
->decls_seen
,
657 TYPE_CANONICAL (TREE_TYPE (decl
)))))
661 for (element
= TYPE_VALUES (TREE_TYPE (decl
));
662 element
!= NULL_TREE
;
663 element
= TREE_CHAIN (element
))
664 fprintf (go_dump_file
, "const _%s = " HOST_WIDE_INT_PRINT_DEC
"\n",
665 IDENTIFIER_POINTER (TREE_PURPOSE (element
)),
666 tree_low_cst (TREE_VALUE (element
), 0));
667 pointer_set_insert (container
->decls_seen
, TREE_TYPE (decl
));
668 if (TYPE_CANONICAL (TREE_TYPE (decl
)) != NULL_TREE
)
669 pointer_set_insert (container
->decls_seen
,
670 TYPE_CANONICAL (TREE_TYPE (decl
)));
673 if (DECL_NAME (decl
) != NULL_TREE
)
678 type
= IDENTIFIER_POINTER (DECL_NAME (decl
));
679 /* If type defined already, skip. */
680 slot
= htab_find_slot (container
->type_hash
, type
, INSERT
);
683 *slot
= CONST_CAST (void *, (const void *) type
);
685 if (!go_format_type (container
, TREE_TYPE (decl
), false, false))
686 fprintf (go_dump_file
, "// ");
687 fprintf (go_dump_file
, "type _%s ",
688 IDENTIFIER_POINTER (DECL_NAME (decl
)));
689 go_output_type (container
);
690 pointer_set_insert (container
->decls_seen
, decl
);
692 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl
)))
697 type
= IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl
))));
698 /* If type defined already, skip. */
699 slot
= htab_find_slot (container
->type_hash
, type
, INSERT
);
702 *slot
= CONST_CAST (void *, (const void *) type
);
704 if (!go_format_type (container
, TREE_TYPE (decl
), false, false))
705 fprintf (go_dump_file
, "// ");
706 fprintf (go_dump_file
, "type _%s ",
707 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl
))));
708 go_output_type (container
);
713 fprintf (go_dump_file
, "\n");
716 /* Output a variable. */
719 go_output_var (struct godump_container
*container
, tree decl
)
721 if (pointer_set_contains (container
->decls_seen
, decl
)
722 || pointer_set_contains (container
->decls_seen
, DECL_NAME (decl
)))
724 pointer_set_insert (container
->decls_seen
, decl
);
725 pointer_set_insert (container
->decls_seen
, DECL_NAME (decl
));
726 if (!go_format_type (container
, TREE_TYPE (decl
), true, false))
727 fprintf (go_dump_file
, "// ");
728 fprintf (go_dump_file
, "var _%s ",
729 IDENTIFIER_POINTER (DECL_NAME (decl
)));
730 go_output_type (container
);
731 fprintf (go_dump_file
, "\n");
733 /* Sometimes an extern variable is declared with an unknown struct
735 if (TYPE_NAME (TREE_TYPE (decl
)) != NULL_TREE
736 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl
)))
738 tree type_name
= TYPE_NAME (TREE_TYPE (decl
));
739 if (TREE_CODE (type_name
) == IDENTIFIER_NODE
)
740 pointer_set_insert (container
->pot_dummy_types
,
741 IDENTIFIER_POINTER (type_name
));
742 else if (TREE_CODE (type_name
) == TYPE_DECL
)
743 pointer_set_insert (container
->pot_dummy_types
,
744 IDENTIFIER_POINTER (DECL_NAME (type_name
)));
748 /* Build a hash table with the Go keywords. */
750 static const char * const keywords
[] = {
751 "__asm__", "break", "case", "chan", "const", "continue", "default",
752 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
753 "import", "interface", "map", "package", "range", "return", "select",
754 "struct", "switch", "type", "var"
758 keyword_hash_init (struct godump_container
*container
)
761 size_t count
= sizeof (keywords
) / sizeof (keywords
[0]);
764 for (i
= 0; i
< count
; i
++)
766 slot
= htab_find_slot (container
->keyword_hash
, keywords
[i
], INSERT
);
767 *slot
= CONST_CAST (void *, (const void *) keywords
[i
]);
771 /* Traversing the pot_dummy_types and seeing which types are present
772 in the global types hash table and creating dummy definitions if
773 not found. This function is invoked by pointer_set_traverse. */
776 find_dummy_types (const void *ptr
, void *adata
)
778 struct godump_container
*data
= (struct godump_container
*) adata
;
779 const char *type
= (const char *) ptr
;
782 slot
= htab_find_slot (data
->type_hash
, type
, NO_INSERT
);
784 fprintf (go_dump_file
, "type _%s struct {}\n", type
);
788 /* Output symbols. */
791 go_finish (const char *filename
)
793 struct godump_container container
;
797 real_debug_hooks
->finish (filename
);
799 container
.decls_seen
= pointer_set_create ();
800 container
.pot_dummy_types
= pointer_set_create ();
801 container
.type_hash
= htab_create (100, htab_hash_string
,
802 string_hash_eq
, NULL
);
803 container
.keyword_hash
= htab_create (50, htab_hash_string
,
804 string_hash_eq
, NULL
);
805 obstack_init (&container
.type_obstack
);
807 keyword_hash_init (&container
);
809 FOR_EACH_VEC_ELT (tree
, queue
, ix
, decl
)
811 switch (TREE_CODE (decl
))
814 go_output_fndecl (&container
, decl
);
818 go_output_typedef (&container
, decl
);
822 go_output_var (&container
, decl
);
830 /* To emit dummy definitions. */
831 pointer_set_traverse (container
.pot_dummy_types
, find_dummy_types
,
832 (void *) &container
);
834 pointer_set_destroy (container
.decls_seen
);
835 pointer_set_destroy (container
.pot_dummy_types
);
836 htab_delete (container
.type_hash
);
837 htab_delete (container
.keyword_hash
);
838 obstack_free (&container
.type_obstack
, NULL
);
842 if (fclose (go_dump_file
) != 0)
843 error ("could not close Go dump file: %m");
847 /* Set up our hooks. */
849 const struct gcc_debug_hooks
*
850 dump_go_spec_init (const char *filename
, const struct gcc_debug_hooks
*hooks
)
852 go_dump_file
= fopen (filename
, "w");
853 if (go_dump_file
== NULL
)
855 error ("could not open Go dump file %qs: %m", filename
);
859 go_debug_hooks
= *hooks
;
860 real_debug_hooks
= hooks
;
862 go_debug_hooks
.finish
= go_finish
;
863 go_debug_hooks
.define
= go_define
;
864 go_debug_hooks
.undef
= go_undef
;
865 go_debug_hooks
.function_decl
= go_function_decl
;
866 go_debug_hooks
.global_decl
= go_global_decl
;
867 go_debug_hooks
.type_decl
= go_type_decl
;
869 macro_hash
= htab_create (100, htab_hash_string
, string_hash_eq
, NULL
);
871 return &go_debug_hooks
;
874 #include "gt-godump.h"