]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/godump.cc
[PATCH v1 1/1] RISC-V: Nan-box the result of movbf on soft-bf16
[thirdparty/gcc.git] / gcc / godump.cc
CommitLineData
c6a13190 1/* Output Go language descriptions of types.
a945c346 2 Copyright (C) 2008-2024 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
d3f3ec5a
ILT
646 "_" to OB. If TYPE_STRING is a null pointer, ERROR_STRING is appended
647 instead of the type. Returns INDEX + 1. */
4bbed9ce
DV
648
649static unsigned int
650go_force_record_alignment (struct obstack *ob, const char *type_string,
651 unsigned int index, const char *error_string)
652{
62c3f75f 653 obstack_grow (ob, "_ ", 2);
4bbed9ce
DV
654 if (type_string == NULL)
655 obstack_grow (ob, error_string, strlen (error_string));
656 else
657 {
658 obstack_grow (ob, "[0]", 3);
659 obstack_grow (ob, type_string, strlen (type_string));
660 }
661 obstack_grow (ob, "; ", 2);
662
663 return index;
664}
665
c6a13190
ILT
666/* Write the Go version of TYPE to CONTAINER->TYPE_OBSTACK.
667 USE_TYPE_NAME is true if we can simply use a type name here without
668 needing to define it. IS_FUNC_OK is true if we can output a func
4bbed9ce
DV
669 type here; the "func" keyword will already have been added.
670 Return true if the type can be represented in Go, false otherwise.
671 P_ART_I is used for indexing artificial elements in nested structures and
672 should always be a NULL pointer when called, except by certain recursive
673 calls from go_format_type() itself. */
c6a13190
ILT
674
675static bool
99b1c316 676go_format_type (class godump_container *container, tree type,
57ab0915
DV
677 bool use_type_name, bool is_func_ok, unsigned int *p_art_i,
678 bool is_anon_record_or_union)
c6a13190
ILT
679{
680 bool ret;
681 struct obstack *ob;
4bbed9ce 682 unsigned int art_i_dummy;
57ab0915 683 bool is_union = false;
c6a13190 684
4bbed9ce
DV
685 if (p_art_i == NULL)
686 {
687 art_i_dummy = 0;
688 p_art_i = &art_i_dummy;
689 }
c6a13190
ILT
690 ret = true;
691 ob = &container->type_obstack;
692
73cf5da2
NB
693 if (use_type_name
694 && TYPE_NAME (type) != NULL_TREE
c6a13190
ILT
695 && (AGGREGATE_TYPE_P (type)
696 || POINTER_TYPE_P (type)
697 || TREE_CODE (type) == FUNCTION_TYPE))
698 {
699 tree name;
f17333e3 700 void **slot;
c6a13190 701
73cf5da2
NB
702 /* References to complex builtin types cannot be translated to
703 Go. */
704 if (DECL_P (TYPE_NAME (type))
705 && DECL_IS_UNDECLARED_BUILTIN (TYPE_NAME (type)))
706 ret = false;
707
9dba4b55 708 name = TYPE_IDENTIFIER (type);
f17333e3
ILT
709
710 slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
711 NO_INSERT);
712 if (slot != NULL)
713 ret = false;
714
73cf5da2
NB
715 /* References to incomplete structs are permitted in many
716 contexts, like behind a pointer or inside of a typedef. So
717 consider any referenced struct a potential dummy type. */
718 if (RECORD_OR_UNION_TYPE_P (type))
719 container->pot_dummy_types.add (IDENTIFIER_POINTER (name));
720
f17333e3
ILT
721 obstack_1grow (ob, '_');
722 go_append_string (ob, name);
723 return ret;
c6a13190
ILT
724 }
725
c6a13190
ILT
726 switch (TREE_CODE (type))
727 {
c6a13190 728 case TYPE_DECL:
dbbc4d4c
ILT
729 {
730 void **slot;
731
732 slot = htab_find_slot (container->invalid_hash,
733 IDENTIFIER_POINTER (DECL_NAME (type)),
734 NO_INSERT);
735 if (slot != NULL)
736 ret = false;
737
738 obstack_1grow (ob, '_');
739 go_append_string (ob, DECL_NAME (type));
740 }
c6a13190
ILT
741 break;
742
e4d02f52 743 case ENUMERAL_TYPE:
c6a13190
ILT
744 case INTEGER_TYPE:
745 {
746 const char *s;
747 char buf[100];
748
4bbed9ce
DV
749 s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
750 TYPE_UNSIGNED (type));
751 if (s == NULL)
c6a13190 752 {
c6a13190
ILT
753 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
754 TYPE_PRECISION (type),
755 TYPE_UNSIGNED (type) ? "u" : "");
756 s = buf;
757 ret = false;
c6a13190
ILT
758 }
759 obstack_grow (ob, s, strlen (s));
760 }
761 break;
762
e4775af4
ILT
763 case BITINT_TYPE:
764 {
765 const char *s;
766 char buf[100];
767
768 s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
769 TYPE_UNSIGNED (type));
770 if (s == NULL)
771 {
772 snprintf (buf, sizeof buf, "INVALID-bitint-%u%s",
773 TYPE_PRECISION (type),
774 TYPE_UNSIGNED (type) ? "u" : "");
775 s = buf;
776 ret = false;
777 }
778 obstack_grow (ob, s, strlen(s));
779 }
780 break;
781
c6a13190
ILT
782 case REAL_TYPE:
783 {
784 const char *s;
785 char buf[100];
786
787 switch (TYPE_PRECISION (type))
788 {
789 case 32:
790 s = "float32";
791 break;
792 case 64:
793 s = "float64";
794 break;
c6a13190
ILT
795 default:
796 snprintf (buf, sizeof buf, "INVALID-float-%u",
797 TYPE_PRECISION (type));
798 s = buf;
799 ret = false;
800 break;
801 }
802 obstack_grow (ob, s, strlen (s));
803 }
804 break;
805
7b310e90
DV
806 case COMPLEX_TYPE:
807 {
808 const char *s;
809 char buf[100];
810 tree real_type;
811
812 real_type = TREE_TYPE (type);
813 if (TREE_CODE (real_type) == REAL_TYPE)
814 {
815 switch (TYPE_PRECISION (real_type))
816 {
817 case 32:
818 s = "complex64";
819 break;
820 case 64:
821 s = "complex128";
822 break;
823 default:
824 snprintf (buf, sizeof buf, "INVALID-complex-%u",
825 2 * TYPE_PRECISION (real_type));
826 s = buf;
827 ret = false;
828 break;
829 }
830 }
831 else
832 {
833 s = "INVALID-complex-non-real";
834 ret = false;
835 }
836 obstack_grow (ob, s, strlen (s));
837 }
838 break;
839
c6a13190
ILT
840 case BOOLEAN_TYPE:
841 obstack_grow (ob, "bool", 4);
842 break;
843
844 case POINTER_TYPE:
c6a13190
ILT
845 if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
846 obstack_grow (ob, "func", 4);
847 else
848 obstack_1grow (ob, '*');
849 if (VOID_TYPE_P (TREE_TYPE (type)))
850 obstack_grow (ob, "byte", 4);
851 else
852 {
853 if (!go_format_type (container, TREE_TYPE (type), use_type_name,
57ab0915 854 true, NULL, false))
c6a13190
ILT
855 ret = false;
856 }
857 break;
858
859 case ARRAY_TYPE:
860 obstack_1grow (ob, '[');
861 if (TYPE_DOMAIN (type) != NULL_TREE
862 && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
863 && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
864 && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
865 && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
866 && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
867 && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
9541ffee 868 && tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
c6a13190
ILT
869 {
870 char buf[100];
871
872 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
9439e9a1 873 tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
c6a13190
ILT
874 obstack_grow (ob, buf, strlen (buf));
875 }
4bbed9ce
DV
876 else
877 obstack_1grow (ob, '0');
c6a13190 878 obstack_1grow (ob, ']');
4bbed9ce 879 if (!go_format_type (container, TREE_TYPE (type), use_type_name, false,
57ab0915 880 NULL, false))
c6a13190
ILT
881 ret = false;
882 break;
883
57ab0915
DV
884 case UNION_TYPE:
885 is_union = true;
886 /* Fall through to RECORD_TYPE case. */
81fea426 887 gcc_fallthrough ();
c6a13190
ILT
888 case RECORD_TYPE:
889 {
4bbed9ce 890 unsigned int prev_field_end;
57ab0915 891 unsigned int known_alignment;
c6a13190 892 tree field;
57ab0915 893 bool emitted_a_field;
c6a13190 894
4bbed9ce
DV
895 /* FIXME: Why is this necessary? Without it we can get a core
896 dump on the s390x headers, or from a file containing simply
897 "typedef struct S T;". */
898 layout_type (type);
899
900 prev_field_end = 0;
57ab0915
DV
901 known_alignment = 1;
902 /* Anonymous records and unions are flattened, i.e. they are not put
903 into "struct { ... }". */
904 if (!is_anon_record_or_union)
905 obstack_grow (ob, "struct { ", 9);
906 for (field = TYPE_FIELDS (type), emitted_a_field = false;
c6a13190
ILT
907 field != NULL_TREE;
908 field = TREE_CHAIN (field))
909 {
4bbed9ce
DV
910 if (TREE_CODE (field) != FIELD_DECL)
911 continue;
c6a13190 912 if (DECL_BIT_FIELD (field))
57ab0915 913 /* Bit fields are replaced by padding. */
4bbed9ce 914 continue;
57ab0915
DV
915 /* Only the first non-bitfield field is emitted for unions. */
916 if (!is_union || !emitted_a_field)
917 {
918 /* Emit the field. */
919 bool field_ok;
920 bool is_anon_substructure;
921 unsigned int decl_align_unit;
922 unsigned int decl_offset;
923
924 field_ok = true;
925 emitted_a_field = true;
926 is_anon_substructure =
927 (DECL_NAME (field) == NULL
928 && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
929 || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE));
930 /* Keep track of the alignment of named substructures, either
931 of the whole record, or the alignment of the emitted field
932 (for unions). */
933 decl_align_unit = DECL_ALIGN_UNIT (field);
934 if (!is_anon_substructure && decl_align_unit > known_alignment)
935 known_alignment = decl_align_unit;
936 /* Pad to start of field. */
937 decl_offset =
938 TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
939 + precision_to_units
940 (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)));
4bbed9ce 941 {
57ab0915
DV
942 unsigned int align_unit;
943
944 /* For anonymous records and unions there is no automatic
945 structure alignment, so use 1 as the alignment. */
946 align_unit = (is_anon_substructure) ? 1 : decl_align_unit;
4bbed9ce 947 *p_art_i = go_append_padding
57ab0915 948 (ob, prev_field_end, decl_offset, align_unit, *p_art_i,
4bbed9ce 949 &prev_field_end);
4bbed9ce 950 }
57ab0915
DV
951 if (DECL_SIZE_UNIT (field))
952 prev_field_end +=
953 TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
954 /* Emit the field name, but not for anonymous records and
955 unions. */
956 if (!is_anon_substructure)
957 {
5433e401 958 if (DECL_NAME (field) == NULL)
57ab0915
DV
959 *p_art_i = go_append_artificial_name (ob, *p_art_i);
960 else
961 go_append_decl_name
962 (ob, field, container->keyword_hash);
963 obstack_1grow (ob, ' ');
964 }
965 /* Do not expand type if a record or union type or a function
966 pointer. */
c6a13190
ILT
967 if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
968 && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
969 || (POINTER_TYPE_P (TREE_TYPE (field))
970 && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
57ab0915 971 == FUNCTION_TYPE))))
c6a13190 972 {
dbbc4d4c
ILT
973 tree name;
974 void **slot;
975
9dba4b55 976 name = TYPE_IDENTIFIER (TREE_TYPE (field));
dbbc4d4c
ILT
977
978 slot = htab_find_slot (container->invalid_hash,
979 IDENTIFIER_POINTER (name),
980 NO_INSERT);
981 if (slot != NULL)
53febcba 982 field_ok = false;
dbbc4d4c
ILT
983
984 obstack_1grow (ob, '_');
985 go_append_string (ob, name);
c6a13190
ILT
986 }
987 else
988 {
989 if (!go_format_type (container, TREE_TYPE (field), true,
57ab0915 990 false, p_art_i, is_anon_substructure))
53febcba 991 field_ok = false;
c6a13190 992 }
57ab0915
DV
993 if (!is_anon_substructure)
994 obstack_grow (ob, "; ", 2);
995 if (!field_ok)
996 ret = false;
997 }
4bbed9ce 998 }
57ab0915 999 /* Padding. */
fca7c764
ILT
1000 *p_art_i = go_append_padding (ob, prev_field_end,
1001 TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)),
1002 1, *p_art_i, &prev_field_end);
57ab0915
DV
1003 /* Alignment. */
1004 if (!is_anon_record_or_union
1005 && known_alignment < TYPE_ALIGN_UNIT (type))
4bbed9ce
DV
1006 {
1007 const char *s;
1008 char buf[100];
c6a13190 1009
4bbed9ce
DV
1010 /* Enforce proper record alignment. */
1011 s = go_get_uinttype_for_precision
1012 (TYPE_ALIGN (type), TYPE_UNSIGNED (type));
1013 if (s == NULL)
53febcba 1014 {
4bbed9ce
DV
1015 snprintf (buf, sizeof buf, "INVALID-int-%u%s",
1016 TYPE_ALIGN (type), TYPE_UNSIGNED (type) ? "u" : "");
1017 s = buf;
1018 ret = false;
53febcba 1019 }
4bbed9ce
DV
1020 *p_art_i = go_force_record_alignment (ob, s, *p_art_i, buf);
1021 }
57ab0915
DV
1022 if (!is_anon_record_or_union)
1023 obstack_1grow (ob, '}');
4bbed9ce 1024 }
57ab0915 1025 break;
c6a13190
ILT
1026
1027 case FUNCTION_TYPE:
1028 {
bce33ab2 1029 tree arg_type;
c6a13190
ILT
1030 bool is_varargs;
1031 tree result;
bce33ab2
NF
1032 function_args_iterator iter;
1033 bool seen_arg;
c6a13190
ILT
1034
1035 /* Go has no way to write a type which is a function but not a
1036 pointer to a function. */
1037 if (!is_func_ok)
1038 {
1039 obstack_grow (ob, "func*", 5);
1040 ret = false;
1041 }
1042
1043 obstack_1grow (ob, '(');
bce33ab2
NF
1044 is_varargs = stdarg_p (type);
1045 seen_arg = false;
1046 FOREACH_FUNCTION_ARGS (type, arg_type, iter)
c6a13190 1047 {
bce33ab2
NF
1048 if (VOID_TYPE_P (arg_type))
1049 break;
1050 if (seen_arg)
c6a13190 1051 obstack_grow (ob, ", ", 2);
57ab0915 1052 if (!go_format_type (container, arg_type, true, false, NULL, false))
c6a13190 1053 ret = false;
bce33ab2 1054 seen_arg = true;
c6a13190
ILT
1055 }
1056 if (is_varargs)
1057 {
bce33ab2 1058 if (prototype_p (type))
c6a13190
ILT
1059 obstack_grow (ob, ", ", 2);
1060 obstack_grow (ob, "...interface{}", 14);
1061 }
1062 obstack_1grow (ob, ')');
1063
1064 result = TREE_TYPE (type);
1065 if (!VOID_TYPE_P (result))
1066 {
1067 obstack_1grow (ob, ' ');
57ab0915
DV
1068 if (!go_format_type (container, result, use_type_name, false, NULL,
1069 false))
c6a13190
ILT
1070 ret = false;
1071 }
1072 }
1073 break;
1074
1075 default:
1076 obstack_grow (ob, "INVALID-type", 12);
1077 ret = false;
1078 break;
1079 }
1080
1081 return ret;
1082}
1083
1084/* Output the type which was built on the type obstack, and then free
1085 it. */
1086
1087static void
99b1c316 1088go_output_type (class godump_container *container)
c6a13190
ILT
1089{
1090 struct obstack *ob;
1091
1092 ob = &container->type_obstack;
1093 obstack_1grow (ob, '\0');
19a9ba64 1094 fputs ((char *) obstack_base (ob), go_dump_file);
c6a13190
ILT
1095 obstack_free (ob, obstack_base (ob));
1096}
1097
1098/* Output a function declaration. */
1099
1100static void
99b1c316 1101go_output_fndecl (class godump_container *container, tree decl)
c6a13190 1102{
73cf5da2 1103 if (!go_format_type (container, TREE_TYPE (decl), true, true, NULL, false))
c6a13190
ILT
1104 fprintf (go_dump_file, "// ");
1105 fprintf (go_dump_file, "func _%s ",
1106 IDENTIFIER_POINTER (DECL_NAME (decl)));
1107 go_output_type (container);
1108 fprintf (go_dump_file, " __asm__(\"%s\")\n",
1109 IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
1110}
1111
1112/* Output a typedef or something like a struct definition. */
1113
1114static void
99b1c316 1115go_output_typedef (class godump_container *container, tree decl)
c6a13190
ILT
1116{
1117 /* If we have an enum type, output the enum constants
1118 separately. */
1119 if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
1120 && TYPE_SIZE (TREE_TYPE (decl)) != 0
6e2830c3 1121 && !container->decls_seen.contains (TREE_TYPE (decl))
c6a13190 1122 && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
6e2830c3
TS
1123 || !container->decls_seen.contains
1124 (TYPE_CANONICAL (TREE_TYPE (decl)))))
c6a13190
ILT
1125 {
1126 tree element;
1127
1128 for (element = TYPE_VALUES (TREE_TYPE (decl));
1129 element != NULL_TREE;
1130 element = TREE_CHAIN (element))
c53aafdf
ILT
1131 {
1132 const char *name;
5743331e 1133 struct macro_hash_value *mhval;
c53aafdf 1134 void **slot;
807e902e 1135 char buf[WIDE_INT_PRINT_BUFFER_SIZE];
2c05a2d1 1136 tree value = DECL_INITIAL (TREE_VALUE (element));
c53aafdf
ILT
1137
1138 name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
1139
1140 /* Sometimes a name will be defined as both an enum constant
1141 and a macro. Avoid duplicate definition errors by
1142 treating enum constants as macros. */
5743331e
ILT
1143 mhval = XNEW (struct macro_hash_value);
1144 mhval->name = xstrdup (name);
1145 mhval->value = NULL;
1146 slot = htab_find_slot (macro_hash, mhval, INSERT);
1147 if (*slot != NULL)
1148 macro_hash_del (*slot);
1149
2c05a2d1 1150 if (tree_fits_shwi_p (value))
5743331e 1151 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
2c05a2d1
MP
1152 tree_to_shwi (value));
1153 else if (tree_fits_uhwi_p (value))
5743331e 1154 snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
2c05a2d1 1155 tree_to_uhwi (value));
5743331e 1156 else
0d00385e
JJ
1157 {
1158 wide_int w = wi::to_wide (element);
1159 gcc_assert (w.get_len () <= WIDE_INT_MAX_INL_ELTS);
1160 print_hex (w, buf);
1161 }
5743331e
ILT
1162
1163 mhval->value = xstrdup (buf);
1164 *slot = mhval;
c53aafdf 1165 }
6e2830c3 1166 container->decls_seen.add (TREE_TYPE (decl));
c6a13190 1167 if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
6e2830c3 1168 container->decls_seen.add (TYPE_CANONICAL (TREE_TYPE (decl)));
c6a13190
ILT
1169 }
1170
1171 if (DECL_NAME (decl) != NULL_TREE)
1172 {
1173 void **slot;
1174 const char *type;
0df5fa66 1175 tree original_type;
c6a13190
ILT
1176
1177 type = IDENTIFIER_POINTER (DECL_NAME (decl));
0df5fa66 1178 original_type = DECL_ORIGINAL_TYPE (decl);
30b76d90
ILT
1179 if (original_type == NULL_TREE)
1180 original_type = TREE_TYPE (decl);
0df5fa66
NB
1181
1182 /* Suppress typedefs where the type name matches the underlying
1183 struct/union/enum tag. This way we'll emit the struct definition
1184 instead of an invalid recursive type. */
1185 if (TYPE_IDENTIFIER (original_type) != NULL
1186 && IDENTIFIER_POINTER (TYPE_IDENTIFIER (original_type)) == type)
1187 return;
1188
c6a13190
ILT
1189 /* If type defined already, skip. */
1190 slot = htab_find_slot (container->type_hash, type, INSERT);
1191 if (*slot != NULL)
1192 return;
1193 *slot = CONST_CAST (void *, (const void *) type);
1194
0df5fa66 1195 if (!go_format_type (container, original_type, true, false,
73cf5da2 1196 NULL, false))
f17333e3
ILT
1197 {
1198 fprintf (go_dump_file, "// ");
1199 slot = htab_find_slot (container->invalid_hash, type, INSERT);
1200 *slot = CONST_CAST (void *, (const void *) type);
1201 }
c6a13190
ILT
1202 fprintf (go_dump_file, "type _%s ",
1203 IDENTIFIER_POINTER (DECL_NAME (decl)));
1204 go_output_type (container);
f12e8bd5
ILT
1205
1206 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1207 {
1208 HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1209
1210 if (size > 0)
1211 fprintf (go_dump_file,
1212 "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1213 IDENTIFIER_POINTER (DECL_NAME (decl)),
1214 size);
1215 }
1216
6e2830c3 1217 container->decls_seen.add (decl);
c6a13190 1218 }
0df5fa66
NB
1219 else if ((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
1220 || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
1221 && TYPE_NAME (TREE_TYPE (decl)) != NULL)
c6a13190
ILT
1222 {
1223 void **slot;
1224 const char *type;
f12e8bd5 1225 HOST_WIDE_INT size;
c6a13190
ILT
1226
1227 type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1228 /* If type defined already, skip. */
1229 slot = htab_find_slot (container->type_hash, type, INSERT);
1230 if (*slot != NULL)
1231 return;
1232 *slot = CONST_CAST (void *, (const void *) type);
1233
57ab0915
DV
1234 if (!go_format_type (container, TREE_TYPE (decl), false, false, NULL,
1235 false))
f17333e3
ILT
1236 {
1237 fprintf (go_dump_file, "// ");
1238 slot = htab_find_slot (container->invalid_hash, type, INSERT);
1239 *slot = CONST_CAST (void *, (const void *) type);
1240 }
c6a13190
ILT
1241 fprintf (go_dump_file, "type _%s ",
1242 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1243 go_output_type (container);
f12e8bd5
ILT
1244
1245 size = int_size_in_bytes (TREE_TYPE (decl));
1246 if (size > 0)
1247 fprintf (go_dump_file,
1248 "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1249 IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))),
1250 size);
c6a13190
ILT
1251 }
1252 else
1253 return;
1254
1255 fprintf (go_dump_file, "\n");
1256}
1257
1258/* Output a variable. */
1259
1260static void
99b1c316 1261go_output_var (class godump_container *container, tree decl)
c6a13190 1262{
4053a5a0 1263 bool is_valid;
4bbed9ce
DV
1264 tree type_name;
1265 tree id;
4053a5a0 1266
6e2830c3
TS
1267 if (container->decls_seen.contains (decl)
1268 || container->decls_seen.contains (DECL_NAME (decl)))
c6a13190 1269 return;
6e2830c3
TS
1270 container->decls_seen.add (decl);
1271 container->decls_seen.add (DECL_NAME (decl));
4053a5a0 1272
4bbed9ce
DV
1273 type_name = TYPE_NAME (TREE_TYPE (decl));
1274 id = NULL_TREE;
1275 if (type_name != NULL_TREE && TREE_CODE (type_name) == IDENTIFIER_NODE)
1276 id = type_name;
1277 else if (type_name != NULL_TREE && TREE_CODE (type_name) == TYPE_DECL
1278 && DECL_SOURCE_LOCATION (type_name) != BUILTINS_LOCATION
1279 && DECL_NAME (type_name))
1280 id = DECL_NAME (type_name);
1281 if (id != NULL_TREE
1282 && (!htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1283 NO_INSERT)
1284 || htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (id),
1285 NO_INSERT)))
1286 id = NULL_TREE;
1287 if (id != NULL_TREE)
1288 {
1289 struct obstack *ob;
1290
1291 ob = &container->type_obstack;
1292 obstack_1grow (ob, '_');
1293 go_append_string (ob, id);
1294 is_valid = htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1295 NO_INSERT) != NULL;
1296 }
1297 else
57ab0915
DV
1298 is_valid = go_format_type (container, TREE_TYPE (decl), true, false, NULL,
1299 false);
4053a5a0
ILT
1300 if (is_valid
1301 && htab_find_slot (container->type_hash,
1302 IDENTIFIER_POINTER (DECL_NAME (decl)),
1303 NO_INSERT) != NULL)
1304 {
1305 /* There is already a type with this name, probably from a
1306 struct tag. Prefer the type to the variable. */
1307 is_valid = false;
1308 }
1309 if (!is_valid)
c6a13190 1310 fprintf (go_dump_file, "// ");
4053a5a0 1311
c6a13190
ILT
1312 fprintf (go_dump_file, "var _%s ",
1313 IDENTIFIER_POINTER (DECL_NAME (decl)));
1314 go_output_type (container);
1315 fprintf (go_dump_file, "\n");
1316
1317 /* Sometimes an extern variable is declared with an unknown struct
1318 type. */
4bbed9ce 1319 if (type_name != NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
c6a13190 1320 {
c6a13190 1321 if (TREE_CODE (type_name) == IDENTIFIER_NODE)
6e2830c3 1322 container->pot_dummy_types.add (IDENTIFIER_POINTER (type_name));
c6a13190 1323 else if (TREE_CODE (type_name) == TYPE_DECL)
6e2830c3
TS
1324 container->pot_dummy_types.add
1325 (IDENTIFIER_POINTER (DECL_NAME (type_name)));
c6a13190
ILT
1326 }
1327}
1328
5743331e
ILT
1329/* Output the final value of a preprocessor macro or enum constant.
1330 This is called via htab_traverse_noresize. */
1331
1332static int
1333go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1334{
1335 struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1336 fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1337 return 1;
1338}
1339
c6a13190
ILT
1340/* Build a hash table with the Go keywords. */
1341
1342static const char * const keywords[] = {
1343 "__asm__", "break", "case", "chan", "const", "continue", "default",
1344 "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1345 "import", "interface", "map", "package", "range", "return", "select",
1346 "struct", "switch", "type", "var"
1347};
1348
1349static void
99b1c316 1350keyword_hash_init (class godump_container *container)
c6a13190
ILT
1351{
1352 size_t i;
ca32b29e 1353 size_t count = ARRAY_SIZE (keywords);
c6a13190
ILT
1354 void **slot;
1355
1356 for (i = 0; i < count; i++)
1357 {
1358 slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1359 *slot = CONST_CAST (void *, (const void *) keywords[i]);
1360 }
1361}
1362
1363/* Traversing the pot_dummy_types and seeing which types are present
1364 in the global types hash table and creating dummy definitions if
6e2830c3 1365 not found. This function is invoked by hash_set::traverse. */
c6a13190 1366
6e2830c3
TS
1367bool
1368find_dummy_types (const char *const &ptr, godump_container *adata)
c6a13190 1369{
99b1c316 1370 class godump_container *data = (class godump_container *) adata;
c6a13190
ILT
1371 const char *type = (const char *) ptr;
1372 void **slot;
3eb9e389 1373 void **islot;
c6a13190
ILT
1374
1375 slot = htab_find_slot (data->type_hash, type, NO_INSERT);
3eb9e389
ILT
1376 islot = htab_find_slot (data->invalid_hash, type, NO_INSERT);
1377 if (slot == NULL || islot != NULL)
c6a13190
ILT
1378 fprintf (go_dump_file, "type _%s struct {}\n", type);
1379 return true;
1380}
1381
1382/* Output symbols. */
1383
1384static void
1385go_finish (const char *filename)
1386{
99b1c316 1387 class godump_container container;
c6a13190
ILT
1388 unsigned int ix;
1389 tree decl;
1390
1391 real_debug_hooks->finish (filename);
1392
c6a13190 1393 container.type_hash = htab_create (100, htab_hash_string,
861c6411 1394 htab_eq_string, NULL);
f17333e3 1395 container.invalid_hash = htab_create (10, htab_hash_string,
861c6411 1396 htab_eq_string, NULL);
c6a13190 1397 container.keyword_hash = htab_create (50, htab_hash_string,
861c6411 1398 htab_eq_string, NULL);
c6a13190
ILT
1399 obstack_init (&container.type_obstack);
1400
1401 keyword_hash_init (&container);
1402
9771b263 1403 FOR_EACH_VEC_SAFE_ELT (queue, ix, decl)
c6a13190
ILT
1404 {
1405 switch (TREE_CODE (decl))
1406 {
1407 case FUNCTION_DECL:
1408 go_output_fndecl (&container, decl);
1409 break;
1410
1411 case TYPE_DECL:
1412 go_output_typedef (&container, decl);
1413 break;
1414
1415 case VAR_DECL:
1416 go_output_var (&container, decl);
1417 break;
1418
1419 default:
c3284718 1420 gcc_unreachable ();
c6a13190
ILT
1421 }
1422 }
1423
5743331e
ILT
1424 htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1425
c6a13190 1426 /* To emit dummy definitions. */
6e2830c3
TS
1427 container.pot_dummy_types.traverse<godump_container *, find_dummy_types>
1428 (&container);
c6a13190 1429
c6a13190 1430 htab_delete (container.type_hash);
f17333e3 1431 htab_delete (container.invalid_hash);
c6a13190
ILT
1432 htab_delete (container.keyword_hash);
1433 obstack_free (&container.type_obstack, NULL);
1434
9771b263 1435 vec_free (queue);
c6a13190
ILT
1436
1437 if (fclose (go_dump_file) != 0)
1438 error ("could not close Go dump file: %m");
1439 go_dump_file = NULL;
1440}
1441
1442/* Set up our hooks. */
1443
1444const struct gcc_debug_hooks *
1445dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1446{
1447 go_dump_file = fopen (filename, "w");
1448 if (go_dump_file == NULL)
1449 {
1450 error ("could not open Go dump file %qs: %m", filename);
1451 return hooks;
1452 }
1453
1454 go_debug_hooks = *hooks;
1455 real_debug_hooks = hooks;
1456
1457 go_debug_hooks.finish = go_finish;
1458 go_debug_hooks.define = go_define;
1459 go_debug_hooks.undef = go_undef;
1460 go_debug_hooks.function_decl = go_function_decl;
d7438551
AH
1461 go_debug_hooks.early_global_decl = go_early_global_decl;
1462 go_debug_hooks.late_global_decl = go_late_global_decl;
c6a13190
ILT
1463 go_debug_hooks.type_decl = go_type_decl;
1464
5743331e
ILT
1465 macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1466 macro_hash_del);
c6a13190
ILT
1467
1468 return &go_debug_hooks;
1469}
1470
1471#include "gt-godump.h"