xref: /netbsd-src/external/gpl3/gcc/dist/gcc/godump.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Output Go language descriptions of types.
2    Copyright (C) 2008-2022 Free Software Foundation, Inc.
3    Written by Ian Lance Taylor <iant@google.com>.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 /* This file is used during the build process to emit Go language
22    descriptions of declarations from C header files.  It uses the
23    debug info hooks to emit the descriptions.  The Go language
24    descriptions then become part of the Go runtime support
25    library.
26 
27    All global names are output with a leading underscore, so that they
28    are all hidden in Go.  */
29 
30 #include "config.h"
31 #include "system.h"
32 #include "coretypes.h"
33 #include "tree.h"
34 #include "diagnostic-core.h"
35 #include "debug.h"
36 #include "stor-layout.h"
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 
45 static struct gcc_debug_hooks go_debug_hooks;
46 
47 /* The real debug hooks.  */
48 
49 static const struct gcc_debug_hooks *real_debug_hooks;
50 
51 /* The file where we should write information.  */
52 
53 static FILE *go_dump_file;
54 
55 /* A queue of decls to output.  */
56 
57 static GTY(()) vec<tree, va_gc> *queue;
58 
59 struct godump_str_hash : string_hash, ggc_remove <const char *> {};
60 
61 /* A hash table of macros we have seen.  */
62 
63 static htab_t macro_hash;
64 
65 /* The type of a value in macro_hash.  */
66 
67 struct 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 
75 /* Returns the number of units necessary to represent an integer with the given
76    PRECISION (in bits).  */
77 
78 static inline unsigned int
precision_to_units(unsigned int precision)79 precision_to_units (unsigned int precision)
80 {
81   return (precision + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
82 }
83 
84 /* Calculate the hash value for an entry in the macro hash table.  */
85 
86 static hashval_t
macro_hash_hashval(const void * val)87 macro_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 
95 static int
macro_hash_eq(const void * v1,const void * v2)96 macro_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 
105 static void
macro_hash_del(void * v)106 macro_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 
114 /* A macro definition.  */
115 
116 static void
go_define(unsigned int lineno,const char * buffer)117 go_define (unsigned int lineno, const char *buffer)
118 {
119   const char *p;
120   const char *name_end;
121   size_t out_len;
122   char *out_buffer;
123   char *q;
124   bool saw_operand;
125   bool need_operand;
126   struct macro_hash_value *mhval;
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 
151   mhval = XNEW (struct macro_hash_value);
152   mhval->name = copy;
153   mhval->value = NULL;
154 
155   hashval = htab_hash_string (copy);
156   slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, NO_INSERT);
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.  */
160   out_len = strlen (p) * 2 + 1;
161   out_buffer = XNEWVEC (char, out_len);
162   q = out_buffer;
163   saw_operand = false;
164   need_operand = false;
165   while (*p != '\0')
166     {
167       switch (*p)
168 	{
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;
187 	    struct macro_hash_value idval;
188 
189 	    if (saw_operand)
190 	      goto unknown;
191 
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';
198 	    idval.name = n;
199 	    idval.value = NULL;
200 	    if (htab_find (macro_hash, &idval) == NULL)
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 == '=')
308 	    {
309 	      /* Must be a binary operator.  */
310 	      if (!saw_operand)
311 		goto unknown;
312 	      *q++ = *p++;
313 	      saw_operand = false;
314 	      need_operand = true;
315 	    }
316 	  else
317 	    {
318 	      /* Must be a unary operator.  */
319 	      if (saw_operand)
320 		goto unknown;
321 	      need_operand = true;
322 	    }
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 	  {
348 	    char quote;
349 	    int count;
350 
351 	    if (saw_operand)
352 	      goto unknown;
353 	    quote = *p;
354 	    *q++ = *p++;
355 	    count = 0;
356 	    while (*p != quote)
357 	      {
358 		int c;
359 
360 		if (*p == '\0')
361 		  goto unknown;
362 
363 		++count;
364 
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 	      }
410 
411 	    *q++ = *p++;
412 
413 	    if (quote == '\'' && count != 1)
414 	      goto unknown;
415 
416 	    saw_operand = true;
417 	    need_operand = false;
418 
419 	    break;
420 	  }
421 
422 	default:
423 	  goto unknown;
424 	}
425     }
426 
427   if (need_operand)
428     goto unknown;
429 
430   gcc_assert ((size_t) (q - out_buffer) < out_len);
431   *q = '\0';
432 
433   mhval->value = out_buffer;
434 
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;
447 
448   return;
449 
450  unknown:
451   fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
452   if (slot != NULL)
453     htab_clear_slot (macro_hash, slot);
454   XDELETEVEC (out_buffer);
455   XDELETEVEC (copy);
456 }
457 
458 /* A macro undef.  */
459 
460 static void
go_undef(unsigned int lineno,const char * buffer)461 go_undef (unsigned int lineno, const char *buffer)
462 {
463   struct macro_hash_value mhval;
464   void **slot;
465 
466   real_debug_hooks->undef (lineno, buffer);
467 
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);
473 }
474 
475 /* A function or variable decl.  */
476 
477 static void
go_decl(tree decl)478 go_decl (tree decl)
479 {
480   if (!TREE_PUBLIC (decl)
481       || DECL_IS_UNDECLARED_BUILTIN (decl)
482       || DECL_NAME (decl) == NULL_TREE)
483     return;
484   vec_safe_push (queue, decl);
485 }
486 
487 /* A function decl.  */
488 
489 static void
go_function_decl(tree decl)490 go_function_decl (tree decl)
491 {
492   real_debug_hooks->function_decl (decl);
493   go_decl (decl);
494 }
495 
496 static void
go_early_global_decl(tree decl)497 go_early_global_decl (tree decl)
498 {
499   go_decl (decl);
500   if (TREE_CODE (decl) != FUNCTION_DECL || DECL_STRUCT_FUNCTION (decl) != NULL)
501     real_debug_hooks->early_global_decl (decl);
502 }
503 
504 /* A global variable decl.  */
505 
506 static void
go_late_global_decl(tree decl)507 go_late_global_decl (tree decl)
508 {
509   real_debug_hooks->late_global_decl (decl);
510 }
511 
512 /* A type declaration.  */
513 
514 static void
go_type_decl(tree decl,int local)515 go_type_decl (tree decl, int local)
516 {
517   real_debug_hooks->type_decl (decl, local);
518 
519   if (local || DECL_IS_UNDECLARED_BUILTIN (decl))
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;
526   vec_safe_push (queue, decl);
527 }
528 
529 /* A container for the data we pass around when generating information
530    at the end of the compilation.  */
531 
532 class godump_container
533 {
534 public:
535   /* DECLs that we have already seen.  */
536   hash_set<tree> decls_seen;
537 
538   /* Types which may potentially have to be defined as dummy
539      types.  */
540   hash_set<const char *, false, godump_str_hash> pot_dummy_types;
541 
542   /* Go keywords.  */
543   htab_t keyword_hash;
544 
545   /* Global type definitions.  */
546   htab_t type_hash;
547 
548   /* Invalid types.  */
549   htab_t invalid_hash;
550 
551   /* Obstack used to write out a type definition.  */
552   struct obstack type_obstack;
553 };
554 
555 /* Append an IDENTIFIER_NODE to OB.  */
556 
557 static void
go_append_string(struct obstack * ob,tree id)558 go_append_string (struct obstack *ob, tree id)
559 {
560   obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
561 }
562 
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 
567 static const char *
go_get_uinttype_for_precision(unsigned int precision,bool is_unsigned)568 go_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 
588 static unsigned int
go_append_artificial_name(struct obstack * ob,unsigned int index)589 go_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 
604 static void
go_append_decl_name(struct obstack * ob,tree decl,htab_t keyword_hash)605 go_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 
624 static unsigned int
go_append_padding(struct obstack * ob,unsigned int from_offset,unsigned int to_offset,unsigned int align_units,unsigned int index,unsigned int * ret_offset)625 go_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    "_" to OB.  If TYPE_STRING is a null pointer, ERROR_STRING is appended
647    instead of the type.  Returns INDEX + 1.  */
648 
649 static unsigned int
go_force_record_alignment(struct obstack * ob,const char * type_string,unsigned int index,const char * error_string)650 go_force_record_alignment (struct obstack *ob, const char *type_string,
651 			   unsigned int index, const char *error_string)
652 {
653   obstack_grow (ob, "_ ", 2);
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 
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
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.  */
674 
675 static bool
go_format_type(class godump_container * container,tree type,bool use_type_name,bool is_func_ok,unsigned int * p_art_i,bool is_anon_record_or_union)676 go_format_type (class godump_container *container, tree type,
677 		bool use_type_name, bool is_func_ok, unsigned int *p_art_i,
678 		bool is_anon_record_or_union)
679 {
680   bool ret;
681   struct obstack *ob;
682   unsigned int art_i_dummy;
683   bool is_union = false;
684 
685   if (p_art_i == NULL)
686     {
687       art_i_dummy = 0;
688       p_art_i = &art_i_dummy;
689     }
690   ret = true;
691   ob = &container->type_obstack;
692 
693   if (use_type_name
694       && TYPE_NAME (type) != NULL_TREE
695       && (AGGREGATE_TYPE_P (type)
696 	  || POINTER_TYPE_P (type)
697 	  || TREE_CODE (type) == FUNCTION_TYPE))
698     {
699       tree name;
700       void **slot;
701 
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 
708       name = TYPE_IDENTIFIER (type);
709 
710       slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
711 			     NO_INSERT);
712       if (slot != NULL)
713 	ret = false;
714 
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 
721       obstack_1grow (ob, '_');
722       go_append_string (ob, name);
723       return ret;
724     }
725 
726   switch (TREE_CODE (type))
727     {
728     case TYPE_DECL:
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       }
741       break;
742 
743     case ENUMERAL_TYPE:
744     case INTEGER_TYPE:
745       {
746 	const char *s;
747 	char buf[100];
748 
749 	s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
750 					   TYPE_UNSIGNED (type));
751 	if (s == NULL)
752 	  {
753 	    snprintf (buf, sizeof buf, "INVALID-int-%u%s",
754 		      TYPE_PRECISION (type),
755 		      TYPE_UNSIGNED (type) ? "u" : "");
756 	    s = buf;
757 	    ret = false;
758 	  }
759 	obstack_grow (ob, s, strlen (s));
760       }
761       break;
762 
763     case REAL_TYPE:
764       {
765 	const char *s;
766 	char buf[100];
767 
768 	switch (TYPE_PRECISION (type))
769 	  {
770 	  case 32:
771 	    s = "float32";
772 	    break;
773 	  case 64:
774 	    s = "float64";
775 	    break;
776 	  default:
777 	    snprintf (buf, sizeof buf, "INVALID-float-%u",
778 		      TYPE_PRECISION (type));
779 	    s = buf;
780 	    ret = false;
781 	    break;
782 	  }
783 	obstack_grow (ob, s, strlen (s));
784       }
785       break;
786 
787     case COMPLEX_TYPE:
788       {
789 	const char *s;
790 	char buf[100];
791 	tree real_type;
792 
793 	real_type = TREE_TYPE (type);
794 	if (TREE_CODE (real_type) == REAL_TYPE)
795 	  {
796 	    switch (TYPE_PRECISION (real_type))
797 	      {
798 	      case 32:
799 		s = "complex64";
800 		break;
801 	      case 64:
802 		s = "complex128";
803 		break;
804 	      default:
805 		snprintf (buf, sizeof buf, "INVALID-complex-%u",
806 			  2 * TYPE_PRECISION (real_type));
807 		s = buf;
808 		ret = false;
809 		break;
810 	      }
811 	  }
812 	else
813 	  {
814 	    s = "INVALID-complex-non-real";
815 	    ret = false;
816 	  }
817 	obstack_grow (ob, s, strlen (s));
818       }
819       break;
820 
821     case BOOLEAN_TYPE:
822       obstack_grow (ob, "bool", 4);
823       break;
824 
825     case POINTER_TYPE:
826       if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
827 	obstack_grow (ob, "func", 4);
828       else
829 	obstack_1grow (ob, '*');
830       if (VOID_TYPE_P (TREE_TYPE (type)))
831 	obstack_grow (ob, "byte", 4);
832       else
833 	{
834 	  if (!go_format_type (container, TREE_TYPE (type), use_type_name,
835 			       true, NULL, false))
836 	    ret = false;
837 	}
838       break;
839 
840     case ARRAY_TYPE:
841       obstack_1grow (ob, '[');
842       if (TYPE_DOMAIN (type) != NULL_TREE
843 	  && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
844 	  && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
845 	  && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
846 	  && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
847 	  && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
848 	  && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
849 	  && tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
850 	{
851 	  char buf[100];
852 
853 	  snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
854 		    tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
855 	  obstack_grow (ob, buf, strlen (buf));
856 	}
857       else
858 	obstack_1grow (ob, '0');
859       obstack_1grow (ob, ']');
860       if (!go_format_type (container, TREE_TYPE (type), use_type_name, false,
861 			   NULL, false))
862 	ret = false;
863       break;
864 
865     case UNION_TYPE:
866       is_union = true;
867       /* Fall through to RECORD_TYPE case.  */
868       gcc_fallthrough ();
869     case RECORD_TYPE:
870       {
871 	unsigned int prev_field_end;
872 	unsigned int known_alignment;
873 	tree field;
874 	bool emitted_a_field;
875 
876 	/* FIXME: Why is this necessary?  Without it we can get a core
877 	   dump on the s390x headers, or from a file containing simply
878 	   "typedef struct S T;".  */
879 	layout_type (type);
880 
881 	prev_field_end = 0;
882 	known_alignment = 1;
883 	/* Anonymous records and unions are flattened, i.e. they are not put
884 	   into "struct { ... }".  */
885 	if (!is_anon_record_or_union)
886 	  obstack_grow (ob, "struct { ", 9);
887 	for (field = TYPE_FIELDS (type), emitted_a_field = false;
888 	     field != NULL_TREE;
889 	     field = TREE_CHAIN (field))
890 	  {
891 	    if (TREE_CODE (field) != FIELD_DECL)
892 	      continue;
893 	    if (DECL_BIT_FIELD (field))
894 	      /* Bit fields are replaced by padding.  */
895 	      continue;
896 	    /* Only the first non-bitfield field is emitted for unions.  */
897 	    if (!is_union || !emitted_a_field)
898 	      {
899 		/* Emit the field.  */
900 		bool field_ok;
901 		bool is_anon_substructure;
902 		unsigned int decl_align_unit;
903 		unsigned int decl_offset;
904 
905 		field_ok = true;
906 		emitted_a_field = true;
907 		is_anon_substructure =
908 		  (DECL_NAME (field) == NULL
909 		   && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
910 		       || TREE_CODE (TREE_TYPE (field)) == UNION_TYPE));
911 		/* Keep track of the alignment of named substructures, either
912 		   of the whole record, or the alignment of the emitted field
913 		   (for unions).  */
914 		decl_align_unit = DECL_ALIGN_UNIT (field);
915 		if (!is_anon_substructure && decl_align_unit > known_alignment)
916 		  known_alignment = decl_align_unit;
917 		/* Pad to start of field.  */
918 		decl_offset =
919 		  TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
920 		  + precision_to_units
921 		  (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)));
922 		{
923 		  unsigned int align_unit;
924 
925 		  /* For anonymous records and unions there is no automatic
926 		     structure alignment, so use 1 as the alignment.  */
927 		  align_unit = (is_anon_substructure) ? 1 : decl_align_unit;
928 		  *p_art_i = go_append_padding
929 		    (ob, prev_field_end, decl_offset, align_unit, *p_art_i,
930 		     &prev_field_end);
931 		}
932 		if (DECL_SIZE_UNIT (field))
933 		  prev_field_end +=
934 		    TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
935 		/* Emit the field name, but not for anonymous records and
936 		   unions.  */
937 		if (!is_anon_substructure)
938 		  {
939 		    if (DECL_NAME (field) == NULL)
940 		      *p_art_i = go_append_artificial_name (ob, *p_art_i);
941 		    else
942 		      go_append_decl_name
943 			(ob, field, container->keyword_hash);
944 		    obstack_1grow (ob, ' ');
945 		  }
946 		/* Do not expand type if a record or union type or a function
947 		   pointer.  */
948 		if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
949 		    && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
950 			|| (POINTER_TYPE_P (TREE_TYPE (field))
951 			    && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
952 				== FUNCTION_TYPE))))
953 		  {
954 		    tree name;
955 		    void **slot;
956 
957 		    name = TYPE_IDENTIFIER (TREE_TYPE (field));
958 
959 		    slot = htab_find_slot (container->invalid_hash,
960 					   IDENTIFIER_POINTER (name),
961 					   NO_INSERT);
962 		    if (slot != NULL)
963 		      field_ok = false;
964 
965 		    obstack_1grow (ob, '_');
966 		    go_append_string (ob, name);
967 		  }
968 		else
969 		  {
970 		    if (!go_format_type (container, TREE_TYPE (field), true,
971 					 false, p_art_i, is_anon_substructure))
972 		      field_ok = false;
973 		  }
974 		if (!is_anon_substructure)
975 		  obstack_grow (ob, "; ", 2);
976 		if (!field_ok)
977 		  ret = false;
978 	      }
979 	  }
980 	/* Padding.  */
981 	*p_art_i = go_append_padding (ob, prev_field_end,
982 				      TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)),
983 				      1, *p_art_i, &prev_field_end);
984 	/* Alignment.  */
985 	if (!is_anon_record_or_union
986 	    && known_alignment < TYPE_ALIGN_UNIT (type))
987 	  {
988 	    const char *s;
989 	    char buf[100];
990 
991 	    /* Enforce proper record alignment.  */
992 	    s = go_get_uinttype_for_precision
993 	      (TYPE_ALIGN (type), TYPE_UNSIGNED (type));
994 	    if (s == NULL)
995 	      {
996 		snprintf (buf, sizeof buf, "INVALID-int-%u%s",
997 			  TYPE_ALIGN (type), TYPE_UNSIGNED (type) ? "u" : "");
998 		s = buf;
999 		ret = false;
1000 	      }
1001 	    *p_art_i = go_force_record_alignment (ob, s, *p_art_i, buf);
1002 	  }
1003 	if (!is_anon_record_or_union)
1004 	  obstack_1grow (ob, '}');
1005       }
1006     break;
1007 
1008     case FUNCTION_TYPE:
1009       {
1010 	tree arg_type;
1011 	bool is_varargs;
1012 	tree result;
1013 	function_args_iterator iter;
1014 	bool seen_arg;
1015 
1016 	/* Go has no way to write a type which is a function but not a
1017 	   pointer to a function.  */
1018 	if (!is_func_ok)
1019 	  {
1020 	    obstack_grow (ob, "func*", 5);
1021 	    ret = false;
1022 	  }
1023 
1024 	obstack_1grow (ob, '(');
1025 	is_varargs = stdarg_p (type);
1026 	seen_arg = false;
1027 	FOREACH_FUNCTION_ARGS (type, arg_type, iter)
1028 	  {
1029 	    if (VOID_TYPE_P (arg_type))
1030 	      break;
1031 	    if (seen_arg)
1032 	      obstack_grow (ob, ", ", 2);
1033 	    if (!go_format_type (container, arg_type, true, false, NULL, false))
1034 	      ret = false;
1035 	    seen_arg = true;
1036 	  }
1037 	if (is_varargs)
1038 	  {
1039 	    if (prototype_p (type))
1040 	      obstack_grow (ob, ", ", 2);
1041 	    obstack_grow (ob, "...interface{}", 14);
1042 	  }
1043 	obstack_1grow (ob, ')');
1044 
1045 	result = TREE_TYPE (type);
1046 	if (!VOID_TYPE_P (result))
1047 	  {
1048 	    obstack_1grow (ob, ' ');
1049 	    if (!go_format_type (container, result, use_type_name, false, NULL,
1050 				 false))
1051 	      ret = false;
1052 	  }
1053       }
1054       break;
1055 
1056     default:
1057       obstack_grow (ob, "INVALID-type", 12);
1058       ret = false;
1059       break;
1060     }
1061 
1062   return ret;
1063 }
1064 
1065 /* Output the type which was built on the type obstack, and then free
1066    it.  */
1067 
1068 static void
go_output_type(class godump_container * container)1069 go_output_type (class godump_container *container)
1070 {
1071   struct obstack *ob;
1072 
1073   ob = &container->type_obstack;
1074   obstack_1grow (ob, '\0');
1075   fputs ((char *) obstack_base (ob), go_dump_file);
1076   obstack_free (ob, obstack_base (ob));
1077 }
1078 
1079 /* Output a function declaration.  */
1080 
1081 static void
go_output_fndecl(class godump_container * container,tree decl)1082 go_output_fndecl (class godump_container *container, tree decl)
1083 {
1084   if (!go_format_type (container, TREE_TYPE (decl), true, true, NULL, false))
1085     fprintf (go_dump_file, "// ");
1086   fprintf (go_dump_file, "func _%s ",
1087 	   IDENTIFIER_POINTER (DECL_NAME (decl)));
1088   go_output_type (container);
1089   fprintf (go_dump_file, " __asm__(\"%s\")\n",
1090 	   IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
1091 }
1092 
1093 /* Output a typedef or something like a struct definition.  */
1094 
1095 static void
go_output_typedef(class godump_container * container,tree decl)1096 go_output_typedef (class godump_container *container, tree decl)
1097 {
1098   /* If we have an enum type, output the enum constants
1099      separately.  */
1100   if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
1101       && TYPE_SIZE (TREE_TYPE (decl)) != 0
1102       && !container->decls_seen.contains (TREE_TYPE (decl))
1103       && (TYPE_CANONICAL (TREE_TYPE (decl)) == NULL_TREE
1104 	  || !container->decls_seen.contains
1105 				    (TYPE_CANONICAL (TREE_TYPE (decl)))))
1106     {
1107       tree element;
1108 
1109       for (element = TYPE_VALUES (TREE_TYPE (decl));
1110 	   element != NULL_TREE;
1111 	   element = TREE_CHAIN (element))
1112 	{
1113 	  const char *name;
1114 	  struct macro_hash_value *mhval;
1115 	  void **slot;
1116 	  char buf[WIDE_INT_PRINT_BUFFER_SIZE];
1117 
1118 	  name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
1119 
1120 	  /* Sometimes a name will be defined as both an enum constant
1121 	     and a macro.  Avoid duplicate definition errors by
1122 	     treating enum constants as macros.  */
1123 	  mhval = XNEW (struct macro_hash_value);
1124 	  mhval->name = xstrdup (name);
1125 	  mhval->value = NULL;
1126 	  slot = htab_find_slot (macro_hash, mhval, INSERT);
1127 	  if (*slot != NULL)
1128 	    macro_hash_del (*slot);
1129 
1130 	  if (tree_fits_shwi_p (TREE_VALUE (element)))
1131 	    snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
1132 		     tree_to_shwi (TREE_VALUE (element)));
1133 	  else if (tree_fits_uhwi_p (TREE_VALUE (element)))
1134 	    snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
1135 		      tree_to_uhwi (TREE_VALUE (element)));
1136 	  else
1137 	    print_hex (wi::to_wide (element), buf);
1138 
1139 	  mhval->value = xstrdup (buf);
1140 	  *slot = mhval;
1141 	}
1142       container->decls_seen.add (TREE_TYPE (decl));
1143       if (TYPE_CANONICAL (TREE_TYPE (decl)) != NULL_TREE)
1144 	container->decls_seen.add (TYPE_CANONICAL (TREE_TYPE (decl)));
1145     }
1146 
1147   if (DECL_NAME (decl) != NULL_TREE)
1148     {
1149       void **slot;
1150       const char *type;
1151       tree original_type;
1152 
1153       type = IDENTIFIER_POINTER (DECL_NAME (decl));
1154       original_type = DECL_ORIGINAL_TYPE (decl);
1155       if (original_type == NULL_TREE)
1156 	original_type = TREE_TYPE (decl);
1157 
1158       /* Suppress typedefs where the type name matches the underlying
1159 	 struct/union/enum tag. This way we'll emit the struct definition
1160 	 instead of an invalid recursive type.  */
1161       if (TYPE_IDENTIFIER (original_type) != NULL
1162 	  && IDENTIFIER_POINTER (TYPE_IDENTIFIER (original_type)) == type)
1163 	return;
1164 
1165       /* If type defined already, skip.  */
1166       slot = htab_find_slot (container->type_hash, type, INSERT);
1167       if (*slot != NULL)
1168 	return;
1169       *slot = CONST_CAST (void *, (const void *) type);
1170 
1171       if (!go_format_type (container, original_type, true, false,
1172 			   NULL, false))
1173 	{
1174 	  fprintf (go_dump_file, "// ");
1175 	  slot = htab_find_slot (container->invalid_hash, type, INSERT);
1176 	  *slot = CONST_CAST (void *, (const void *) type);
1177 	}
1178       fprintf (go_dump_file, "type _%s ",
1179 	       IDENTIFIER_POINTER (DECL_NAME (decl)));
1180       go_output_type (container);
1181 
1182       if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1183 	{
1184 	  HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1185 
1186 	  if (size > 0)
1187 	    fprintf (go_dump_file,
1188 		     "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1189 		     IDENTIFIER_POINTER (DECL_NAME (decl)),
1190 		     size);
1191 	}
1192 
1193       container->decls_seen.add (decl);
1194     }
1195   else if ((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
1196 	    || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
1197 	   && TYPE_NAME (TREE_TYPE (decl)) != NULL)
1198     {
1199        void **slot;
1200        const char *type;
1201        HOST_WIDE_INT size;
1202 
1203        type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1204        /* If type defined already, skip.  */
1205        slot = htab_find_slot (container->type_hash, type, INSERT);
1206        if (*slot != NULL)
1207          return;
1208        *slot = CONST_CAST (void *, (const void *) type);
1209 
1210        if (!go_format_type (container, TREE_TYPE (decl), false, false, NULL,
1211 			    false))
1212 	 {
1213 	   fprintf (go_dump_file, "// ");
1214 	   slot = htab_find_slot (container->invalid_hash, type, INSERT);
1215 	   *slot = CONST_CAST (void *, (const void *) type);
1216 	 }
1217        fprintf (go_dump_file, "type _%s ",
1218 	       IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1219        go_output_type (container);
1220 
1221        size = int_size_in_bytes (TREE_TYPE (decl));
1222        if (size > 0)
1223 	 fprintf (go_dump_file,
1224 		  "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1225 		  IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))),
1226 		  size);
1227     }
1228   else
1229     return;
1230 
1231   fprintf (go_dump_file, "\n");
1232 }
1233 
1234 /* Output a variable.  */
1235 
1236 static void
go_output_var(class godump_container * container,tree decl)1237 go_output_var (class godump_container *container, tree decl)
1238 {
1239   bool is_valid;
1240   tree type_name;
1241   tree id;
1242 
1243   if (container->decls_seen.contains (decl)
1244       || container->decls_seen.contains (DECL_NAME (decl)))
1245     return;
1246   container->decls_seen.add (decl);
1247   container->decls_seen.add (DECL_NAME (decl));
1248 
1249   type_name = TYPE_NAME (TREE_TYPE (decl));
1250   id = NULL_TREE;
1251   if (type_name != NULL_TREE && TREE_CODE (type_name) == IDENTIFIER_NODE)
1252     id = type_name;
1253   else if (type_name != NULL_TREE && TREE_CODE (type_name) == TYPE_DECL
1254 	   && DECL_SOURCE_LOCATION (type_name) != BUILTINS_LOCATION
1255 	   && DECL_NAME (type_name))
1256     id = DECL_NAME (type_name);
1257   if (id != NULL_TREE
1258       && (!htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1259 			   NO_INSERT)
1260 	  || htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (id),
1261 			     NO_INSERT)))
1262     id = NULL_TREE;
1263   if (id != NULL_TREE)
1264     {
1265       struct obstack *ob;
1266 
1267       ob = &container->type_obstack;
1268       obstack_1grow (ob, '_');
1269       go_append_string (ob, id);
1270       is_valid = htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1271 				 NO_INSERT) != NULL;
1272     }
1273   else
1274     is_valid = go_format_type (container, TREE_TYPE (decl), true, false, NULL,
1275 			       false);
1276   if (is_valid
1277       && htab_find_slot (container->type_hash,
1278 			 IDENTIFIER_POINTER (DECL_NAME (decl)),
1279 			 NO_INSERT) != NULL)
1280     {
1281       /* There is already a type with this name, probably from a
1282 	 struct tag.  Prefer the type to the variable.  */
1283       is_valid = false;
1284     }
1285   if (!is_valid)
1286     fprintf (go_dump_file, "// ");
1287 
1288   fprintf (go_dump_file, "var _%s ",
1289 	   IDENTIFIER_POINTER (DECL_NAME (decl)));
1290   go_output_type (container);
1291   fprintf (go_dump_file, "\n");
1292 
1293   /* Sometimes an extern variable is declared with an unknown struct
1294      type.  */
1295   if (type_name != NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1296     {
1297       if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1298 	container->pot_dummy_types.add (IDENTIFIER_POINTER (type_name));
1299       else if (TREE_CODE (type_name) == TYPE_DECL)
1300 	container->pot_dummy_types.add
1301 			    (IDENTIFIER_POINTER (DECL_NAME (type_name)));
1302     }
1303 }
1304 
1305 /* Output the final value of a preprocessor macro or enum constant.
1306    This is called via htab_traverse_noresize.  */
1307 
1308 static int
go_print_macro(void ** slot,void * arg ATTRIBUTE_UNUSED)1309 go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1310 {
1311   struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1312   fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1313   return 1;
1314 }
1315 
1316 /* Build a hash table with the Go keywords.  */
1317 
1318 static const char * const keywords[] = {
1319   "__asm__", "break", "case", "chan", "const", "continue", "default",
1320   "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1321   "import", "interface", "map", "package", "range", "return", "select",
1322   "struct", "switch", "type", "var"
1323 };
1324 
1325 static void
keyword_hash_init(class godump_container * container)1326 keyword_hash_init (class godump_container *container)
1327 {
1328   size_t i;
1329   size_t count = sizeof (keywords) / sizeof (keywords[0]);
1330   void **slot;
1331 
1332   for (i = 0; i < count; i++)
1333     {
1334       slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1335       *slot = CONST_CAST (void *, (const void *) keywords[i]);
1336     }
1337 }
1338 
1339 /* Traversing the pot_dummy_types and seeing which types are present
1340    in the global types hash table and creating dummy definitions if
1341    not found.  This function is invoked by hash_set::traverse.  */
1342 
1343 bool
find_dummy_types(const char * const & ptr,godump_container * adata)1344 find_dummy_types (const char *const &ptr, godump_container *adata)
1345 {
1346   class godump_container *data = (class godump_container *) adata;
1347   const char *type = (const char *) ptr;
1348   void **slot;
1349   void **islot;
1350 
1351   slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1352   islot = htab_find_slot (data->invalid_hash, type, NO_INSERT);
1353   if (slot == NULL || islot != NULL)
1354     fprintf (go_dump_file, "type _%s struct {}\n", type);
1355   return true;
1356 }
1357 
1358 /* Output symbols.  */
1359 
1360 static void
go_finish(const char * filename)1361 go_finish (const char *filename)
1362 {
1363   class godump_container container;
1364   unsigned int ix;
1365   tree decl;
1366 
1367   real_debug_hooks->finish (filename);
1368 
1369   container.type_hash = htab_create (100, htab_hash_string,
1370 				     htab_eq_string, NULL);
1371   container.invalid_hash = htab_create (10, htab_hash_string,
1372 					htab_eq_string, NULL);
1373   container.keyword_hash = htab_create (50, htab_hash_string,
1374 					htab_eq_string, NULL);
1375   obstack_init (&container.type_obstack);
1376 
1377   keyword_hash_init (&container);
1378 
1379   FOR_EACH_VEC_SAFE_ELT (queue, ix, decl)
1380     {
1381       switch (TREE_CODE (decl))
1382 	{
1383 	case FUNCTION_DECL:
1384 	  go_output_fndecl (&container, decl);
1385 	  break;
1386 
1387 	case TYPE_DECL:
1388 	  go_output_typedef (&container, decl);
1389 	  break;
1390 
1391 	case VAR_DECL:
1392 	  go_output_var (&container, decl);
1393 	  break;
1394 
1395 	default:
1396 	  gcc_unreachable ();
1397 	}
1398     }
1399 
1400   htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1401 
1402   /* To emit dummy definitions.  */
1403   container.pot_dummy_types.traverse<godump_container *, find_dummy_types>
1404                         (&container);
1405 
1406   htab_delete (container.type_hash);
1407   htab_delete (container.invalid_hash);
1408   htab_delete (container.keyword_hash);
1409   obstack_free (&container.type_obstack, NULL);
1410 
1411   vec_free (queue);
1412 
1413   if (fclose (go_dump_file) != 0)
1414     error ("could not close Go dump file: %m");
1415   go_dump_file = NULL;
1416 }
1417 
1418 /* Set up our hooks.  */
1419 
1420 const struct gcc_debug_hooks *
dump_go_spec_init(const char * filename,const struct gcc_debug_hooks * hooks)1421 dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1422 {
1423   go_dump_file = fopen (filename, "w");
1424   if (go_dump_file == NULL)
1425     {
1426       error ("could not open Go dump file %qs: %m", filename);
1427       return hooks;
1428     }
1429 
1430   go_debug_hooks = *hooks;
1431   real_debug_hooks = hooks;
1432 
1433   go_debug_hooks.finish = go_finish;
1434   go_debug_hooks.define = go_define;
1435   go_debug_hooks.undef = go_undef;
1436   go_debug_hooks.function_decl = go_function_decl;
1437   go_debug_hooks.early_global_decl = go_early_global_decl;
1438   go_debug_hooks.late_global_decl = go_late_global_decl;
1439   go_debug_hooks.type_decl = go_type_decl;
1440 
1441   macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1442 			    macro_hash_del);
1443 
1444   return &go_debug_hooks;
1445 }
1446 
1447 #include "gt-godump.h"
1448