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