]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/godump.c
go: use htab_eq_string in godump
[thirdparty/gcc.git] / gcc / godump.c
CommitLineData
c6a13190 1/* Output Go language descriptions of types.
99dee823 2 Copyright (C) 2008-2021 Free Software Foundation, Inc.
c6a13190
ILT
3 Written by Ian Lance Taylor <iant@google.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along 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"
957060b5 33#include "tree.h"
957060b5 34#include "diagnostic-core.h"
957060b5 35#include "debug.h"
4bbed9ce 36#include "stor-layout.h"
c6a13190
ILT
37
38/* We dump this information from the debug hooks. This gives us a
39 stable and maintainable API to hook into. In order to work
40 correctly when -g is used, we build our own hooks structure which
41 wraps the hooks we need to change. */
42
43/* Our debug hooks. This is initialized by dump_go_spec_init. */
44
45static struct gcc_debug_hooks go_debug_hooks;
46
47/* The real debug hooks. */
48
49static const struct gcc_debug_hooks *real_debug_hooks;
50
51/* The file where we should write information. */
52
53static FILE *go_dump_file;
54
55/* A queue of decls to output. */
56
9771b263 57static GTY(()) vec<tree, va_gc> *queue;
c6a13190
ILT
58
59/* A hash table of macros we have seen. */
60
61static htab_t macro_hash;
62
5743331e
ILT
63/* The type of a value in macro_hash. */
64
65struct macro_hash_value
66{
67 /* The name stored in the hash table. */
68 char *name;
69 /* The value of the macro. */
70 char *value;
71};
72
4bbed9ce
DV
73/* Returns the number of units necessary to represent an integer with the given
74 PRECISION (in bits). */
75
76static inline unsigned int
77precision_to_units (unsigned int precision)
78{
79 return (precision + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
80}
81
5743331e
ILT
82/* Calculate the hash value for an entry in the macro hash table. */
83
84static hashval_t
85macro_hash_hashval (const void *val)
86{
87 const struct macro_hash_value *mhval = (const struct macro_hash_value *) val;
88 return htab_hash_string (mhval->name);
89}
90
91/* Compare values in the macro hash table for equality. */
92
93static int
94macro_hash_eq (const void *v1, const void *v2)
95{
96 const struct macro_hash_value *mhv1 = (const struct macro_hash_value *) v1;
97 const struct macro_hash_value *mhv2 = (const struct macro_hash_value *) v2;
98 return strcmp (mhv1->name, mhv2->name) == 0;
99}
100
101/* Free values deleted from the macro hash table. */
102
103static void
104macro_hash_del (void *v)
105{
106 struct macro_hash_value *mhv = (struct macro_hash_value *) v;
107 XDELETEVEC (mhv->name);
108 XDELETEVEC (mhv->value);
109 XDELETE (mhv);
110}
111
c6a13190
ILT
112/* A macro definition. */
113
114static void
115go_define (unsigned int lineno, const char *buffer)
116{
117 const char *p;
118 const char *name_end;
5743331e 119 size_t out_len;
c6a13190
ILT
120 char *out_buffer;
121 char *q;
82c03907
ILT
122 bool saw_operand;
123 bool need_operand;
5743331e 124 struct macro_hash_value *mhval;
c6a13190
ILT
125 char *copy;
126 hashval_t hashval;
127 void **slot;
128
129 real_debug_hooks->define (lineno, buffer);
130
131 /* Skip macro functions. */
132 for (p = buffer; *p != '\0' && *p != ' '; ++p)
133 if (*p == '(')
134 return;
135
136 if (*p == '\0')
137 return;
138
139 name_end = p;
140
141 ++p;
142 if (*p == '\0')
143 return;
144
145 copy = XNEWVEC (char, name_end - buffer + 1);
146 memcpy (copy, buffer, name_end - buffer);
147 copy[name_end - buffer] = '\0';
148
5743331e
ILT
149 mhval = XNEW (struct macro_hash_value);
150 mhval->name = copy;
151 mhval->value = NULL;
152
c6a13190 153 hashval = htab_hash_string (copy);
5743331e 154 slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, NO_INSERT);
c6a13190
ILT
155
156 /* For simplicity, we force all names to be hidden by adding an
157 initial underscore, and let the user undo this as needed. */
5743331e
ILT
158 out_len = strlen (p) * 2 + 1;
159 out_buffer = XNEWVEC (char, out_len);
c6a13190 160 q = out_buffer;
82c03907
ILT
161 saw_operand = false;
162 need_operand = false;
c6a13190
ILT
163 while (*p != '\0')
164 {
82c03907 165 switch (*p)
c6a13190 166 {
82c03907
ILT
167 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
168 case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
169 case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
170 case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
171 case 'Y': case 'Z':
172 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
173 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
174 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
175 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
176 case 'y': case 'z':
177 case '_':
178 {
179 /* The start of an identifier. Technically we should also
180 worry about UTF-8 identifiers, but they are not a
181 problem for practical uses of -fdump-go-spec so we
182 don't worry about them. */
183 const char *start;
184 char *n;
5743331e 185 struct macro_hash_value idval;
82c03907 186
9b798ac5
ILT
187 if (saw_operand)
188 goto unknown;
189
82c03907
ILT
190 start = p;
191 while (ISALNUM (*p) || *p == '_')
192 ++p;
193 n = XALLOCAVEC (char, p - start + 1);
194 memcpy (n, start, p - start);
195 n[p - start] = '\0';
5743331e
ILT
196 idval.name = n;
197 idval.value = NULL;
198 if (htab_find (macro_hash, &idval) == NULL)
82c03907
ILT
199 {
200 /* This is a reference to a name which was not defined
201 as a macro. */
202 goto unknown;
203 }
204
205 *q++ = '_';
206 memcpy (q, start, p - start);
207 q += p - start;
208
209 saw_operand = true;
210 need_operand = false;
211 }
212 break;
213
214 case '.':
215 if (!ISDIGIT (p[1]))
216 goto unknown;
217 /* Fall through. */
218 case '0': case '1': case '2': case '3': case '4':
219 case '5': case '6': case '7': case '8': case '9':
220 {
221 const char *start;
222 bool is_hex;
223
224 start = p;
225 is_hex = false;
226 if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
227 {
228 p += 2;
229 is_hex = true;
230 }
231 while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
232 || (is_hex
233 && ((*p >= 'a' && *p <= 'f')
234 || (*p >= 'A' && *p <= 'F'))))
235 ++p;
236 memcpy (q, start, p - start);
237 q += p - start;
238 while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
239 || *p == 'f' || *p == 'F'
240 || *p == 'd' || *p == 'D')
241 {
242 /* Go doesn't use any of these trailing type
243 modifiers. */
244 ++p;
245 }
246
247 /* We'll pick up the exponent, if any, as an
248 expression. */
249
250 saw_operand = true;
251 need_operand = false;
252 }
253 break;
254
255 case ' ': case '\t':
256 *q++ = *p++;
257 break;
258
259 case '(':
260 /* Always OK, not part of an operand, presumed to start an
261 operand. */
262 *q++ = *p++;
263 saw_operand = false;
264 need_operand = false;
265 break;
266
267 case ')':
268 /* OK if we don't need an operand, and presumed to indicate
269 an operand. */
270 if (need_operand)
271 goto unknown;
272 *q++ = *p++;
273 saw_operand = true;
274 break;
275
276 case '+': case '-':
277 /* Always OK, but not part of an operand. */
278 *q++ = *p++;
279 saw_operand = false;
280 break;
281
282 case '*': case '/': case '%': case '|': case '&': case '^':
283 /* Must be a binary operator. */
284 if (!saw_operand)
285 goto unknown;
286 *q++ = *p++;
287 saw_operand = false;
288 need_operand = true;
289 break;
290
291 case '=':
292 *q++ = *p++;
293 if (*p != '=')
294 goto unknown;
295 /* Must be a binary operator. */
296 if (!saw_operand)
297 goto unknown;
298 *q++ = *p++;
299 saw_operand = false;
300 need_operand = true;
301 break;
302
303 case '!':
304 *q++ = *p++;
305 if (*p == '=')
c6a13190 306 {
82c03907
ILT
307 /* Must be a binary operator. */
308 if (!saw_operand)
309 goto unknown;
310 *q++ = *p++;
311 saw_operand = false;
312 need_operand = true;
c6a13190 313 }
82c03907 314 else
c6a13190 315 {
82c03907
ILT
316 /* Must be a unary operator. */
317 if (saw_operand)
318 goto unknown;
319 need_operand = true;
c6a13190 320 }
82c03907
ILT
321 break;
322
323 case '<': case '>':
324 /* Must be a binary operand, may be << or >> or <= or >=. */
325 if (!saw_operand)
326 goto unknown;
327 *q++ = *p++;
328 if (*p == *(p - 1) || *p == '=')
329 *q++ = *p++;
330 saw_operand = false;
331 need_operand = true;
332 break;
333
334 case '~':
335 /* Must be a unary operand, must be translated for Go. */
336 if (saw_operand)
337 goto unknown;
338 *q++ = '^';
339 p++;
340 need_operand = true;
341 break;
342
343 case '"':
344 case '\'':
345 {
936fd13c 346 char quote;
9e4ef69e 347 int count;
936fd13c
ILT
348
349 if (saw_operand)
350 goto unknown;
351 quote = *p;
82c03907 352 *q++ = *p++;
9e4ef69e 353 count = 0;
82c03907
ILT
354 while (*p != quote)
355 {
356 int c;
357
358 if (*p == '\0')
359 goto unknown;
360
9e4ef69e
ILT
361 ++count;
362
82c03907
ILT
363 if (*p != '\\')
364 {
365 *q++ = *p++;
366 continue;
367 }
368
369 *q++ = *p++;
370 switch (*p)
371 {
372 case '0': case '1': case '2': case '3':
373 case '4': case '5': case '6': case '7':
374 c = 0;
375 while (*p >= '0' && *p <= '7')
376 {
377 *q++ = *p++;
378 ++c;
379 }
380 /* Go octal characters are always 3
381 digits. */
382 if (c != 3)
383 goto unknown;
384 break;
385
386 case 'x':
387 *q++ = *p++;
388 c = 0;
389 while (ISXDIGIT (*p))
390 {
391 *q++ = *p++;
392 ++c;
393 }
394 /* Go hex characters are always 2 digits. */
395 if (c != 2)
396 goto unknown;
397 break;
398
399 case 'a': case 'b': case 'f': case 'n': case 'r':
400 case 't': case 'v': case '\\': case '\'': case '"':
401 *q++ = *p++;
402 break;
403
404 default:
405 goto unknown;
406 }
407 }
9e4ef69e 408
82c03907 409 *q++ = *p++;
9e4ef69e
ILT
410
411 if (quote == '\'' && count != 1)
412 goto unknown;
413
414 saw_operand = true;
415 need_operand = false;
416
82c03907
ILT
417 break;
418 }
419
420 default:
421 goto unknown;
c6a13190
ILT
422 }
423 }
82c03907
ILT
424
425 if (need_operand)
426 goto unknown;
427
5743331e 428 gcc_assert ((size_t) (q - out_buffer) < out_len);
c6a13190
ILT
429 *q = '\0';
430
5743331e 431 mhval->value = out_buffer;
c6a13190 432
5743331e
ILT
433 if (slot == NULL)
434 {
435 slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, INSERT);
436 gcc_assert (slot != NULL && *slot == NULL);
437 }
438 else
439 {
440 if (*slot != NULL)
441 macro_hash_del (*slot);
442 }
443
444 *slot = mhval;
c6a13190 445
82c03907
ILT
446 return;
447
448 unknown:
449 fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
5743331e
ILT
450 if (slot != NULL)
451 htab_clear_slot (macro_hash, slot);
82c03907
ILT
452 XDELETEVEC (out_buffer);
453 XDELETEVEC (copy);
c6a13190
ILT
454}
455
456/* A macro undef. */
457
458static void
459go_undef (unsigned int lineno, const char *buffer)
460{
5743331e 461 struct macro_hash_value mhval;
c6a13190
ILT
462 void **slot;
463
464 real_debug_hooks->undef (lineno, buffer);
465
5743331e
ILT
466 mhval.name = CONST_CAST (char *, buffer);
467 mhval.value = NULL;
468 slot = htab_find_slot (macro_hash, &mhval, NO_INSERT);
469 if (slot != NULL)
470 htab_clear_slot (macro_hash, slot);
c6a13190
ILT
471}
472
473/* A function or variable decl. */
474
475static void
476go_decl (tree decl)
477{
478 if (!TREE_PUBLIC (decl)
ba649812 479 || DECL_IS_UNDECLARED_BUILTIN (decl)
c6a13190
ILT
480 || DECL_NAME (decl) == NULL_TREE)
481 return;
9771b263 482 vec_safe_push (queue, decl);
c6a13190
ILT
483}
484
485/* A function decl. */
486
487static void
488go_function_decl (tree decl)
489{
490 real_debug_hooks->function_decl (decl);
491 go_decl (decl);
492}
493
d7438551
AH
494static void
495go_early_global_decl (tree decl)
496{
497 go_decl (decl);
ff9baa5f
PMR
498 if (TREE_CODE (decl) != FUNCTION_DECL || DECL_STRUCT_FUNCTION (decl) != NULL)
499 real_debug_hooks->early_global_decl (decl);
d7438551
AH
500}
501
c6a13190
ILT
502/* A global variable decl. */
503
504static void
d7438551 505go_late_global_decl (tree decl)
c6a13190 506{
d7438551 507 real_debug_hooks->late_global_decl (decl);
c6a13190
ILT
508}
509
510/* A type declaration. */
511
512static void
513go_type_decl (tree decl, int local)
514{
515 real_debug_hooks->type_decl (decl, local);
516
ba649812 517 if (local || DECL_IS_UNDECLARED_BUILTIN (decl))
c6a13190
ILT
518 return;
519 if (DECL_NAME (decl) == NULL_TREE
520 && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
521 || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
522 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
523 return;
9771b263 524 vec_safe_push (queue, decl);
c6a13190
ILT
525}
526
527/* A container for the data we pass around when generating information
528 at the end of the compilation. */
529
6c1dae73 530class godump_container
c6a13190 531{
6c1dae73 532public:
c6a13190 533 /* DECLs that we have already seen. */
6e2830c3 534 hash_set<tree> decls_seen;
c6a13190
ILT
535
536 /* Types which may potentially have to be defined as dummy
537 types. */
6e2830c3 538 hash_set<const char *> pot_dummy_types;
c6a13190
ILT
539
540 /* Go keywords. */
541 htab_t keyword_hash;
542
543 /* Global type definitions. */
544 htab_t type_hash;
545
f17333e3
ILT
546 /* Invalid types. */
547 htab_t invalid_hash;
548
c6a13190
ILT
549 /* Obstack used to write out a type definition. */
550 struct obstack type_obstack;
551};
552
553/* Append an IDENTIFIER_NODE to OB. */
554
555static void
556go_append_string (struct obstack *ob, tree id)
557{
558 obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
559}
560
4bbed9ce
DV
561/* Given an integer PRECISION in bits, returns a constant string that is the
562 matching go int or uint type (depending on the IS_UNSIGNED flag). Returns a
563 NULL pointer if there is no matching go type. */
564
565static const char *
566go_get_uinttype_for_precision (unsigned int precision, bool is_unsigned)
567{
568 switch (precision)
569 {
570 case 8:
571 return is_unsigned ? "uint8" : "int8";
572 case 16:
573 return is_unsigned ? "uint16" : "int16";
574 case 32:
575 return is_unsigned ? "uint32" : "int32";
576 case 64:
577 return is_unsigned ? "uint64" : "int64";
578 default:
579 return NULL;
580 }
581}
582
583/* Append an artificial variable name with the suffix _INDEX to OB. Returns
584 INDEX + 1. */
585
586static unsigned int
587go_append_artificial_name (struct obstack *ob, unsigned int index)
588{
589 char buf[100];
590
591 /* FIXME: identifier may not be unique. */
592 obstack_grow (ob, "Godump_", 7);
593 snprintf (buf, sizeof buf, "%u", index);
594 obstack_grow (ob, buf, strlen (buf));
595
596 return index + 1;
597}
598
599/* Append the variable name from DECL to OB. If the name is in the
600 KEYWORD_HASH, prepend an '_'. */
601
602static void
603go_append_decl_name (struct obstack *ob, tree decl, htab_t keyword_hash)
604{
605 const char *var_name;
606 void **slot;
607
608 /* Start variable name with an underscore if a keyword. */
609 var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
610 slot = htab_find_slot (keyword_hash, var_name, NO_INSERT);
611 if (slot != NULL)
612 obstack_1grow (ob, '_');
613 go_append_string (ob, DECL_NAME (decl));
614}
615
616/* Appends a byte array with the necessary number of elements and the name
617 "Godump_INDEX_pad" to pad from FROM_OFFSET to TO_OFFSET to OB assuming that
618 the next field is automatically aligned to ALIGN_UNITS. Returns INDEX + 1,
619 or INDEX if no padding had to be appended. The resulting offset where the
620 next field is allocated is returned through RET_OFFSET. */
621
622static unsigned int
623go_append_padding (struct obstack *ob, unsigned int from_offset,
624 unsigned int to_offset, unsigned int align_units,
625 unsigned int index, unsigned int *ret_offset)
626{
627 if (from_offset % align_units > 0)
628 from_offset += align_units - (from_offset % align_units);
629 gcc_assert (to_offset >= from_offset);
630 if (to_offset > from_offset)
631 {
632 char buf[100];
633
634 index = go_append_artificial_name (ob, index);
635 snprintf (buf, sizeof buf, "_pad [%u]byte; ", to_offset - from_offset);
636 obstack_grow (ob, buf, strlen (buf));
637 }
638 *ret_offset = to_offset;
639
640 return index;
641}
642
643/* Appends an array of type TYPE_STRING with zero elements and the name
644 "Godump_INDEX_align" to OB. If TYPE_STRING is a null pointer, ERROR_STRING
645 is appended instead of the type. Returns INDEX + 1. */
646
647static unsigned int
648go_force_record_alignment (struct obstack *ob, const char *type_string,
649 unsigned int index, const char *error_string)
650{
651 index = go_append_artificial_name (ob, index);
652 obstack_grow (ob, "_align ", 7);
653 if (type_string == NULL)
654 obstack_grow (ob, error_string, strlen (error_string));
655 else
656 {
657 obstack_grow (ob, "[0]", 3);
658 obstack_grow (ob, type_string, strlen (type_string));
659 }
660 obstack_grow (ob, "; ", 2);
661
662 return index;
663}
664
c6a13190
ILT
665/* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
666 USE_TYPE_NAME is true if we can simply use a type name here without
667 needing to define it. IS_FUNC_OK is true if we can output a func
4bbed9ce
DV
668 type here; the "func" keyword will already have been added.
669 Return true if the type can be represented in Go, false otherwise.
670 P_ART_I is used for indexing artificial elements in nested structures and
671 should always be a NULL pointer when called, except by certain recursive
672 calls from go_format_type() itself. */
c6a13190
ILT
673
674static bool
99b1c316 675go_format_type (class godump_container *container, tree type,
57ab0915
DV
676 bool use_type_name, bool is_func_ok, unsigned int *p_art_i,
677 bool is_anon_record_or_union)
c6a13190
ILT
678{
679 bool ret;
680 struct obstack *ob;
4bbed9ce 681 unsigned int art_i_dummy;
57ab0915 682 bool is_union = false;
c6a13190 683
4bbed9ce
DV
684 if (p_art_i == NULL)
685 {
686 art_i_dummy = 0;
687 p_art_i = &art_i_dummy;
688 }
c6a13190
ILT
689 ret = true;
690 ob = &container->type_obstack;
691
73cf5da2
NB
692 if (use_type_name
693 && TYPE_NAME (type) != NULL_TREE
c6a13190
ILT
694 && (AGGREGATE_TYPE_P (type)
695 || POINTER_TYPE_P (type)
696 || TREE_CODE (type) == FUNCTION_TYPE))
697 {
698 tree name;
f17333e3 699 void **slot;
c6a13190 700
73cf5da2
NB
701 /* References to complex builtin types cannot be translated to
702 Go. */
703 if (DECL_P (TYPE_NAME (type))
704 && DECL_IS_UNDECLARED_BUILTIN (TYPE_NAME (type)))
705 ret = false;
706
9dba4b55 707 name = TYPE_IDENTIFIER (type);
f17333e3
ILT
708
709 slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
710 NO_INSERT);
711 if (slot != NULL)
712 ret = false;
713
73cf5da2
NB
714 /* References to incomplete structs are permitted in many
715 contexts, like behind a pointer or inside of a typedef. So
716 consider any referenced struct a potential dummy type. */
717 if (RECORD_OR_UNION_TYPE_P (type))
718 container->pot_dummy_types.add (IDENTIFIER_POINTER (name));
719
f17333e3
ILT
720 obstack_1grow (ob, '_');
721 go_append_string (ob, name);
722 return ret;
c6a13190
ILT
723 }
724
c6a13190
ILT
725 switch (TREE_CODE (type))
726 {
c6a13190 727 case TYPE_DECL:
dbbc4d4c
ILT
728 {
729 void **slot;
730
731 slot = htab_find_slot (container->invalid_hash,
732 IDENTIFIER_POINTER (DECL_NAME (type)),
733 NO_INSERT);
734 if (slot != NULL)
735 ret = false;
736
737 obstack_1grow (ob, '_');
738 go_append_string (ob, DECL_NAME (type));
739 }
c6a13190
ILT
740 break;
741
e4d02f52 742 case ENUMERAL_TYPE:
c6a13190
ILT
743 case INTEGER_TYPE:
744 {
745 const char *s;
746 char buf[100];
747
4bbed9ce
DV
748 s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
749 TYPE_UNSIGNED (type));
750 if (s == NULL)
c6a13190 751 {
c6a13190
ILT
752 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
753 TYPE_PRECISION (type),
754 TYPE_UNSIGNED (type) ? "u" : "");
755 s = buf;
756 ret = false;
c6a13190
ILT
757 }
758 obstack_grow (ob, s, strlen (s));
759 }
760 break;
761
762 case REAL_TYPE:
763 {
764 const char *s;
765 char buf[100];
766
767 switch (TYPE_PRECISION (type))
768 {
769 case 32:
770 s = "float32";
771 break;
772 case 64:
773 s = "float64";
774 break;
c6a13190
ILT
775 default:
776 snprintf (buf, sizeof buf, "INVALID-float-%u",
777 TYPE_PRECISION (type));
778 s = buf;
779 ret = false;
780 break;
781 }
782 obstack_grow (ob, s, strlen (s));
783 }
784 break;
785
7b310e90
DV
786 case COMPLEX_TYPE:
787 {
788 const char *s;
789 char buf[100];
790 tree real_type;
791
792 real_type = TREE_TYPE (type);
793 if (TREE_CODE (real_type) == REAL_TYPE)
794 {
795 switch (TYPE_PRECISION (real_type))
796 {
797 case 32:
798 s = "complex64";
799 break;
800 case 64:
801 s = "complex128";
802 break;
803 default:
804 snprintf (buf, sizeof buf, "INVALID-complex-%u",
805 2 * TYPE_PRECISION (real_type));
806 s = buf;
807 ret = false;
808 break;
809 }
810 }
811 else
812 {
813 s = "INVALID-complex-non-real";
814 ret = false;
815 }
816 obstack_grow (ob, s, strlen (s));
817 }
818 break;
819
c6a13190
ILT
820 case BOOLEAN_TYPE:
821 obstack_grow (ob, "bool", 4);
822 break;
823
824 case POINTER_TYPE:
c6a13190
ILT
825 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
826 obstack_grow (ob, "func", 4);
827 else
828 obstack_1grow (ob, '*');
829 if (VOID_TYPE_P (TREE_TYPE (type)))
830 obstack_grow (ob, "byte", 4);
831 else
832 {
833 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
57ab0915 834 true, NULL, false))
c6a13190
ILT
835 ret = false;
836 }
837 break;
838
839 case ARRAY_TYPE:
840 obstack_1grow (ob, '[');
841 if (TYPE_DOMAIN (type) != NULL_TREE
842 && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
843 && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
844 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
845 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
846 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
847 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
9541ffee 848 && tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
c6a13190
ILT
849 {
850 char buf[100];
851
852 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
9439e9a1 853 tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
c6a13190
ILT
854 obstack_grow (ob, buf, strlen (buf));
855 }
4bbed9ce
DV
856 else
857 obstack_1grow (ob, '0');
c6a13190 858 obstack_1grow (ob, ']');
4bbed9ce 859 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false,
57ab0915 860 NULL, false))
c6a13190
ILT
861 ret = false;
862 break;
863
57ab0915
DV
864 case UNION_TYPE:
865 is_union = true;
866 /* Fall through to RECORD_TYPE case. */
81fea426 867 gcc_fallthrough ();
c6a13190
ILT
868 case RECORD_TYPE:
869 {
4bbed9ce 870 unsigned int prev_field_end;
57ab0915 871 unsigned int known_alignment;
c6a13190 872 tree field;
57ab0915 873 bool emitted_a_field;
c6a13190 874
4bbed9ce
DV
875 /* FIXME: Why is this necessary? Without it we can get a core
876 dump on the s390x headers, or from a file containing simply
877 "typedef struct S T;". */
878 layout_type (type);
879
880 prev_field_end = 0;
57ab0915
DV
881 known_alignment = 1;
882 /* Anonymous records and unions are flattened, i.e. they are not put
883 into "struct { ... }". */
884 if (!is_anon_record_or_union)
885 obstack_grow (ob, "struct { ", 9);
886 for (field = TYPE_FIELDS (type), emitted_a_field = false;
c6a13190
ILT
887 field != NULL_TREE;
888 field = TREE_CHAIN (field))
889 {
4bbed9ce
DV
890 if (TREE_CODE (field) != FIELD_DECL)
891 continue;
c6a13190 892 if (DECL_BIT_FIELD (field))
57ab0915 893 /* Bit fields are replaced by padding. */
4bbed9ce 894 continue;
57ab0915
DV
895 /* Only the first non-bitfield field is emitted for unions. */
896 if (!is_union || !emitted_a_field)
897 {
898 /* Emit the field. */
899 bool field_ok;
900 bool is_anon_substructure;
901 unsigned int decl_align_unit;
902 unsigned int decl_offset;
903
904 field_ok = true;
905 emitted_a_field = true;
906 is_anon_substructure =
907 (DECL_NAME (field) == NULL
908 && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
909 || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE));
910 /* Keep track of the alignment of named substructures, either
911 of the whole record, or the alignment of the emitted field
912 (for unions). */
913 decl_align_unit = DECL_ALIGN_UNIT (field);
914 if (!is_anon_substructure && decl_align_unit > known_alignment)
915 known_alignment = decl_align_unit;
916 /* Pad to start of field. */
917 decl_offset =
918 TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
919 + precision_to_units
920 (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)));
4bbed9ce 921 {
57ab0915
DV
922 unsigned int align_unit;
923
924 /* For anonymous records and unions there is no automatic
925 structure alignment, so use 1 as the alignment. */
926 align_unit = (is_anon_substructure) ? 1 : decl_align_unit;
4bbed9ce 927 *p_art_i = go_append_padding
57ab0915 928 (ob, prev_field_end, decl_offset, align_unit, *p_art_i,
4bbed9ce 929 &prev_field_end);
4bbed9ce 930 }
57ab0915
DV
931 if (DECL_SIZE_UNIT (field))
932 prev_field_end +=
933 TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
934 /* Emit the field name, but not for anonymous records and
935 unions. */
936 if (!is_anon_substructure)
937 {
5433e401 938 if (DECL_NAME (field) == NULL)
57ab0915
DV
939 *p_art_i = go_append_artificial_name (ob, *p_art_i);
940 else
941 go_append_decl_name
942 (ob, field, container->keyword_hash);
943 obstack_1grow (ob, ' ');
944 }
945 /* Do not expand type if a record or union type or a function
946 pointer. */
c6a13190
ILT
947 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
948 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
949 || (POINTER_TYPE_P (TREE_TYPE (field))
950 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
57ab0915 951 == FUNCTION_TYPE))))
c6a13190 952 {
dbbc4d4c
ILT
953 tree name;
954 void **slot;
955
9dba4b55 956 name = TYPE_IDENTIFIER (TREE_TYPE (field));
dbbc4d4c
ILT
957
958 slot = htab_find_slot (container->invalid_hash,
959 IDENTIFIER_POINTER (name),
960 NO_INSERT);
961 if (slot != NULL)
53febcba 962 field_ok = false;
dbbc4d4c
ILT
963
964 obstack_1grow (ob, '_');
965 go_append_string (ob, name);
c6a13190
ILT
966 }
967 else
968 {
969 if (!go_format_type (container, TREE_TYPE (field), true,
57ab0915 970 false, p_art_i, is_anon_substructure))
53febcba 971 field_ok = false;
c6a13190 972 }
57ab0915
DV
973 if (!is_anon_substructure)
974 obstack_grow (ob, "; ", 2);
975 if (!field_ok)
976 ret = false;
977 }
4bbed9ce 978 }
57ab0915 979 /* Padding. */
fca7c764
ILT
980 *p_art_i = go_append_padding (ob, prev_field_end,
981 TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)),
982 1, *p_art_i, &prev_field_end);
57ab0915
DV
983 /* Alignment. */
984 if (!is_anon_record_or_union
985 && known_alignment < TYPE_ALIGN_UNIT (type))
4bbed9ce
DV
986 {
987 const char *s;
988 char buf[100];
c6a13190 989
4bbed9ce
DV
990 /* Enforce proper record alignment. */
991 s = go_get_uinttype_for_precision
992 (TYPE_ALIGN (type), TYPE_UNSIGNED (type));
993 if (s == NULL)
53febcba 994 {
4bbed9ce
DV
995 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
996 TYPE_ALIGN (type), TYPE_UNSIGNED (type) ? "u" : "");
997 s = buf;
998 ret = false;
53febcba 999 }
4bbed9ce
DV
1000 *p_art_i = go_force_record_alignment (ob, s, *p_art_i, buf);
1001 }
57ab0915
DV
1002 if (!is_anon_record_or_union)
1003 obstack_1grow (ob, '}');
4bbed9ce 1004 }
57ab0915 1005 break;
c6a13190
ILT
1006
1007 case FUNCTION_TYPE:
1008 {
bce33ab2 1009 tree arg_type;
c6a13190
ILT
1010 bool is_varargs;
1011 tree result;
bce33ab2
NF
1012 function_args_iterator iter;
1013 bool seen_arg;
c6a13190
ILT
1014
1015 /* Go has no way to write a type which is a function but not a
1016 pointer to a function. */
1017 if (!is_func_ok)
1018 {
1019 obstack_grow (ob, "func*", 5);
1020 ret = false;
1021 }
1022
1023 obstack_1grow (ob, '(');
bce33ab2
NF
1024 is_varargs = stdarg_p (type);
1025 seen_arg = false;
1026 FOREACH_FUNCTION_ARGS (type, arg_type, iter)
c6a13190 1027 {
bce33ab2
NF
1028 if (VOID_TYPE_P (arg_type))
1029 break;
1030 if (seen_arg)
c6a13190 1031 obstack_grow (ob, ", ", 2);
57ab0915 1032 if (!go_format_type (container, arg_type, true, false, NULL, false))
c6a13190 1033 ret = false;
bce33ab2 1034 seen_arg = true;
c6a13190
ILT
1035 }
1036 if (is_varargs)
1037 {
bce33ab2 1038 if (prototype_p (type))
c6a13190
ILT
1039 obstack_grow (ob, ", ", 2);
1040 obstack_grow (ob, "...interface{}", 14);
1041 }
1042 obstack_1grow (ob, ')');
1043
1044 result = TREE_TYPE (type);
1045 if (!VOID_TYPE_P (result))
1046 {
1047 obstack_1grow (ob, ' ');
57ab0915
DV
1048 if (!go_format_type (container, result, use_type_name, false, NULL,
1049 false))
c6a13190
ILT
1050 ret = false;
1051 }
1052 }
1053 break;
1054
1055 default:
1056 obstack_grow (ob, "INVALID-type", 12);
1057 ret = false;
1058 break;
1059 }
1060
1061 return ret;
1062}
1063
1064/* Output the type which was built on the type obstack, and then free
1065 it. */
1066
1067static void
99b1c316 1068go_output_type (class godump_container *container)
c6a13190
ILT
1069{
1070 struct obstack *ob;
1071
1072 ob = &container->type_obstack;
1073 obstack_1grow (ob, '\0');
19a9ba64 1074 fputs ((char *) obstack_base (ob), go_dump_file);
c6a13190
ILT
1075 obstack_free (ob, obstack_base (ob));
1076}
1077
1078/* Output a function declaration. */
1079
1080static void
99b1c316 1081go_output_fndecl (class godump_container *container, tree decl)
c6a13190 1082{
73cf5da2 1083 if (!go_format_type (container, TREE_TYPE (decl), true, true, NULL, false))
c6a13190
ILT
1084 fprintf (go_dump_file, "// ");
1085 fprintf (go_dump_file, "func _%s ",
1086 IDENTIFIER_POINTER (DECL_NAME (decl)));
1087 go_output_type (container);
1088 fprintf (go_dump_file, " __asm__(\"%s\")\n",
1089 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
1090}
1091
1092/* Output a typedef or something like a struct definition. */
1093
1094static void
99b1c316 1095go_output_typedef (class godump_container *container, tree decl)
c6a13190
ILT
1096{
1097 /* If we have an enum type, output the enum constants
1098 separately. */
1099 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
1100 && TYPE_SIZE (TREE_TYPE (decl)) != 0
6e2830c3 1101 && !container->decls_seen.contains (TREE_TYPE (decl))
c6a13190 1102 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
6e2830c3
TS
1103 || !container->decls_seen.contains
1104 (TYPE_CANONICAL (TREE_TYPE (decl)))))
c6a13190
ILT
1105 {
1106 tree element;
1107
1108 for (element = TYPE_VALUES (TREE_TYPE (decl));
1109 element != NULL_TREE;
1110 element = TREE_CHAIN (element))
c53aafdf
ILT
1111 {
1112 const char *name;
5743331e 1113 struct macro_hash_value *mhval;
c53aafdf 1114 void **slot;
807e902e 1115 char buf[WIDE_INT_PRINT_BUFFER_SIZE];
c53aafdf
ILT
1116
1117 name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
1118
1119 /* Sometimes a name will be defined as both an enum constant
1120 and a macro. Avoid duplicate definition errors by
1121 treating enum constants as macros. */
5743331e
ILT
1122 mhval = XNEW (struct macro_hash_value);
1123 mhval->name = xstrdup (name);
1124 mhval->value = NULL;
1125 slot = htab_find_slot (macro_hash, mhval, INSERT);
1126 if (*slot != NULL)
1127 macro_hash_del (*slot);
1128
9541ffee 1129 if (tree_fits_shwi_p (TREE_VALUE (element)))
5743331e 1130 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
9439e9a1 1131 tree_to_shwi (TREE_VALUE (element)));
cc269bb6 1132 else if (tree_fits_uhwi_p (TREE_VALUE (element)))
5743331e 1133 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
7d362f6c 1134 tree_to_uhwi (TREE_VALUE (element)));
5743331e 1135 else
8e6cdc90 1136 print_hex (wi::to_wide (element), buf);
5743331e
ILT
1137
1138 mhval->value = xstrdup (buf);
1139 *slot = mhval;
c53aafdf 1140 }
6e2830c3 1141 container->decls_seen.add (TREE_TYPE (decl));
c6a13190 1142 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
6e2830c3 1143 container->decls_seen.add (TYPE_CANONICAL (TREE_TYPE (decl)));
c6a13190
ILT
1144 }
1145
1146 if (DECL_NAME (decl) != NULL_TREE)
1147 {
1148 void **slot;
1149 const char *type;
0df5fa66 1150 tree original_type;
c6a13190
ILT
1151
1152 type = IDENTIFIER_POINTER (DECL_NAME (decl));
0df5fa66 1153 original_type = DECL_ORIGINAL_TYPE (decl);
30b76d90
ILT
1154 if (original_type == NULL_TREE)
1155 original_type = TREE_TYPE (decl);
0df5fa66
NB
1156
1157 /* Suppress typedefs where the type name matches the underlying
1158 struct/union/enum tag. This way we'll emit the struct definition
1159 instead of an invalid recursive type. */
1160 if (TYPE_IDENTIFIER (original_type) != NULL
1161 && IDENTIFIER_POINTER (TYPE_IDENTIFIER (original_type)) == type)
1162 return;
1163
c6a13190
ILT
1164 /* If type defined already, skip. */
1165 slot = htab_find_slot (container->type_hash, type, INSERT);
1166 if (*slot != NULL)
1167 return;
1168 *slot = CONST_CAST (void *, (const void *) type);
1169
0df5fa66 1170 if (!go_format_type (container, original_type, true, false,
73cf5da2 1171 NULL, false))
f17333e3
ILT
1172 {
1173 fprintf (go_dump_file, "// ");
1174 slot = htab_find_slot (container->invalid_hash, type, INSERT);
1175 *slot = CONST_CAST (void *, (const void *) type);
1176 }
c6a13190
ILT
1177 fprintf (go_dump_file, "type _%s ",
1178 IDENTIFIER_POINTER (DECL_NAME (decl)));
1179 go_output_type (container);
f12e8bd5
ILT
1180
1181 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1182 {
1183 HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1184
1185 if (size > 0)
1186 fprintf (go_dump_file,
1187 "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1188 IDENTIFIER_POINTER (DECL_NAME (decl)),
1189 size);
1190 }
1191
6e2830c3 1192 container->decls_seen.add (decl);
c6a13190 1193 }
0df5fa66
NB
1194 else if ((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
1195 || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
1196 && TYPE_NAME (TREE_TYPE (decl)) != NULL)
c6a13190
ILT
1197 {
1198 void **slot;
1199 const char *type;
f12e8bd5 1200 HOST_WIDE_INT size;
c6a13190
ILT
1201
1202 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1203 /* If type defined already, skip. */
1204 slot = htab_find_slot (container->type_hash, type, INSERT);
1205 if (*slot != NULL)
1206 return;
1207 *slot = CONST_CAST (void *, (const void *) type);
1208
57ab0915
DV
1209 if (!go_format_type (container, TREE_TYPE (decl), false, false, NULL,
1210 false))
f17333e3
ILT
1211 {
1212 fprintf (go_dump_file, "// ");
1213 slot = htab_find_slot (container->invalid_hash, type, INSERT);
1214 *slot = CONST_CAST (void *, (const void *) type);
1215 }
c6a13190
ILT
1216 fprintf (go_dump_file, "type _%s ",
1217 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1218 go_output_type (container);
f12e8bd5
ILT
1219
1220 size = int_size_in_bytes (TREE_TYPE (decl));
1221 if (size > 0)
1222 fprintf (go_dump_file,
1223 "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1224 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))),
1225 size);
c6a13190
ILT
1226 }
1227 else
1228 return;
1229
1230 fprintf (go_dump_file, "\n");
1231}
1232
1233/* Output a variable. */
1234
1235static void
99b1c316 1236go_output_var (class godump_container *container, tree decl)
c6a13190 1237{
4053a5a0 1238 bool is_valid;
4bbed9ce
DV
1239 tree type_name;
1240 tree id;
4053a5a0 1241
6e2830c3
TS
1242 if (container->decls_seen.contains (decl)
1243 || container->decls_seen.contains (DECL_NAME (decl)))
c6a13190 1244 return;
6e2830c3
TS
1245 container->decls_seen.add (decl);
1246 container->decls_seen.add (DECL_NAME (decl));
4053a5a0 1247
4bbed9ce
DV
1248 type_name = TYPE_NAME (TREE_TYPE (decl));
1249 id = NULL_TREE;
1250 if (type_name != NULL_TREE && TREE_CODE (type_name) == IDENTIFIER_NODE)
1251 id = type_name;
1252 else if (type_name != NULL_TREE && TREE_CODE (type_name) == TYPE_DECL
1253 && DECL_SOURCE_LOCATION (type_name) != BUILTINS_LOCATION
1254 && DECL_NAME (type_name))
1255 id = DECL_NAME (type_name);
1256 if (id != NULL_TREE
1257 && (!htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1258 NO_INSERT)
1259 || htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (id),
1260 NO_INSERT)))
1261 id = NULL_TREE;
1262 if (id != NULL_TREE)
1263 {
1264 struct obstack *ob;
1265
1266 ob = &container->type_obstack;
1267 obstack_1grow (ob, '_');
1268 go_append_string (ob, id);
1269 is_valid = htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1270 NO_INSERT) != NULL;
1271 }
1272 else
57ab0915
DV
1273 is_valid = go_format_type (container, TREE_TYPE (decl), true, false, NULL,
1274 false);
4053a5a0
ILT
1275 if (is_valid
1276 && htab_find_slot (container->type_hash,
1277 IDENTIFIER_POINTER (DECL_NAME (decl)),
1278 NO_INSERT) != NULL)
1279 {
1280 /* There is already a type with this name, probably from a
1281 struct tag. Prefer the type to the variable. */
1282 is_valid = false;
1283 }
1284 if (!is_valid)
c6a13190 1285 fprintf (go_dump_file, "// ");
4053a5a0 1286
c6a13190
ILT
1287 fprintf (go_dump_file, "var _%s ",
1288 IDENTIFIER_POINTER (DECL_NAME (decl)));
1289 go_output_type (container);
1290 fprintf (go_dump_file, "\n");
1291
1292 /* Sometimes an extern variable is declared with an unknown struct
1293 type. */
4bbed9ce 1294 if (type_name != NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
c6a13190 1295 {
c6a13190 1296 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
6e2830c3 1297 container->pot_dummy_types.add (IDENTIFIER_POINTER (type_name));
c6a13190 1298 else if (TREE_CODE (type_name) == TYPE_DECL)
6e2830c3
TS
1299 container->pot_dummy_types.add
1300 (IDENTIFIER_POINTER (DECL_NAME (type_name)));
c6a13190
ILT
1301 }
1302}
1303
5743331e
ILT
1304/* Output the final value of a preprocessor macro or enum constant.
1305 This is called via htab_traverse_noresize. */
1306
1307static int
1308go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1309{
1310 struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1311 fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1312 return 1;
1313}
1314
c6a13190
ILT
1315/* Build a hash table with the Go keywords. */
1316
1317static const char * const keywords[] = {
1318 "__asm__", "break", "case", "chan", "const", "continue", "default",
1319 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1320 "import", "interface", "map", "package", "range", "return", "select",
1321 "struct", "switch", "type", "var"
1322};
1323
1324static void
99b1c316 1325keyword_hash_init (class godump_container *container)
c6a13190
ILT
1326{
1327 size_t i;
1328 size_t count = sizeof (keywords) / sizeof (keywords[0]);
1329 void **slot;
1330
1331 for (i = 0; i < count; i++)
1332 {
1333 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1334 *slot = CONST_CAST (void *, (const void *) keywords[i]);
1335 }
1336}
1337
1338/* Traversing the pot_dummy_types and seeing which types are present
1339 in the global types hash table and creating dummy definitions if
6e2830c3 1340 not found. This function is invoked by hash_set::traverse. */
c6a13190 1341
6e2830c3
TS
1342bool
1343find_dummy_types (const char *const &ptr, godump_container *adata)
c6a13190 1344{
99b1c316 1345 class godump_container *data = (class godump_container *) adata;
c6a13190
ILT
1346 const char *type = (const char *) ptr;
1347 void **slot;
3eb9e389 1348 void **islot;
c6a13190
ILT
1349
1350 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
3eb9e389
ILT
1351 islot = htab_find_slot (data->invalid_hash, type, NO_INSERT);
1352 if (slot == NULL || islot != NULL)
c6a13190
ILT
1353 fprintf (go_dump_file, "type _%s struct {}\n", type);
1354 return true;
1355}
1356
1357/* Output symbols. */
1358
1359static void
1360go_finish (const char *filename)
1361{
99b1c316 1362 class godump_container container;
c6a13190
ILT
1363 unsigned int ix;
1364 tree decl;
1365
1366 real_debug_hooks->finish (filename);
1367
c6a13190 1368 container.type_hash = htab_create (100, htab_hash_string,
861c6411 1369 htab_eq_string, NULL);
f17333e3 1370 container.invalid_hash = htab_create (10, htab_hash_string,
861c6411 1371 htab_eq_string, NULL);
c6a13190 1372 container.keyword_hash = htab_create (50, htab_hash_string,
861c6411 1373 htab_eq_string, NULL);
c6a13190
ILT
1374 obstack_init (&container.type_obstack);
1375
1376 keyword_hash_init (&container);
1377
9771b263 1378 FOR_EACH_VEC_SAFE_ELT (queue, ix, decl)
c6a13190
ILT
1379 {
1380 switch (TREE_CODE (decl))
1381 {
1382 case FUNCTION_DECL:
1383 go_output_fndecl (&container, decl);
1384 break;
1385
1386 case TYPE_DECL:
1387 go_output_typedef (&container, decl);
1388 break;
1389
1390 case VAR_DECL:
1391 go_output_var (&container, decl);
1392 break;
1393
1394 default:
c3284718 1395 gcc_unreachable ();
c6a13190
ILT
1396 }
1397 }
1398
5743331e
ILT
1399 htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1400
c6a13190 1401 /* To emit dummy definitions. */
6e2830c3
TS
1402 container.pot_dummy_types.traverse<godump_container *, find_dummy_types>
1403 (&container);
c6a13190 1404
c6a13190 1405 htab_delete (container.type_hash);
f17333e3 1406 htab_delete (container.invalid_hash);
c6a13190
ILT
1407 htab_delete (container.keyword_hash);
1408 obstack_free (&container.type_obstack, NULL);
1409
9771b263 1410 vec_free (queue);
c6a13190
ILT
1411
1412 if (fclose (go_dump_file) != 0)
1413 error ("could not close Go dump file: %m");
1414 go_dump_file = NULL;
1415}
1416
1417/* Set up our hooks. */
1418
1419const struct gcc_debug_hooks *
1420dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1421{
1422 go_dump_file = fopen (filename, "w");
1423 if (go_dump_file == NULL)
1424 {
1425 error ("could not open Go dump file %qs: %m", filename);
1426 return hooks;
1427 }
1428
1429 go_debug_hooks = *hooks;
1430 real_debug_hooks = hooks;
1431
1432 go_debug_hooks.finish = go_finish;
1433 go_debug_hooks.define = go_define;
1434 go_debug_hooks.undef = go_undef;
1435 go_debug_hooks.function_decl = go_function_decl;
d7438551
AH
1436 go_debug_hooks.early_global_decl = go_early_global_decl;
1437 go_debug_hooks.late_global_decl = go_late_global_decl;
c6a13190
ILT
1438 go_debug_hooks.type_decl = go_type_decl;
1439
5743331e
ILT
1440 macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1441 macro_hash_del);
c6a13190
ILT
1442
1443 return &go_debug_hooks;
1444}
1445
1446#include "gt-godump.h"