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