godump.c (go_define): Don't accept a string immediately after another operand.
[gcc.git] / gcc / godump.c
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>.
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
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.
26
27 All global names are output with a leading underscore, so that they
28 are all hidden in Go. */
29
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"
39
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. */
44
45 /* Our debug hooks. This is initialized by dump_go_spec_init. */
46
47 static struct gcc_debug_hooks go_debug_hooks;
48
49 /* The real debug hooks. */
50
51 static const struct gcc_debug_hooks *real_debug_hooks;
52
53 /* The file where we should write information. */
54
55 static FILE *go_dump_file;
56
57 /* A queue of decls to output. */
58
59 static GTY(()) VEC(tree,gc) *queue;
60
61 /* A hash table of macros we have seen. */
62
63 static htab_t macro_hash;
64
65 /* For the hash tables. */
66
67 static int
68 string_hash_eq (const void *y1, const void *y2)
69 {
70 return strcmp ((const char *) y1, (const char *) y2) == 0;
71 }
72
73 /* A macro definition. */
74
75 static void
76 go_define (unsigned int lineno, const char *buffer)
77 {
78 const char *p;
79 const char *name_end;
80 char *out_buffer;
81 char *q;
82 bool saw_operand;
83 bool need_operand;
84 char *copy;
85 hashval_t hashval;
86 void **slot;
87
88 real_debug_hooks->define (lineno, buffer);
89
90 /* Skip macro functions. */
91 for (p = buffer; *p != '\0' && *p != ' '; ++p)
92 if (*p == '(')
93 return;
94
95 if (*p == '\0')
96 return;
97
98 name_end = p;
99
100 ++p;
101 if (*p == '\0')
102 return;
103
104 copy = XNEWVEC (char, name_end - buffer + 1);
105 memcpy (copy, buffer, name_end - buffer);
106 copy[name_end - buffer] = '\0';
107
108 hashval = htab_hash_string (copy);
109 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, NO_INSERT);
110 if (slot != NULL)
111 {
112 XDELETEVEC (copy);
113 return;
114 }
115
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);
119 q = out_buffer;
120 saw_operand = false;
121 need_operand = false;
122 while (*p != '\0')
123 {
124 switch (*p)
125 {
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':
130 case 'Y': case 'Z':
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':
135 case 'y': case 'z':
136 case '_':
137 {
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. */
142 const char *start;
143 char *n;
144
145 if (saw_operand)
146 goto unknown;
147
148 start = p;
149 while (ISALNUM (*p) || *p == '_')
150 ++p;
151 n = XALLOCAVEC (char, p - start + 1);
152 memcpy (n, start, p - start);
153 n[p - start] = '\0';
154 slot = htab_find_slot (macro_hash, n, NO_INSERT);
155 if (slot == NULL || *slot == NULL)
156 {
157 /* This is a reference to a name which was not defined
158 as a macro. */
159 goto unknown;
160 }
161
162 *q++ = '_';
163 memcpy (q, start, p - start);
164 q += p - start;
165
166 saw_operand = true;
167 need_operand = false;
168 }
169 break;
170
171 case '.':
172 if (!ISDIGIT (p[1]))
173 goto unknown;
174 /* Fall through. */
175 case '0': case '1': case '2': case '3': case '4':
176 case '5': case '6': case '7': case '8': case '9':
177 {
178 const char *start;
179 bool is_hex;
180
181 start = p;
182 is_hex = false;
183 if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
184 {
185 p += 2;
186 is_hex = true;
187 }
188 while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
189 || (is_hex
190 && ((*p >= 'a' && *p <= 'f')
191 || (*p >= 'A' && *p <= 'F'))))
192 ++p;
193 memcpy (q, start, p - start);
194 q += p - start;
195 while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
196 || *p == 'f' || *p == 'F'
197 || *p == 'd' || *p == 'D')
198 {
199 /* Go doesn't use any of these trailing type
200 modifiers. */
201 ++p;
202 }
203
204 /* We'll pick up the exponent, if any, as an
205 expression. */
206
207 saw_operand = true;
208 need_operand = false;
209 }
210 break;
211
212 case ' ': case '\t':
213 *q++ = *p++;
214 break;
215
216 case '(':
217 /* Always OK, not part of an operand, presumed to start an
218 operand. */
219 *q++ = *p++;
220 saw_operand = false;
221 need_operand = false;
222 break;
223
224 case ')':
225 /* OK if we don't need an operand, and presumed to indicate
226 an operand. */
227 if (need_operand)
228 goto unknown;
229 *q++ = *p++;
230 saw_operand = true;
231 break;
232
233 case '+': case '-':
234 /* Always OK, but not part of an operand. */
235 *q++ = *p++;
236 saw_operand = false;
237 break;
238
239 case '*': case '/': case '%': case '|': case '&': case '^':
240 /* Must be a binary operator. */
241 if (!saw_operand)
242 goto unknown;
243 *q++ = *p++;
244 saw_operand = false;
245 need_operand = true;
246 break;
247
248 case '=':
249 *q++ = *p++;
250 if (*p != '=')
251 goto unknown;
252 /* Must be a binary operator. */
253 if (!saw_operand)
254 goto unknown;
255 *q++ = *p++;
256 saw_operand = false;
257 need_operand = true;
258 break;
259
260 case '!':
261 *q++ = *p++;
262 if (*p == '=')
263 {
264 /* Must be a binary operator. */
265 if (!saw_operand)
266 goto unknown;
267 *q++ = *p++;
268 saw_operand = false;
269 need_operand = true;
270 }
271 else
272 {
273 /* Must be a unary operator. */
274 if (saw_operand)
275 goto unknown;
276 need_operand = true;
277 }
278 break;
279
280 case '<': case '>':
281 /* Must be a binary operand, may be << or >> or <= or >=. */
282 if (!saw_operand)
283 goto unknown;
284 *q++ = *p++;
285 if (*p == *(p - 1) || *p == '=')
286 *q++ = *p++;
287 saw_operand = false;
288 need_operand = true;
289 break;
290
291 case '~':
292 /* Must be a unary operand, must be translated for Go. */
293 if (saw_operand)
294 goto unknown;
295 *q++ = '^';
296 p++;
297 need_operand = true;
298 break;
299
300 case '"':
301 case '\'':
302 {
303 char quote;
304
305 if (saw_operand)
306 goto unknown;
307 quote = *p;
308 *q++ = *p++;
309 while (*p != quote)
310 {
311 int c;
312
313 if (*p == '\0')
314 goto unknown;
315
316 if (*p != '\\')
317 {
318 *q++ = *p++;
319 continue;
320 }
321
322 *q++ = *p++;
323 switch (*p)
324 {
325 case '0': case '1': case '2': case '3':
326 case '4': case '5': case '6': case '7':
327 c = 0;
328 while (*p >= '0' && *p <= '7')
329 {
330 *q++ = *p++;
331 ++c;
332 }
333 /* Go octal characters are always 3
334 digits. */
335 if (c != 3)
336 goto unknown;
337 break;
338
339 case 'x':
340 *q++ = *p++;
341 c = 0;
342 while (ISXDIGIT (*p))
343 {
344 *q++ = *p++;
345 ++c;
346 }
347 /* Go hex characters are always 2 digits. */
348 if (c != 2)
349 goto unknown;
350 break;
351
352 case 'a': case 'b': case 'f': case 'n': case 'r':
353 case 't': case 'v': case '\\': case '\'': case '"':
354 *q++ = *p++;
355 break;
356
357 default:
358 goto unknown;
359 }
360 }
361 *q++ = *p++;
362 break;
363 }
364
365 default:
366 goto unknown;
367 }
368 }
369
370 if (need_operand)
371 goto unknown;
372
373 *q = '\0';
374
375 slot = htab_find_slot_with_hash (macro_hash, copy, hashval, INSERT);
376 *slot = copy;
377
378 fprintf (go_dump_file, "const _%s = %s\n", copy, out_buffer);
379
380 XDELETEVEC (out_buffer);
381 return;
382
383 unknown:
384 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
385 XDELETEVEC (out_buffer);
386 XDELETEVEC (copy);
387 }
388
389 /* A macro undef. */
390
391 static void
392 go_undef (unsigned int lineno, const char *buffer)
393 {
394 void **slot;
395
396 real_debug_hooks->undef (lineno, buffer);
397
398 slot = htab_find_slot (macro_hash, buffer, NO_INSERT);
399 if (slot == NULL)
400 return;
401 fprintf (go_dump_file, "// undef _%s\n", buffer);
402 /* We don't delete the slot from the hash table because that will
403 cause a duplicate const definition. */
404 }
405
406 /* A function or variable decl. */
407
408 static void
409 go_decl (tree decl)
410 {
411 if (!TREE_PUBLIC (decl)
412 || DECL_IS_BUILTIN (decl)
413 || DECL_NAME (decl) == NULL_TREE)
414 return;
415 VEC_safe_push (tree, gc, queue, decl);
416 }
417
418 /* A function decl. */
419
420 static void
421 go_function_decl (tree decl)
422 {
423 real_debug_hooks->function_decl (decl);
424 go_decl (decl);
425 }
426
427 /* A global variable decl. */
428
429 static void
430 go_global_decl (tree decl)
431 {
432 real_debug_hooks->global_decl (decl);
433 go_decl (decl);
434 }
435
436 /* A type declaration. */
437
438 static void
439 go_type_decl (tree decl, int local)
440 {
441 real_debug_hooks->type_decl (decl, local);
442
443 if (local || DECL_IS_BUILTIN (decl))
444 return;
445 if (DECL_NAME (decl) == NULL_TREE
446 && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
447 || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
448 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
449 return;
450 VEC_safe_push (tree, gc, queue, decl);
451 }
452
453 /* A container for the data we pass around when generating information
454 at the end of the compilation. */
455
456 struct godump_container
457 {
458 /* DECLs that we have already seen. */
459 struct pointer_set_t *decls_seen;
460
461 /* Types which may potentially have to be defined as dummy
462 types. */
463 struct pointer_set_t *pot_dummy_types;
464
465 /* Go keywords. */
466 htab_t keyword_hash;
467
468 /* Global type definitions. */
469 htab_t type_hash;
470
471 /* Invalid types. */
472 htab_t invalid_hash;
473
474 /* Obstack used to write out a type definition. */
475 struct obstack type_obstack;
476 };
477
478 /* Append an IDENTIFIER_NODE to OB. */
479
480 static void
481 go_append_string (struct obstack *ob, tree id)
482 {
483 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
484 }
485
486 /* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
487 USE_TYPE_NAME is true if we can simply use a type name here without
488 needing to define it. IS_FUNC_OK is true if we can output a func
489 type here; the "func" keyword will already have been added. Return
490 true if the type can be represented in Go, false otherwise. */
491
492 static bool
493 go_format_type (struct godump_container *container, tree type,
494 bool use_type_name, bool is_func_ok)
495 {
496 bool ret;
497 struct obstack *ob;
498
499 ret = true;
500 ob = &container->type_obstack;
501
502 if (TYPE_NAME (type) != NULL_TREE
503 && (pointer_set_contains (container->decls_seen, type)
504 || pointer_set_contains (container->decls_seen, TYPE_NAME (type)))
505 && (AGGREGATE_TYPE_P (type)
506 || POINTER_TYPE_P (type)
507 || TREE_CODE (type) == FUNCTION_TYPE))
508 {
509 tree name;
510 void **slot;
511
512 name = TYPE_NAME (type);
513 if (TREE_CODE (name) == TYPE_DECL)
514 name = DECL_NAME (name);
515
516 slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
517 NO_INSERT);
518 if (slot != NULL)
519 ret = false;
520
521 obstack_1grow (ob, '_');
522 go_append_string (ob, name);
523 return ret;
524 }
525
526 pointer_set_insert (container->decls_seen, type);
527
528 switch (TREE_CODE (type))
529 {
530 case ENUMERAL_TYPE:
531 obstack_grow (ob, "int", 3);
532 break;
533
534 case TYPE_DECL:
535 obstack_1grow (ob, '_');
536 go_append_string (ob, DECL_NAME (type));
537 break;
538
539 case INTEGER_TYPE:
540 {
541 const char *s;
542 char buf[100];
543
544 switch (TYPE_PRECISION (type))
545 {
546 case 8:
547 s = TYPE_UNSIGNED (type) ? "uint8" : "int8";
548 break;
549 case 16:
550 s = TYPE_UNSIGNED (type) ? "uint16" : "int16";
551 break;
552 case 32:
553 s = TYPE_UNSIGNED (type) ? "uint32" : "int32";
554 break;
555 case 64:
556 s = TYPE_UNSIGNED (type) ? "uint64" : "int64";
557 break;
558 default:
559 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
560 TYPE_PRECISION (type),
561 TYPE_UNSIGNED (type) ? "u" : "");
562 s = buf;
563 ret = false;
564 break;
565 }
566 obstack_grow (ob, s, strlen (s));
567 }
568 break;
569
570 case REAL_TYPE:
571 {
572 const char *s;
573 char buf[100];
574
575 switch (TYPE_PRECISION (type))
576 {
577 case 32:
578 s = "float32";
579 break;
580 case 64:
581 s = "float64";
582 break;
583 default:
584 snprintf (buf, sizeof buf, "INVALID-float-%u",
585 TYPE_PRECISION (type));
586 s = buf;
587 ret = false;
588 break;
589 }
590 obstack_grow (ob, s, strlen (s));
591 }
592 break;
593
594 case BOOLEAN_TYPE:
595 obstack_grow (ob, "bool", 4);
596 break;
597
598 case POINTER_TYPE:
599 if (use_type_name
600 && TYPE_NAME (TREE_TYPE (type)) != NULL_TREE
601 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))
602 || (POINTER_TYPE_P (TREE_TYPE (type))
603 && (TREE_CODE (TREE_TYPE (TREE_TYPE (type)))
604 == FUNCTION_TYPE))))
605 {
606 tree name;
607
608 name = TYPE_NAME (TREE_TYPE (type));
609 if (TREE_CODE (name) == IDENTIFIER_NODE)
610 {
611 obstack_grow (ob, "*_", 2);
612 go_append_string (ob, name);
613
614 /* The pointer here can be used without the struct or
615 union definition. So this struct or union is a a
616 potential dummy type. */
617 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
618 pointer_set_insert (container->pot_dummy_types,
619 IDENTIFIER_POINTER (name));
620
621 return ret;
622 }
623 else if (TREE_CODE (name) == TYPE_DECL)
624 {
625 obstack_grow (ob, "*_", 2);
626 go_append_string (ob, DECL_NAME (name));
627 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type)))
628 pointer_set_insert (container->pot_dummy_types,
629 IDENTIFIER_POINTER (DECL_NAME (name)));
630 return ret;
631 }
632 }
633 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
634 obstack_grow (ob, "func", 4);
635 else
636 obstack_1grow (ob, '*');
637 if (VOID_TYPE_P (TREE_TYPE (type)))
638 obstack_grow (ob, "byte", 4);
639 else
640 {
641 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
642 true))
643 ret = false;
644 }
645 break;
646
647 case ARRAY_TYPE:
648 obstack_1grow (ob, '[');
649 if (TYPE_DOMAIN (type) != NULL_TREE
650 && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
651 && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
652 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
653 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
654 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
655 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
656 && host_integerp (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0))
657 {
658 char buf[100];
659
660 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
661 tree_low_cst (TYPE_MAX_VALUE (TYPE_DOMAIN (type)), 0));
662 obstack_grow (ob, buf, strlen (buf));
663 }
664 obstack_1grow (ob, ']');
665 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false))
666 ret = false;
667 break;
668
669 case UNION_TYPE:
670 case RECORD_TYPE:
671 {
672 tree field;
673 int i;
674
675 obstack_grow (ob, "struct { ", 9);
676 i = 0;
677 for (field = TYPE_FIELDS (type);
678 field != NULL_TREE;
679 field = TREE_CHAIN (field))
680 {
681 if (DECL_NAME (field) == NULL)
682 {
683 char buf[100];
684
685 obstack_grow (ob, "Godump_", 2);
686 snprintf (buf, sizeof buf, "%d", i);
687 obstack_grow (ob, buf, strlen (buf));
688 i++;
689 }
690 else
691 {
692 const char *var_name;
693 void **slot;
694
695 /* Start variable name with an underscore if a keyword. */
696 var_name = IDENTIFIER_POINTER (DECL_NAME (field));
697 slot = htab_find_slot (container->keyword_hash, var_name,
698 NO_INSERT);
699 if (slot != NULL)
700 obstack_1grow (ob, '_');
701 go_append_string (ob, DECL_NAME (field));
702 }
703 obstack_1grow (ob, ' ');
704 if (DECL_BIT_FIELD (field))
705 {
706 obstack_grow (ob, "INVALID-bit-field", 17);
707 ret = false;
708 }
709 else
710 {
711 /* Do not expand type if a record or union type or a
712 function pointer. */
713 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
714 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
715 || (POINTER_TYPE_P (TREE_TYPE (field))
716 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
717 == FUNCTION_TYPE))))
718 {
719 tree name = TYPE_NAME (TREE_TYPE (field));
720 if (TREE_CODE (name) == IDENTIFIER_NODE)
721 {
722 obstack_1grow (ob, '_');
723 go_append_string (ob, name);
724 }
725 else if (TREE_CODE (name) == TYPE_DECL)
726 {
727 obstack_1grow (ob, '_');
728 go_append_string (ob, DECL_NAME (name));
729 }
730 }
731 else
732 {
733 if (!go_format_type (container, TREE_TYPE (field), true,
734 false))
735 ret = false;
736 }
737 }
738 obstack_grow (ob, "; ", 2);
739
740 /* Only output the first field of a union, and hope for
741 the best. */
742 if (TREE_CODE (type) == UNION_TYPE)
743 break;
744 }
745 obstack_1grow (ob, '}');
746 }
747 break;
748
749 case FUNCTION_TYPE:
750 {
751 tree arg_type;
752 bool is_varargs;
753 tree result;
754 function_args_iterator iter;
755 bool seen_arg;
756
757 /* Go has no way to write a type which is a function but not a
758 pointer to a function. */
759 if (!is_func_ok)
760 {
761 obstack_grow (ob, "func*", 5);
762 ret = false;
763 }
764
765 obstack_1grow (ob, '(');
766 is_varargs = stdarg_p (type);
767 seen_arg = false;
768 FOREACH_FUNCTION_ARGS (type, arg_type, iter)
769 {
770 if (VOID_TYPE_P (arg_type))
771 break;
772 if (seen_arg)
773 obstack_grow (ob, ", ", 2);
774 if (!go_format_type (container, arg_type, true, false))
775 ret = false;
776 seen_arg = true;
777 }
778 if (is_varargs)
779 {
780 if (prototype_p (type))
781 obstack_grow (ob, ", ", 2);
782 obstack_grow (ob, "...interface{}", 14);
783 }
784 obstack_1grow (ob, ')');
785
786 result = TREE_TYPE (type);
787 if (!VOID_TYPE_P (result))
788 {
789 obstack_1grow (ob, ' ');
790 if (!go_format_type (container, result, use_type_name, false))
791 ret = false;
792 }
793 }
794 break;
795
796 default:
797 obstack_grow (ob, "INVALID-type", 12);
798 ret = false;
799 break;
800 }
801
802 return ret;
803 }
804
805 /* Output the type which was built on the type obstack, and then free
806 it. */
807
808 static void
809 go_output_type (struct godump_container *container)
810 {
811 struct obstack *ob;
812
813 ob = &container->type_obstack;
814 obstack_1grow (ob, '\0');
815 fputs (obstack_base (ob), go_dump_file);
816 obstack_free (ob, obstack_base (ob));
817 }
818
819 /* Output a function declaration. */
820
821 static void
822 go_output_fndecl (struct godump_container *container, tree decl)
823 {
824 if (!go_format_type (container, TREE_TYPE (decl), false, true))
825 fprintf (go_dump_file, "// ");
826 fprintf (go_dump_file, "func _%s ",
827 IDENTIFIER_POINTER (DECL_NAME (decl)));
828 go_output_type (container);
829 fprintf (go_dump_file, " __asm__(\"%s\")\n",
830 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
831 }
832
833 /* Output a typedef or something like a struct definition. */
834
835 static void
836 go_output_typedef (struct godump_container *container, tree decl)
837 {
838 /* If we have an enum type, output the enum constants
839 separately. */
840 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
841 && TYPE_SIZE (TREE_TYPE (decl)) != 0
842 && !pointer_set_contains (container->decls_seen, TREE_TYPE (decl))
843 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
844 || !pointer_set_contains (container->decls_seen,
845 TYPE_CANONICAL (TREE_TYPE (decl)))))
846 {
847 tree element;
848
849 for (element = TYPE_VALUES (TREE_TYPE (decl));
850 element != NULL_TREE;
851 element = TREE_CHAIN (element))
852 {
853 const char *name;
854 void **slot;
855
856 name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
857
858 /* Sometimes a name will be defined as both an enum constant
859 and a macro. Avoid duplicate definition errors by
860 treating enum constants as macros. */
861 slot = htab_find_slot (macro_hash, name, INSERT);
862 if (*slot == NULL)
863 {
864 *slot = CONST_CAST (char *, name);
865 fprintf (go_dump_file,
866 "const _%s = " HOST_WIDE_INT_PRINT_DEC "\n",
867 name, tree_low_cst (TREE_VALUE (element), 0));
868 }
869 }
870 pointer_set_insert (container->decls_seen, TREE_TYPE (decl));
871 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
872 pointer_set_insert (container->decls_seen,
873 TYPE_CANONICAL (TREE_TYPE (decl)));
874 }
875
876 if (DECL_NAME (decl) != NULL_TREE)
877 {
878 void **slot;
879 const char *type;
880
881 type = IDENTIFIER_POINTER (DECL_NAME (decl));
882 /* If type defined already, skip. */
883 slot = htab_find_slot (container->type_hash, type, INSERT);
884 if (*slot != NULL)
885 return;
886 *slot = CONST_CAST (void *, (const void *) type);
887
888 if (!go_format_type (container, TREE_TYPE (decl), false, false))
889 {
890 fprintf (go_dump_file, "// ");
891 slot = htab_find_slot (container->invalid_hash, type, INSERT);
892 *slot = CONST_CAST (void *, (const void *) type);
893 }
894 fprintf (go_dump_file, "type _%s ",
895 IDENTIFIER_POINTER (DECL_NAME (decl)));
896 go_output_type (container);
897 pointer_set_insert (container->decls_seen, decl);
898 }
899 else if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
900 {
901 void **slot;
902 const char *type;
903
904 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
905 /* If type defined already, skip. */
906 slot = htab_find_slot (container->type_hash, type, INSERT);
907 if (*slot != NULL)
908 return;
909 *slot = CONST_CAST (void *, (const void *) type);
910
911 if (!go_format_type (container, TREE_TYPE (decl), false, false))
912 {
913 fprintf (go_dump_file, "// ");
914 slot = htab_find_slot (container->invalid_hash, type, INSERT);
915 *slot = CONST_CAST (void *, (const void *) type);
916 }
917 fprintf (go_dump_file, "type _%s ",
918 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
919 go_output_type (container);
920 }
921 else
922 return;
923
924 fprintf (go_dump_file, "\n");
925 }
926
927 /* Output a variable. */
928
929 static void
930 go_output_var (struct godump_container *container, tree decl)
931 {
932 bool is_valid;
933
934 if (pointer_set_contains (container->decls_seen, decl)
935 || pointer_set_contains (container->decls_seen, DECL_NAME (decl)))
936 return;
937 pointer_set_insert (container->decls_seen, decl);
938 pointer_set_insert (container->decls_seen, DECL_NAME (decl));
939
940 is_valid = go_format_type (container, TREE_TYPE (decl), true, false);
941 if (is_valid
942 && htab_find_slot (container->type_hash,
943 IDENTIFIER_POINTER (DECL_NAME (decl)),
944 NO_INSERT) != NULL)
945 {
946 /* There is already a type with this name, probably from a
947 struct tag. Prefer the type to the variable. */
948 is_valid = false;
949 }
950 if (!is_valid)
951 fprintf (go_dump_file, "// ");
952
953 fprintf (go_dump_file, "var _%s ",
954 IDENTIFIER_POINTER (DECL_NAME (decl)));
955 go_output_type (container);
956 fprintf (go_dump_file, "\n");
957
958 /* Sometimes an extern variable is declared with an unknown struct
959 type. */
960 if (TYPE_NAME (TREE_TYPE (decl)) != NULL_TREE
961 && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
962 {
963 tree type_name = TYPE_NAME (TREE_TYPE (decl));
964 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
965 pointer_set_insert (container->pot_dummy_types,
966 IDENTIFIER_POINTER (type_name));
967 else if (TREE_CODE (type_name) == TYPE_DECL)
968 pointer_set_insert (container->pot_dummy_types,
969 IDENTIFIER_POINTER (DECL_NAME (type_name)));
970 }
971 }
972
973 /* Build a hash table with the Go keywords. */
974
975 static const char * const keywords[] = {
976 "__asm__", "break", "case", "chan", "const", "continue", "default",
977 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
978 "import", "interface", "map", "package", "range", "return", "select",
979 "struct", "switch", "type", "var"
980 };
981
982 static void
983 keyword_hash_init (struct godump_container *container)
984 {
985 size_t i;
986 size_t count = sizeof (keywords) / sizeof (keywords[0]);
987 void **slot;
988
989 for (i = 0; i < count; i++)
990 {
991 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
992 *slot = CONST_CAST (void *, (const void *) keywords[i]);
993 }
994 }
995
996 /* Traversing the pot_dummy_types and seeing which types are present
997 in the global types hash table and creating dummy definitions if
998 not found. This function is invoked by pointer_set_traverse. */
999
1000 static bool
1001 find_dummy_types (const void *ptr, void *adata)
1002 {
1003 struct godump_container *data = (struct godump_container *) adata;
1004 const char *type = (const char *) ptr;
1005 void **slot;
1006
1007 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1008 if (slot == NULL)
1009 fprintf (go_dump_file, "type _%s struct {}\n", type);
1010 return true;
1011 }
1012
1013 /* Output symbols. */
1014
1015 static void
1016 go_finish (const char *filename)
1017 {
1018 struct godump_container container;
1019 unsigned int ix;
1020 tree decl;
1021
1022 real_debug_hooks->finish (filename);
1023
1024 container.decls_seen = pointer_set_create ();
1025 container.pot_dummy_types = pointer_set_create ();
1026 container.type_hash = htab_create (100, htab_hash_string,
1027 string_hash_eq, NULL);
1028 container.invalid_hash = htab_create (10, htab_hash_string,
1029 string_hash_eq, NULL);
1030 container.keyword_hash = htab_create (50, htab_hash_string,
1031 string_hash_eq, NULL);
1032 obstack_init (&container.type_obstack);
1033
1034 keyword_hash_init (&container);
1035
1036 FOR_EACH_VEC_ELT (tree, queue, ix, decl)
1037 {
1038 switch (TREE_CODE (decl))
1039 {
1040 case FUNCTION_DECL:
1041 go_output_fndecl (&container, decl);
1042 break;
1043
1044 case TYPE_DECL:
1045 go_output_typedef (&container, decl);
1046 break;
1047
1048 case VAR_DECL:
1049 go_output_var (&container, decl);
1050 break;
1051
1052 default:
1053 gcc_unreachable();
1054 }
1055 }
1056
1057 /* To emit dummy definitions. */
1058 pointer_set_traverse (container.pot_dummy_types, find_dummy_types,
1059 (void *) &container);
1060
1061 pointer_set_destroy (container.decls_seen);
1062 pointer_set_destroy (container.pot_dummy_types);
1063 htab_delete (container.type_hash);
1064 htab_delete (container.invalid_hash);
1065 htab_delete (container.keyword_hash);
1066 obstack_free (&container.type_obstack, NULL);
1067
1068 queue = NULL;
1069
1070 if (fclose (go_dump_file) != 0)
1071 error ("could not close Go dump file: %m");
1072 go_dump_file = NULL;
1073 }
1074
1075 /* Set up our hooks. */
1076
1077 const struct gcc_debug_hooks *
1078 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1079 {
1080 go_dump_file = fopen (filename, "w");
1081 if (go_dump_file == NULL)
1082 {
1083 error ("could not open Go dump file %qs: %m", filename);
1084 return hooks;
1085 }
1086
1087 go_debug_hooks = *hooks;
1088 real_debug_hooks = hooks;
1089
1090 go_debug_hooks.finish = go_finish;
1091 go_debug_hooks.define = go_define;
1092 go_debug_hooks.undef = go_undef;
1093 go_debug_hooks.function_decl = go_function_decl;
1094 go_debug_hooks.global_decl = go_global_decl;
1095 go_debug_hooks.type_decl = go_type_decl;
1096
1097 macro_hash = htab_create (100, htab_hash_string, string_hash_eq, NULL);
1098
1099 return &go_debug_hooks;
1100 }
1101
1102 #include "gt-godump.h"