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
)
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
))
391 snprintf (buf
, sizeof buf
, "INVALID-float-%u",
392 TYPE_PRECISION (type
));
397 obstack_grow (ob
, s
, strlen (s
));
402 obstack_grow (ob
, "bool", 4);
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
)))
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
));
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
)));
440 if (TREE_CODE (TREE_TYPE (type
)) == FUNCTION_TYPE
)
441 obstack_grow (ob
, "func", 4);
443 obstack_1grow (ob
, '*');
444 if (VOID_TYPE_P (TREE_TYPE (type
)))
445 obstack_grow (ob
, "byte", 4);
448 if (!go_format_type (container
, TREE_TYPE (type
), use_type_name
,
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))
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))
482 obstack_grow (ob
, "struct { ", 9);
484 for (field
= TYPE_FIELDS (type
);
486 field
= TREE_CHAIN (field
))
488 if (DECL_NAME (field
) == NULL
)
492 obstack_grow (ob
, "_f", 2);
493 snprintf (buf
, sizeof buf
, "%d", i
);
494 obstack_grow (ob
, buf
, strlen (buf
));
499 const char *var_name
;
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
,
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);
518 /* Do not expand type if a record or union type or a
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
)))
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
));
540 if (!go_format_type (container
, TREE_TYPE (field
), true,
545 obstack_grow (ob
, "; ", 2);
547 /* Only output the first field of a union, and hope for
549 if (TREE_CODE (type
) == UNION_TYPE
)
552 obstack_1grow (ob
, '}');
562 /* Go has no way to write a type which is a function but not a
563 pointer to a function. */
566 obstack_grow (ob
, "func*", 5);
570 obstack_1grow (ob
, '(');
572 for (args
= TYPE_ARG_TYPES (type
);
574 args
= TREE_CHAIN (args
))
576 if (VOID_TYPE_P (TREE_VALUE (args
)))
578 gcc_assert (TREE_CHAIN (args
) == NULL
);
582 if (args
!= TYPE_ARG_TYPES (type
))
583 obstack_grow (ob
, ", ", 2);
584 if (!go_format_type (container
, TREE_VALUE (args
), true, false))
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))
606 obstack_grow (ob
, "INVALID-type", 12);
614 /* Output the type which was built on the type obstack, and then free
618 go_output_type (struct godump_container
*container
)
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. */
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. */
645 go_output_typedef (struct godump_container
*container
, tree decl
)
647 /* If we have an enum type, output the enum constants
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
)))))
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
)
675 type
= IDENTIFIER_POINTER (DECL_NAME (decl
));
676 /* If type defined already, skip. */
677 slot
= htab_find_slot (container
->type_hash
, type
, INSERT
);
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
)))
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
);
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
);
710 fprintf (go_dump_file
, "\n");
713 /* Output a variable. */
716 go_output_var (struct godump_container
*container
, tree decl
)
718 if (pointer_set_contains (container
->decls_seen
, decl
)
719 || pointer_set_contains (container
->decls_seen
, DECL_NAME (decl
)))
721 pointer_set_insert (container
->decls_seen
, decl
);
722 pointer_set_insert (container
->decls_seen
, DECL_NAME (decl
));
723 if (!go_format_type (container
, TREE_TYPE (decl
), true, false))
724 fprintf (go_dump_file
, "// ");
725 fprintf (go_dump_file
, "var _%s ",
726 IDENTIFIER_POINTER (DECL_NAME (decl
)));
727 go_output_type (container
);
728 fprintf (go_dump_file
, "\n");
730 /* Sometimes an extern variable is declared with an unknown struct
732 if (TYPE_NAME (TREE_TYPE (decl
)) != NULL_TREE
733 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl
)))
735 tree type_name
= TYPE_NAME (TREE_TYPE (decl
));
736 if (TREE_CODE (type_name
) == IDENTIFIER_NODE
)
737 pointer_set_insert (container
->pot_dummy_types
,
738 IDENTIFIER_POINTER (type_name
));
739 else if (TREE_CODE (type_name
) == TYPE_DECL
)
740 pointer_set_insert (container
->pot_dummy_types
,
741 IDENTIFIER_POINTER (DECL_NAME (type_name
)));
745 /* Build a hash table with the Go keywords. */
747 static const char * const keywords
[] = {
748 "__asm__", "break", "case", "chan", "const", "continue", "default",
749 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
750 "import", "interface", "map", "package", "range", "return", "select",
751 "struct", "switch", "type", "var"
755 keyword_hash_init (struct godump_container
*container
)
758 size_t count
= sizeof (keywords
) / sizeof (keywords
[0]);
761 for (i
= 0; i
< count
; i
++)
763 slot
= htab_find_slot (container
->keyword_hash
, keywords
[i
], INSERT
);
764 *slot
= CONST_CAST (void *, (const void *) keywords
[i
]);
768 /* Traversing the pot_dummy_types and seeing which types are present
769 in the global types hash table and creating dummy definitions if
770 not found. This function is invoked by pointer_set_traverse. */
773 find_dummy_types (const void *ptr
, void *adata
)
775 struct godump_container
*data
= (struct godump_container
*) adata
;
776 const char *type
= (const char *) ptr
;
779 slot
= htab_find_slot (data
->type_hash
, type
, NO_INSERT
);
781 fprintf (go_dump_file
, "type _%s struct {}\n", type
);
785 /* Output symbols. */
788 go_finish (const char *filename
)
790 struct godump_container container
;
794 real_debug_hooks
->finish (filename
);
796 container
.decls_seen
= pointer_set_create ();
797 container
.pot_dummy_types
= pointer_set_create ();
798 container
.type_hash
= htab_create (100, htab_hash_string
,
799 string_hash_eq
, NULL
);
800 container
.keyword_hash
= htab_create (50, htab_hash_string
,
801 string_hash_eq
, NULL
);
802 obstack_init (&container
.type_obstack
);
804 keyword_hash_init (&container
);
806 FOR_EACH_VEC_ELT (tree
, queue
, ix
, decl
)
808 switch (TREE_CODE (decl
))
811 go_output_fndecl (&container
, decl
);
815 go_output_typedef (&container
, decl
);
819 go_output_var (&container
, decl
);
827 /* To emit dummy definitions. */
828 pointer_set_traverse (container
.pot_dummy_types
, find_dummy_types
,
829 (void *) &container
);
831 pointer_set_destroy (container
.decls_seen
);
832 pointer_set_destroy (container
.pot_dummy_types
);
833 htab_delete (container
.type_hash
);
834 htab_delete (container
.keyword_hash
);
835 obstack_free (&container
.type_obstack
, NULL
);
839 if (fclose (go_dump_file
) != 0)
840 error ("could not close Go dump file: %m");
844 /* Set up our hooks. */
846 const struct gcc_debug_hooks
*
847 dump_go_spec_init (const char *filename
, const struct gcc_debug_hooks
*hooks
)
849 go_dump_file
= fopen (filename
, "w");
850 if (go_dump_file
== NULL
)
852 error ("could not open Go dump file %qs: %m", filename
);
856 go_debug_hooks
= *hooks
;
857 real_debug_hooks
= hooks
;
859 go_debug_hooks
.finish
= go_finish
;
860 go_debug_hooks
.define
= go_define
;
861 go_debug_hooks
.undef
= go_undef
;
862 go_debug_hooks
.function_decl
= go_function_decl
;
863 go_debug_hooks
.global_decl
= go_global_decl
;
864 go_debug_hooks
.type_decl
= go_type_decl
;
866 macro_hash
= htab_create (100, htab_hash_string
, string_hash_eq
, NULL
);
868 return &go_debug_hooks
;
871 #include "gt-godump.h"