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