Branch data Line data Source code
1 : : /* Output Go language descriptions of types.
2 : : Copyright (C) 2008-2025 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
79 : 2791 : precision_to_units (unsigned int precision)
80 : : {
81 : 2791 : 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
87 : 34070 : macro_hash_hashval (const void *val)
88 : : {
89 : 34070 : const struct macro_hash_value *mhval = (const struct macro_hash_value *) val;
90 : 34070 : return htab_hash_string (mhval->name);
91 : : }
92 : :
93 : : /* Compare values in the macro hash table for equality. */
94 : :
95 : : static int
96 : 43171 : macro_hash_eq (const void *v1, const void *v2)
97 : : {
98 : 43171 : const struct macro_hash_value *mhv1 = (const struct macro_hash_value *) v1;
99 : 43171 : const struct macro_hash_value *mhv2 = (const struct macro_hash_value *) v2;
100 : 43171 : return strcmp (mhv1->name, mhv2->name) == 0;
101 : : }
102 : :
103 : : /* Free values deleted from the macro hash table. */
104 : :
105 : : static void
106 : 549 : macro_hash_del (void *v)
107 : : {
108 : 549 : struct macro_hash_value *mhv = (struct macro_hash_value *) v;
109 : 549 : XDELETEVEC (mhv->name);
110 : 549 : XDELETEVEC (mhv->value);
111 : 549 : XDELETE (mhv);
112 : 549 : }
113 : :
114 : : /* A macro definition. */
115 : :
116 : : static void
117 : 14827 : go_define (unsigned int lineno, const char *buffer)
118 : : {
119 : 14827 : const char *p;
120 : 14827 : const char *name_end;
121 : 14827 : size_t out_len;
122 : 14827 : char *out_buffer;
123 : 14827 : char *q;
124 : 14827 : bool saw_operand;
125 : 14827 : bool need_operand;
126 : 14827 : struct macro_hash_value *mhval;
127 : 14827 : char *copy;
128 : 14827 : hashval_t hashval;
129 : 14827 : void **slot;
130 : :
131 : 14827 : real_debug_hooks->define (lineno, buffer);
132 : :
133 : : /* Skip macro functions. */
134 : 234295 : for (p = buffer; *p != '\0' && *p != ' '; ++p)
135 : 205429 : if (*p == '(')
136 : : return;
137 : :
138 : 14039 : if (*p == '\0')
139 : : return;
140 : :
141 : 14039 : name_end = p;
142 : :
143 : 14039 : ++p;
144 : 14039 : if (*p == '\0')
145 : : return;
146 : :
147 : 13607 : copy = XNEWVEC (char, name_end - buffer + 1);
148 : 13607 : memcpy (copy, buffer, name_end - buffer);
149 : 13607 : copy[name_end - buffer] = '\0';
150 : :
151 : 13607 : mhval = XNEW (struct macro_hash_value);
152 : 13607 : mhval->name = copy;
153 : 13607 : mhval->value = NULL;
154 : :
155 : 13607 : hashval = htab_hash_string (copy);
156 : 13607 : 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 : 13607 : out_len = strlen (p) * 2 + 1;
161 : 13607 : out_buffer = XNEWVEC (char, out_len);
162 : 13607 : q = out_buffer;
163 : 13607 : saw_operand = false;
164 : 13607 : need_operand = false;
165 : 42557 : while (*p != '\0')
166 : : {
167 : 18440 : switch (*p)
168 : : {
169 : 4811 : case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
170 : 4811 : case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
171 : 4811 : case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
172 : 4811 : case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
173 : 4811 : case 'Y': case 'Z':
174 : 4811 : case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
175 : 4811 : case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
176 : 4811 : case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
177 : 4811 : case 's': case 't': case 'u': case 'v': case 'w': case 'x':
178 : 4811 : case 'y': case 'z':
179 : 4811 : case '_':
180 : 4811 : {
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 : 4811 : const char *start;
186 : 4811 : char *n;
187 : 4811 : struct macro_hash_value idval;
188 : :
189 : 4811 : if (saw_operand)
190 : 2922 : goto unknown;
191 : :
192 : : start = p;
193 : 63861 : while (ISALNUM (*p) || *p == '_')
194 : 59126 : ++p;
195 : 4735 : n = XALLOCAVEC (char, p - start + 1);
196 : 4735 : memcpy (n, start, p - start);
197 : 4735 : n[p - start] = '\0';
198 : 4735 : idval.name = n;
199 : 4735 : idval.value = NULL;
200 : 4735 : 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 : 2846 : goto unknown;
205 : : }
206 : :
207 : 1889 : *q++ = '_';
208 : 1889 : memcpy (q, start, p - start);
209 : 1889 : q += p - start;
210 : :
211 : 1889 : saw_operand = true;
212 : 1889 : need_operand = false;
213 : : }
214 : 1889 : break;
215 : :
216 : 0 : case '.':
217 : 0 : if (!ISDIGIT (p[1]))
218 : 0 : goto unknown;
219 : : /* Fall through. */
220 : 9506 : case '0': case '1': case '2': case '3': case '4':
221 : 9506 : case '5': case '6': case '7': case '8': case '9':
222 : 9506 : {
223 : 9506 : const char *start;
224 : 9506 : bool is_hex;
225 : :
226 : 9506 : start = p;
227 : 9506 : is_hex = false;
228 : 9506 : if (*p == '0' && (p[1] == 'x' || p[1] == 'X'))
229 : : {
230 : 1871 : p += 2;
231 : 1871 : is_hex = true;
232 : : }
233 : 42505 : while (ISDIGIT (*p) || *p == '.' || *p == 'e' || *p == 'E'
234 : 53997 : || (is_hex
235 : 3857 : && ((*p >= 'a' && *p <= 'f')
236 : 2097 : || (*p >= 'A' && *p <= 'F'))))
237 : 32999 : ++p;
238 : 9506 : memcpy (q, start, p - start);
239 : 9506 : q += p - start;
240 : 9506 : while (*p == 'u' || *p == 'U' || *p == 'l' || *p == 'L'
241 : : || *p == 'f' || *p == 'F'
242 : 10322 : || *p == 'd' || *p == 'D')
243 : : {
244 : : /* Go doesn't use any of these trailing type
245 : : modifiers. */
246 : 816 : ++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 : 972 : case ' ': case '\t':
258 : 972 : *q++ = *p++;
259 : 972 : break;
260 : :
261 : 1071 : case '(':
262 : : /* Always OK, not part of an operand, presumed to start an
263 : : operand. */
264 : 1071 : *q++ = *p++;
265 : 1071 : saw_operand = false;
266 : 1071 : need_operand = false;
267 : 1071 : break;
268 : :
269 : 626 : case ')':
270 : : /* OK if we don't need an operand, and presumed to indicate
271 : : an operand. */
272 : 626 : if (need_operand)
273 : 0 : goto unknown;
274 : 626 : *q++ = *p++;
275 : 626 : saw_operand = true;
276 : 626 : break;
277 : :
278 : 554 : case '+': case '-':
279 : : /* Always OK, but not part of an operand. */
280 : 554 : *q++ = *p++;
281 : 554 : saw_operand = false;
282 : 554 : break;
283 : :
284 : 174 : case '*': case '/': case '%': case '|': case '&': case '^':
285 : : /* Must be a binary operator. */
286 : 174 : if (!saw_operand)
287 : 6 : goto unknown;
288 : 168 : *q++ = *p++;
289 : 168 : saw_operand = false;
290 : 168 : need_operand = true;
291 : 168 : break;
292 : :
293 : 0 : case '=':
294 : 0 : *q++ = *p++;
295 : 0 : if (*p != '=')
296 : 0 : goto unknown;
297 : : /* Must be a binary operator. */
298 : 0 : if (!saw_operand)
299 : 0 : goto unknown;
300 : 0 : *q++ = *p++;
301 : 0 : saw_operand = false;
302 : 0 : need_operand = true;
303 : 0 : break;
304 : :
305 : 0 : case '!':
306 : 0 : *q++ = *p++;
307 : 0 : if (*p == '=')
308 : : {
309 : : /* Must be a binary operator. */
310 : 0 : if (!saw_operand)
311 : 0 : goto unknown;
312 : 0 : *q++ = *p++;
313 : 0 : saw_operand = false;
314 : 0 : need_operand = true;
315 : : }
316 : : else
317 : : {
318 : : /* Must be a unary operator. */
319 : 0 : if (saw_operand)
320 : 0 : goto unknown;
321 : : need_operand = true;
322 : : }
323 : : break;
324 : :
325 : 292 : case '<': case '>':
326 : : /* Must be a binary operand, may be << or >> or <= or >=. */
327 : 292 : if (!saw_operand)
328 : 0 : goto unknown;
329 : 292 : *q++ = *p++;
330 : 292 : if (*p == *(p - 1) || *p == '=')
331 : 292 : *q++ = *p++;
332 : : saw_operand = false;
333 : : need_operand = true;
334 : : break;
335 : :
336 : 10 : case '~':
337 : : /* Must be a unary operand, must be translated for Go. */
338 : 10 : if (saw_operand)
339 : 0 : goto unknown;
340 : 10 : *q++ = '^';
341 : 10 : p++;
342 : 10 : need_operand = true;
343 : 10 : break;
344 : :
345 : 411 : case '"':
346 : 411 : case '\'':
347 : 411 : {
348 : 411 : char quote;
349 : 411 : int count;
350 : :
351 : 411 : if (saw_operand)
352 : 154 : goto unknown;
353 : 257 : quote = *p;
354 : 257 : *q++ = *p++;
355 : 257 : count = 0;
356 : 1177 : while (*p != quote)
357 : : {
358 : 922 : int c;
359 : :
360 : 922 : if (*p == '\0')
361 : 0 : goto unknown;
362 : :
363 : 922 : ++count;
364 : :
365 : 922 : if (*p != '\\')
366 : : {
367 : 920 : *q++ = *p++;
368 : 920 : continue;
369 : : }
370 : :
371 : 2 : *q++ = *p++;
372 : 2 : 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 : 4 : while (*p >= '0' && *p <= '7')
378 : : {
379 : 2 : *q++ = *p++;
380 : 2 : ++c;
381 : : }
382 : : /* Go octal characters are always 3
383 : : digits. */
384 : 2 : if (c != 3)
385 : 2 : goto unknown;
386 : : break;
387 : :
388 : 0 : case 'x':
389 : 0 : *q++ = *p++;
390 : 0 : c = 0;
391 : 0 : while (ISXDIGIT (*p))
392 : : {
393 : 0 : *q++ = *p++;
394 : 0 : ++c;
395 : : }
396 : : /* Go hex characters are always 2 digits. */
397 : 0 : if (c != 2)
398 : 0 : goto unknown;
399 : : break;
400 : :
401 : 0 : case 'a': case 'b': case 'f': case 'n': case 'r':
402 : 0 : case 't': case 'v': case '\\': case '\'': case '"':
403 : 0 : *q++ = *p++;
404 : 0 : break;
405 : :
406 : 0 : default:
407 : 0 : goto unknown;
408 : : }
409 : : }
410 : :
411 : 255 : *q++ = *p++;
412 : :
413 : 255 : if (quote == '\'' && count != 1)
414 : 0 : goto unknown;
415 : :
416 : : saw_operand = true;
417 : : need_operand = false;
418 : :
419 : : break;
420 : : }
421 : :
422 : 13 : default:
423 : 13 : goto unknown;
424 : : }
425 : : }
426 : :
427 : 10510 : if (need_operand)
428 : 0 : goto unknown;
429 : :
430 : 10510 : gcc_assert ((size_t) (q - out_buffer) < out_len);
431 : 10510 : *q = '\0';
432 : :
433 : 10510 : mhval->value = out_buffer;
434 : :
435 : 10510 : if (slot == NULL)
436 : : {
437 : 10242 : slot = htab_find_slot_with_hash (macro_hash, mhval, hashval, INSERT);
438 : 10242 : gcc_assert (slot != NULL && *slot == NULL);
439 : : }
440 : : else
441 : : {
442 : 268 : if (*slot != NULL)
443 : 268 : macro_hash_del (*slot);
444 : : }
445 : :
446 : 10510 : *slot = mhval;
447 : :
448 : 10510 : return;
449 : :
450 : 3097 : unknown:
451 : 3097 : fprintf (go_dump_file, "// unknowndefine %s\n", buffer);
452 : 3097 : if (slot != NULL)
453 : 0 : htab_clear_slot (macro_hash, slot);
454 : 3097 : XDELETEVEC (out_buffer);
455 : 3097 : XDELETEVEC (copy);
456 : : }
457 : :
458 : : /* A macro undef. */
459 : :
460 : : static void
461 : 674 : go_undef (unsigned int lineno, const char *buffer)
462 : : {
463 : 674 : struct macro_hash_value mhval;
464 : 674 : void **slot;
465 : :
466 : 674 : real_debug_hooks->undef (lineno, buffer);
467 : :
468 : 674 : mhval.name = CONST_CAST (char *, buffer);
469 : 674 : mhval.value = NULL;
470 : 674 : slot = htab_find_slot (macro_hash, &mhval, NO_INSERT);
471 : 674 : if (slot != NULL)
472 : 150 : htab_clear_slot (macro_hash, slot);
473 : 674 : }
474 : :
475 : : /* A function or variable decl. */
476 : :
477 : : static void
478 : 2988 : go_decl (tree decl)
479 : : {
480 : 2988 : if (!TREE_PUBLIC (decl)
481 : 2215 : || DECL_IS_UNDECLARED_BUILTIN (decl)
482 : 5203 : || DECL_NAME (decl) == NULL_TREE)
483 : : return;
484 : 2215 : vec_safe_push (queue, decl);
485 : : }
486 : :
487 : : /* A function decl. */
488 : :
489 : : static void
490 : 0 : go_function_decl (tree decl)
491 : : {
492 : 0 : real_debug_hooks->function_decl (decl);
493 : 0 : go_decl (decl);
494 : 0 : }
495 : :
496 : : static void
497 : 2988 : go_early_global_decl (tree decl)
498 : : {
499 : 2988 : go_decl (decl);
500 : 2988 : if (TREE_CODE (decl) != FUNCTION_DECL || DECL_STRUCT_FUNCTION (decl) != NULL)
501 : 1112 : real_debug_hooks->early_global_decl (decl);
502 : 2988 : }
503 : :
504 : : /* A global variable decl. */
505 : :
506 : : static void
507 : 133 : go_late_global_decl (tree decl)
508 : : {
509 : 133 : real_debug_hooks->late_global_decl (decl);
510 : 133 : }
511 : :
512 : : /* A type declaration. */
513 : :
514 : : static void
515 : 1929 : go_type_decl (tree decl, int local)
516 : : {
517 : 1929 : real_debug_hooks->type_decl (decl, local);
518 : :
519 : 1929 : if (local || DECL_IS_UNDECLARED_BUILTIN (decl))
520 : : return;
521 : 1809 : if (DECL_NAME (decl) == NULL_TREE
522 : 1036 : && (TYPE_NAME (TREE_TYPE (decl)) == NULL_TREE
523 : 525 : || TREE_CODE (TYPE_NAME (TREE_TYPE (decl))) != IDENTIFIER_NODE)
524 : 2320 : && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE)
525 : : return;
526 : 1505 : 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 : 4 : 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
558 : 4217 : go_append_string (struct obstack *ob, tree id)
559 : : {
560 : 4217 : obstack_grow (ob, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
561 : 4217 : }
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 *
568 : 7738 : go_get_uinttype_for_precision (unsigned int precision, bool is_unsigned)
569 : : {
570 : 7738 : switch (precision)
571 : : {
572 : 1812 : case 8:
573 : 1812 : return is_unsigned ? "uint8" : "int8";
574 : 433 : case 16:
575 : 433 : return is_unsigned ? "uint16" : "int16";
576 : 4262 : case 32:
577 : 4262 : return is_unsigned ? "uint32" : "int32";
578 : 1228 : case 64:
579 : 1228 : 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
589 : 150 : go_append_artificial_name (struct obstack *ob, unsigned int index)
590 : : {
591 : 150 : char buf[100];
592 : :
593 : : /* FIXME: identifier may not be unique. */
594 : 150 : obstack_grow (ob, "Godump_", 7);
595 : 150 : snprintf (buf, sizeof buf, "%u", index);
596 : 150 : obstack_grow (ob, buf, strlen (buf));
597 : :
598 : 150 : 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
605 : 2699 : go_append_decl_name (struct obstack *ob, tree decl, htab_t keyword_hash)
606 : : {
607 : 2699 : const char *var_name;
608 : 2699 : void **slot;
609 : :
610 : : /* Start variable name with an underscore if a keyword. */
611 : 2699 : var_name = IDENTIFIER_POINTER (DECL_NAME (decl));
612 : 2699 : slot = htab_find_slot (keyword_hash, var_name, NO_INSERT);
613 : 2699 : if (slot != NULL)
614 : 4 : obstack_1grow (ob, '_');
615 : 2699 : go_append_string (ob, DECL_NAME (decl));
616 : 2699 : }
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
625 : 3512 : 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 : 3512 : if (from_offset % align_units > 0)
630 : 54 : from_offset += align_units - (from_offset % align_units);
631 : 3512 : gcc_assert (to_offset >= from_offset);
632 : 3512 : if (to_offset > from_offset)
633 : : {
634 : 124 : char buf[100];
635 : :
636 : 124 : index = go_append_artificial_name (ob, index);
637 : 124 : snprintf (buf, sizeof buf, "_pad [%u]byte; ", to_offset - from_offset);
638 : 124 : obstack_grow (ob, buf, strlen (buf));
639 : : }
640 : 3512 : *ret_offset = to_offset;
641 : :
642 : 3512 : 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
650 : 59 : go_force_record_alignment (struct obstack *ob, const char *type_string,
651 : : unsigned int index, const char *error_string)
652 : : {
653 : 59 : obstack_grow (ob, "_ ", 2);
654 : 59 : if (type_string == NULL)
655 : 0 : obstack_grow (ob, error_string, strlen (error_string));
656 : : else
657 : : {
658 : 59 : obstack_grow (ob, "[0]", 3);
659 : 59 : obstack_grow (ob, type_string, strlen (type_string));
660 : : }
661 : 59 : obstack_grow (ob, "; ", 2);
662 : :
663 : 59 : 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
676 : 15386 : 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 : 15386 : bool ret;
681 : 15386 : struct obstack *ob;
682 : 15386 : unsigned int art_i_dummy;
683 : 15386 : bool is_union = false;
684 : :
685 : 15386 : if (p_art_i == NULL)
686 : : {
687 : 12792 : art_i_dummy = 0;
688 : 12792 : p_art_i = &art_i_dummy;
689 : : }
690 : 15386 : ret = true;
691 : 15386 : ob = &container->type_obstack;
692 : :
693 : 15386 : if (use_type_name
694 : 14861 : && TYPE_NAME (type) != NULL_TREE
695 : 24332 : && (AGGREGATE_TYPE_P (type)
696 : : || POINTER_TYPE_P (type)
697 : : || TREE_CODE (type) == FUNCTION_TYPE))
698 : : {
699 : 1242 : tree name;
700 : 1242 : void **slot;
701 : :
702 : : /* References to complex builtin types cannot be translated to
703 : : Go. */
704 : 1242 : if (DECL_P (TYPE_NAME (type))
705 : 1242 : && DECL_IS_UNDECLARED_BUILTIN (TYPE_NAME (type)))
706 : : ret = false;
707 : :
708 : 1242 : name = TYPE_IDENTIFIER (type);
709 : :
710 : 1242 : slot = htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (name),
711 : : NO_INSERT);
712 : 1242 : if (slot != NULL)
713 : 17 : 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 : 1242 : if (RECORD_OR_UNION_TYPE_P (type))
719 : 1129 : container->pot_dummy_types.add (IDENTIFIER_POINTER (name));
720 : :
721 : 1242 : obstack_1grow (ob, '_');
722 : 1242 : go_append_string (ob, name);
723 : 1242 : return ret;
724 : : }
725 : :
726 : 14144 : switch (TREE_CODE (type))
727 : : {
728 : 0 : case TYPE_DECL:
729 : 0 : {
730 : 0 : void **slot;
731 : :
732 : 0 : slot = htab_find_slot (container->invalid_hash,
733 : 0 : IDENTIFIER_POINTER (DECL_NAME (type)),
734 : : NO_INSERT);
735 : 0 : if (slot != NULL)
736 : 0 : ret = false;
737 : :
738 : 0 : obstack_1grow (ob, '_');
739 : 0 : go_append_string (ob, DECL_NAME (type));
740 : : }
741 : 0 : break;
742 : :
743 : 7675 : case ENUMERAL_TYPE:
744 : 7675 : case INTEGER_TYPE:
745 : 7675 : {
746 : 7675 : const char *s;
747 : 7675 : char buf[100];
748 : :
749 : 7675 : s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
750 : 7675 : TYPE_UNSIGNED (type));
751 : 7675 : if (s == NULL)
752 : : {
753 : 6 : snprintf (buf, sizeof buf, "INVALID-int-%u%s",
754 : 2 : TYPE_PRECISION (type),
755 : 2 : TYPE_UNSIGNED (type) ? "u" : "");
756 : 2 : s = buf;
757 : 2 : ret = false;
758 : : }
759 : 7675 : obstack_grow (ob, s, strlen (s));
760 : : }
761 : 7675 : break;
762 : :
763 : 4 : case BITINT_TYPE:
764 : 4 : {
765 : 4 : const char *s;
766 : 4 : char buf[100];
767 : :
768 : 4 : s = go_get_uinttype_for_precision (TYPE_PRECISION (type),
769 : 4 : TYPE_UNSIGNED (type));
770 : 4 : if (s == NULL)
771 : : {
772 : 3 : snprintf (buf, sizeof buf, "INVALID-bitint-%u%s",
773 : 1 : TYPE_PRECISION (type),
774 : 1 : TYPE_UNSIGNED (type) ? "u" : "");
775 : 1 : s = buf;
776 : 1 : ret = false;
777 : : }
778 : 4 : obstack_grow (ob, s, strlen(s));
779 : : }
780 : 4 : break;
781 : :
782 : 97 : case REAL_TYPE:
783 : 97 : {
784 : 97 : const char *s;
785 : 97 : char buf[100];
786 : :
787 : 97 : switch (TYPE_PRECISION (type))
788 : : {
789 : : case 32:
790 : : s = "float32";
791 : : break;
792 : 48 : case 64:
793 : 48 : s = "float64";
794 : 48 : break;
795 : 31 : default:
796 : 62 : snprintf (buf, sizeof buf, "INVALID-float-%u",
797 : 31 : TYPE_PRECISION (type));
798 : 31 : s = buf;
799 : 31 : ret = false;
800 : 31 : break;
801 : : }
802 : 97 : obstack_grow (ob, s, strlen (s));
803 : : }
804 : 97 : break;
805 : :
806 : 12 : case COMPLEX_TYPE:
807 : 12 : {
808 : 12 : const char *s;
809 : 12 : char buf[100];
810 : 12 : tree real_type;
811 : :
812 : 12 : real_type = TREE_TYPE (type);
813 : 12 : if (TREE_CODE (real_type) == REAL_TYPE)
814 : : {
815 : 9 : switch (TYPE_PRECISION (real_type))
816 : : {
817 : : case 32:
818 : : s = "complex64";
819 : : break;
820 : 4 : case 64:
821 : 4 : s = "complex128";
822 : 4 : break;
823 : 3 : default:
824 : 6 : snprintf (buf, sizeof buf, "INVALID-complex-%u",
825 : 3 : 2 * TYPE_PRECISION (real_type));
826 : 3 : s = buf;
827 : 3 : ret = false;
828 : 3 : break;
829 : : }
830 : : }
831 : : else
832 : : {
833 : : s = "INVALID-complex-non-real";
834 : : ret = false;
835 : : }
836 : 12 : obstack_grow (ob, s, strlen (s));
837 : : }
838 : 12 : break;
839 : :
840 : 0 : case BOOLEAN_TYPE:
841 : 0 : obstack_grow (ob, "bool", 4);
842 : 0 : break;
843 : :
844 : 3419 : case POINTER_TYPE:
845 : 3419 : if (TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
846 : 76 : obstack_grow (ob, "func", 4);
847 : : else
848 : 3343 : obstack_1grow (ob, '*');
849 : 3419 : if (VOID_TYPE_P (TREE_TYPE (type)))
850 : 416 : obstack_grow (ob, "byte", 4);
851 : : else
852 : : {
853 : 3003 : if (!go_format_type (container, TREE_TYPE (type), use_type_name,
854 : : true, NULL, false))
855 : 23 : ret = false;
856 : : }
857 : : break;
858 : :
859 : 262 : case ARRAY_TYPE:
860 : 262 : obstack_1grow (ob, '[');
861 : 262 : if (TYPE_DOMAIN (type) != NULL_TREE
862 : 261 : && TREE_CODE (TYPE_DOMAIN (type)) == INTEGER_TYPE
863 : 261 : && TYPE_MIN_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
864 : 261 : && TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
865 : 261 : && tree_int_cst_sgn (TYPE_MIN_VALUE (TYPE_DOMAIN (type))) == 0
866 : 261 : && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
867 : 248 : && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) == INTEGER_CST
868 : 510 : && tree_fits_shwi_p (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
869 : : {
870 : 248 : char buf[100];
871 : :
872 : 496 : snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC "+1",
873 : 248 : tree_to_shwi (TYPE_MAX_VALUE (TYPE_DOMAIN (type))));
874 : 248 : obstack_grow (ob, buf, strlen (buf));
875 : : }
876 : : else
877 : 14 : obstack_1grow (ob, '0');
878 : 262 : obstack_1grow (ob, ']');
879 : 262 : if (!go_format_type (container, TREE_TYPE (type), use_type_name, false,
880 : : NULL, false))
881 : 23 : ret = false;
882 : : break;
883 : :
884 : 130 : case UNION_TYPE:
885 : 130 : is_union = true;
886 : : /* Fall through to RECORD_TYPE case. */
887 : 721 : gcc_fallthrough ();
888 : 721 : case RECORD_TYPE:
889 : 721 : {
890 : 721 : unsigned int prev_field_end;
891 : 721 : unsigned int known_alignment;
892 : 721 : tree field;
893 : 721 : bool emitted_a_field;
894 : :
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 : 721 : layout_type (type);
899 : :
900 : 721 : prev_field_end = 0;
901 : 721 : known_alignment = 1;
902 : : /* Anonymous records and unions are flattened, i.e. they are not put
903 : : into "struct { ... }". */
904 : 721 : if (!is_anon_record_or_union)
905 : 655 : obstack_grow (ob, "struct { ", 9);
906 : 721 : for (field = TYPE_FIELDS (type), emitted_a_field = false;
907 : 3844 : field != NULL_TREE;
908 : 3123 : field = TREE_CHAIN (field))
909 : : {
910 : 3123 : if (TREE_CODE (field) != FIELD_DECL)
911 : 0 : continue;
912 : 3123 : if (DECL_BIT_FIELD (field))
913 : : /* Bit fields are replaced by padding. */
914 : 122 : continue;
915 : : /* Only the first non-bitfield field is emitted for unions. */
916 : 3001 : if (!is_union || !emitted_a_field)
917 : : {
918 : : /* Emit the field. */
919 : 2791 : bool field_ok;
920 : 2791 : bool is_anon_substructure;
921 : 2791 : unsigned int decl_align_unit;
922 : 2791 : unsigned int decl_offset;
923 : :
924 : 2791 : field_ok = true;
925 : 2791 : emitted_a_field = true;
926 : 5582 : is_anon_substructure =
927 : 2791 : (DECL_NAME (field) == NULL
928 : 2791 : && (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE
929 : 78 : || 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 : 2791 : decl_align_unit = DECL_ALIGN_UNIT (field);
934 : 2791 : if (!is_anon_substructure && decl_align_unit > known_alignment)
935 : 683 : known_alignment = decl_align_unit;
936 : : /* Pad to start of field. */
937 : 5582 : decl_offset =
938 : 2791 : TREE_INT_CST_LOW (DECL_FIELD_OFFSET (field))
939 : 2791 : + precision_to_units
940 : 2791 : (TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (field)));
941 : 2791 : {
942 : 2791 : 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 : 2791 : align_unit = (is_anon_substructure) ? 1 : decl_align_unit;
947 : 5582 : *p_art_i = go_append_padding
948 : 2791 : (ob, prev_field_end, decl_offset, align_unit, *p_art_i,
949 : : &prev_field_end);
950 : : }
951 : 2791 : if (DECL_SIZE_UNIT (field))
952 : 5562 : prev_field_end +=
953 : 2781 : TREE_INT_CST_LOW (DECL_SIZE_UNIT (field));
954 : : /* Emit the field name, but not for anonymous records and
955 : : unions. */
956 : 2791 : if (!is_anon_substructure)
957 : : {
958 : 2725 : if (DECL_NAME (field) == NULL)
959 : 26 : *p_art_i = go_append_artificial_name (ob, *p_art_i);
960 : : else
961 : 2699 : go_append_decl_name
962 : 2699 : (ob, field, container->keyword_hash);
963 : 2725 : obstack_1grow (ob, ' ');
964 : : }
965 : : /* Do not expand type if a record or union type or a function
966 : : pointer. */
967 : 2791 : if (TYPE_NAME (TREE_TYPE (field)) != NULL_TREE
968 : 2791 : && (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
969 : 2043 : || (POINTER_TYPE_P (TREE_TYPE (field))
970 : 6 : && (TREE_CODE (TREE_TYPE (TREE_TYPE (field)))
971 : : == FUNCTION_TYPE))))
972 : : {
973 : 197 : tree name;
974 : 197 : void **slot;
975 : :
976 : 197 : name = TYPE_IDENTIFIER (TREE_TYPE (field));
977 : :
978 : 197 : slot = htab_find_slot (container->invalid_hash,
979 : 197 : IDENTIFIER_POINTER (name),
980 : : NO_INSERT);
981 : 197 : if (slot != NULL)
982 : 0 : field_ok = false;
983 : :
984 : 197 : obstack_1grow (ob, '_');
985 : 197 : go_append_string (ob, name);
986 : : }
987 : : else
988 : : {
989 : 2594 : if (!go_format_type (container, TREE_TYPE (field), true,
990 : : false, p_art_i, is_anon_substructure))
991 : : field_ok = false;
992 : : }
993 : 2791 : if (!is_anon_substructure)
994 : 2725 : obstack_grow (ob, "; ", 2);
995 : 2791 : if (!field_ok)
996 : 8 : ret = false;
997 : : }
998 : : }
999 : : /* Padding. */
1000 : 2163 : *p_art_i = go_append_padding (ob, prev_field_end,
1001 : 721 : TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type)),
1002 : : 1, *p_art_i, &prev_field_end);
1003 : : /* Alignment. */
1004 : 721 : if (!is_anon_record_or_union
1005 : 721 : && known_alignment < TYPE_ALIGN_UNIT (type))
1006 : : {
1007 : 59 : const char *s;
1008 : 59 : char buf[100];
1009 : :
1010 : : /* Enforce proper record alignment. */
1011 : 59 : s = go_get_uinttype_for_precision
1012 : 59 : (TYPE_ALIGN (type), TYPE_UNSIGNED (type));
1013 : 59 : if (s == NULL)
1014 : : {
1015 : 0 : snprintf (buf, sizeof buf, "INVALID-int-%u%s",
1016 : 0 : TYPE_ALIGN (type), TYPE_UNSIGNED (type) ? "u" : "");
1017 : 0 : s = buf;
1018 : 0 : ret = false;
1019 : : }
1020 : 59 : *p_art_i = go_force_record_alignment (ob, s, *p_art_i, buf);
1021 : : }
1022 : 721 : if (!is_anon_record_or_union)
1023 : 655 : obstack_1grow (ob, '}');
1024 : : }
1025 : 721 : break;
1026 : :
1027 : 1952 : case FUNCTION_TYPE:
1028 : 1952 : {
1029 : 1952 : tree arg_type;
1030 : 1952 : bool is_varargs;
1031 : 1952 : tree result;
1032 : 1952 : function_args_iterator iter;
1033 : 1952 : bool seen_arg;
1034 : :
1035 : : /* Go has no way to write a type which is a function but not a
1036 : : pointer to a function. */
1037 : 1952 : if (!is_func_ok)
1038 : : {
1039 : 8 : obstack_grow (ob, "func*", 5);
1040 : 8 : ret = false;
1041 : : }
1042 : :
1043 : 1952 : obstack_1grow (ob, '(');
1044 : 1952 : is_varargs = stdarg_p (type);
1045 : 1952 : seen_arg = false;
1046 : 6411 : FOREACH_FUNCTION_ARGS (type, arg_type, iter)
1047 : : {
1048 : 6349 : if (VOID_TYPE_P (arg_type))
1049 : : break;
1050 : 4459 : if (seen_arg)
1051 : 2670 : obstack_grow (ob, ", ", 2);
1052 : 4459 : if (!go_format_type (container, arg_type, true, false, NULL, false))
1053 : 34 : ret = false;
1054 : 4459 : seen_arg = true;
1055 : : }
1056 : 1952 : if (is_varargs)
1057 : : {
1058 : 62 : if (prototype_p (type))
1059 : 62 : obstack_grow (ob, ", ", 2);
1060 : 62 : obstack_grow (ob, "...interface{}", 14);
1061 : : }
1062 : 1952 : obstack_1grow (ob, ')');
1063 : :
1064 : 1952 : result = TREE_TYPE (type);
1065 : 1952 : if (!VOID_TYPE_P (result))
1066 : : {
1067 : 1780 : obstack_1grow (ob, ' ');
1068 : 1780 : if (!go_format_type (container, result, use_type_name, false, NULL,
1069 : : false))
1070 : 1952 : ret = false;
1071 : : }
1072 : : }
1073 : 1952 : break;
1074 : :
1075 : 2 : default:
1076 : 2 : obstack_grow (ob, "INVALID-type", 12);
1077 : 2 : ret = false;
1078 : 2 : 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 : :
1087 : : static void
1088 : 3367 : go_output_type (class godump_container *container)
1089 : : {
1090 : 3367 : struct obstack *ob;
1091 : :
1092 : 3367 : ob = &container->type_obstack;
1093 : 3367 : obstack_1grow (ob, '\0');
1094 : 3367 : fputs ((char *) obstack_base (ob), go_dump_file);
1095 : 3367 : obstack_free (ob, obstack_base (ob));
1096 : 3367 : }
1097 : :
1098 : : /* Output a function declaration. */
1099 : :
1100 : : static void
1101 : 1876 : go_output_fndecl (class godump_container *container, tree decl)
1102 : : {
1103 : 1876 : if (!go_format_type (container, TREE_TYPE (decl), true, true, NULL, false))
1104 : 46 : fprintf (go_dump_file, "// ");
1105 : 3752 : fprintf (go_dump_file, "func _%s ",
1106 : 1876 : IDENTIFIER_POINTER (DECL_NAME (decl)));
1107 : 1876 : go_output_type (container);
1108 : 3752 : fprintf (go_dump_file, " __asm__(\"%s\")\n",
1109 : 1876 : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
1110 : 1876 : }
1111 : :
1112 : : /* Output a typedef or something like a struct definition. */
1113 : :
1114 : : static void
1115 : 1505 : go_output_typedef (class godump_container *container, tree decl)
1116 : : {
1117 : : /* If we have an enum type, output the enum constants
1118 : : separately. */
1119 : 1505 : if (TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE
1120 : 298 : && TYPE_SIZE (TREE_TYPE (decl)) != 0
1121 : 1803 : && !container->decls_seen.contains
1122 : 298 : (TYPE_MAIN_VARIANT (TREE_TYPE (decl))))
1123 : : {
1124 : 281 : tree element;
1125 : :
1126 : 281 : for (element = TYPE_VALUES (TREE_TYPE (decl));
1127 : 3663 : element != NULL_TREE;
1128 : 3382 : element = TREE_CHAIN (element))
1129 : : {
1130 : 3382 : const char *name;
1131 : 3382 : struct macro_hash_value *mhval;
1132 : 3382 : void **slot;
1133 : 3382 : char buf[WIDE_INT_PRINT_BUFFER_SIZE];
1134 : 3382 : tree value = DECL_INITIAL (TREE_VALUE (element));
1135 : :
1136 : 3382 : name = IDENTIFIER_POINTER (TREE_PURPOSE (element));
1137 : :
1138 : : /* Sometimes a name will be defined as both an enum constant
1139 : : and a macro. Avoid duplicate definition errors by
1140 : : treating enum constants as macros. */
1141 : 3382 : mhval = XNEW (struct macro_hash_value);
1142 : 3382 : mhval->name = xstrdup (name);
1143 : 3382 : mhval->value = NULL;
1144 : 3382 : slot = htab_find_slot (macro_hash, mhval, INSERT);
1145 : 3382 : if (*slot != NULL)
1146 : 131 : macro_hash_del (*slot);
1147 : :
1148 : 3382 : if (tree_fits_shwi_p (value))
1149 : 3382 : snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_DEC,
1150 : : tree_to_shwi (value));
1151 : 0 : else if (tree_fits_uhwi_p (value))
1152 : 0 : snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
1153 : : tree_to_uhwi (value));
1154 : : else
1155 : : {
1156 : 0 : wide_int w = wi::to_wide (element);
1157 : 0 : gcc_assert (w.get_len () <= WIDE_INT_MAX_INL_ELTS);
1158 : 0 : print_hex (w, buf);
1159 : 0 : }
1160 : :
1161 : 3382 : mhval->value = xstrdup (buf);
1162 : 3382 : *slot = mhval;
1163 : : }
1164 : 281 : container->decls_seen.add (TYPE_MAIN_VARIANT (TREE_TYPE (decl)));
1165 : : }
1166 : :
1167 : 1505 : if (DECL_NAME (decl) != NULL_TREE)
1168 : : {
1169 : 773 : void **slot;
1170 : 773 : const char *type;
1171 : 773 : tree original_type;
1172 : :
1173 : 773 : type = IDENTIFIER_POINTER (DECL_NAME (decl));
1174 : 773 : original_type = DECL_ORIGINAL_TYPE (decl);
1175 : 773 : if (original_type == NULL_TREE)
1176 : 0 : original_type = TREE_TYPE (decl);
1177 : :
1178 : : /* Suppress typedefs where the type name matches the underlying
1179 : : struct/union/enum tag. This way we'll emit the struct definition
1180 : : instead of an invalid recursive type. */
1181 : 773 : if (TYPE_IDENTIFIER (original_type) != NULL
1182 : 1389 : && IDENTIFIER_POINTER (TYPE_IDENTIFIER (original_type)) == type)
1183 : : return;
1184 : :
1185 : : /* If type defined already, skip. */
1186 : 761 : slot = htab_find_slot (container->type_hash, type, INSERT);
1187 : 761 : if (*slot != NULL)
1188 : : return;
1189 : 761 : *slot = CONST_CAST (void *, (const void *) type);
1190 : :
1191 : 761 : if (!go_format_type (container, original_type, true, false,
1192 : : NULL, false))
1193 : : {
1194 : 21 : fprintf (go_dump_file, "// ");
1195 : 21 : slot = htab_find_slot (container->invalid_hash, type, INSERT);
1196 : 21 : *slot = CONST_CAST (void *, (const void *) type);
1197 : : }
1198 : 1522 : fprintf (go_dump_file, "type _%s ",
1199 : 761 : IDENTIFIER_POINTER (DECL_NAME (decl)));
1200 : 761 : go_output_type (container);
1201 : :
1202 : 761 : if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1203 : : {
1204 : 154 : HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
1205 : :
1206 : 154 : if (size > 0)
1207 : 296 : fprintf (go_dump_file,
1208 : : "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1209 : 148 : IDENTIFIER_POINTER (DECL_NAME (decl)),
1210 : : size);
1211 : : }
1212 : :
1213 : 761 : container->decls_seen.add (decl);
1214 : : }
1215 : 1021 : else if ((RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl))
1216 : 281 : || TREE_CODE (TREE_TYPE (decl)) == ENUMERAL_TYPE)
1217 : 1021 : && TYPE_NAME (TREE_TYPE (decl)) != NULL)
1218 : : {
1219 : 525 : void **slot;
1220 : 525 : const char *type;
1221 : 525 : HOST_WIDE_INT size;
1222 : :
1223 : 525 : type = IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE ((decl))));
1224 : : /* If type defined already, skip. */
1225 : 525 : slot = htab_find_slot (container->type_hash, type, INSERT);
1226 : 525 : if (*slot != NULL)
1227 : : return;
1228 : 525 : *slot = CONST_CAST (void *, (const void *) type);
1229 : :
1230 : 525 : if (!go_format_type (container, TREE_TYPE (decl), false, false, NULL,
1231 : : false))
1232 : : {
1233 : 2 : fprintf (go_dump_file, "// ");
1234 : 2 : slot = htab_find_slot (container->invalid_hash, type, INSERT);
1235 : 2 : *slot = CONST_CAST (void *, (const void *) type);
1236 : : }
1237 : 1050 : fprintf (go_dump_file, "type _%s ",
1238 : 525 : IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))));
1239 : 525 : go_output_type (container);
1240 : :
1241 : 525 : size = int_size_in_bytes (TREE_TYPE (decl));
1242 : 525 : if (size > 0)
1243 : 1040 : fprintf (go_dump_file,
1244 : : "\nconst _sizeof_%s = " HOST_WIDE_INT_PRINT_DEC,
1245 : 520 : IDENTIFIER_POINTER (TYPE_NAME (TREE_TYPE (decl))),
1246 : : size);
1247 : : }
1248 : : else
1249 : : return;
1250 : :
1251 : 1286 : fprintf (go_dump_file, "\n");
1252 : : }
1253 : :
1254 : : /* Output a variable. */
1255 : :
1256 : : static void
1257 : 339 : go_output_var (class godump_container *container, tree decl)
1258 : : {
1259 : 339 : bool is_valid;
1260 : 339 : tree type_name;
1261 : 339 : tree id;
1262 : :
1263 : 339 : if (container->decls_seen.contains (decl)
1264 : 339 : || container->decls_seen.contains (DECL_NAME (decl)))
1265 : 134 : return;
1266 : 205 : container->decls_seen.add (decl);
1267 : 205 : container->decls_seen.add (DECL_NAME (decl));
1268 : :
1269 : 205 : type_name = TYPE_NAME (TREE_TYPE (decl));
1270 : 205 : id = NULL_TREE;
1271 : 205 : if (type_name != NULL_TREE && TREE_CODE (type_name) == IDENTIFIER_NODE)
1272 : : id = type_name;
1273 : 118 : else if (type_name != NULL_TREE && TREE_CODE (type_name) == TYPE_DECL
1274 : 118 : && DECL_SOURCE_LOCATION (type_name) != BUILTINS_LOCATION
1275 : 118 : && DECL_NAME (type_name))
1276 : 118 : id = DECL_NAME (type_name);
1277 : 118 : if (id != NULL_TREE
1278 : 241 : && (!htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1279 : : NO_INSERT)
1280 : 82 : || htab_find_slot (container->invalid_hash, IDENTIFIER_POINTER (id),
1281 : : NO_INSERT)))
1282 : : id = NULL_TREE;
1283 : 161 : if (id != NULL_TREE)
1284 : : {
1285 : 79 : struct obstack *ob;
1286 : :
1287 : 79 : ob = &container->type_obstack;
1288 : 79 : obstack_1grow (ob, '_');
1289 : 79 : go_append_string (ob, id);
1290 : 79 : is_valid = htab_find_slot (container->type_hash, IDENTIFIER_POINTER (id),
1291 : : NO_INSERT) != NULL;
1292 : : }
1293 : : else
1294 : 126 : is_valid = go_format_type (container, TREE_TYPE (decl), true, false, NULL,
1295 : : false);
1296 : 205 : if (is_valid
1297 : 403 : && htab_find_slot (container->type_hash,
1298 : 198 : IDENTIFIER_POINTER (DECL_NAME (decl)),
1299 : : NO_INSERT) != NULL)
1300 : : {
1301 : : /* There is already a type with this name, probably from a
1302 : : struct tag. Prefer the type to the variable. */
1303 : : is_valid = false;
1304 : : }
1305 : 203 : if (!is_valid)
1306 : 9 : fprintf (go_dump_file, "// ");
1307 : :
1308 : 410 : fprintf (go_dump_file, "var _%s ",
1309 : 205 : IDENTIFIER_POINTER (DECL_NAME (decl)));
1310 : 205 : go_output_type (container);
1311 : 205 : fprintf (go_dump_file, "\n");
1312 : :
1313 : : /* Sometimes an extern variable is declared with an unknown struct
1314 : : type. */
1315 : 205 : if (type_name != NULL_TREE && RECORD_OR_UNION_TYPE_P (TREE_TYPE (decl)))
1316 : : {
1317 : 37 : if (TREE_CODE (type_name) == IDENTIFIER_NODE)
1318 : 5 : container->pot_dummy_types.add (IDENTIFIER_POINTER (type_name));
1319 : 32 : else if (TREE_CODE (type_name) == TYPE_DECL)
1320 : 32 : container->pot_dummy_types.add
1321 : 32 : (IDENTIFIER_POINTER (DECL_NAME (type_name)));
1322 : : }
1323 : : }
1324 : :
1325 : : /* Output the final value of a preprocessor macro or enum constant.
1326 : : This is called via htab_traverse_noresize. */
1327 : :
1328 : : static int
1329 : 13343 : go_print_macro (void **slot, void *arg ATTRIBUTE_UNUSED)
1330 : : {
1331 : 13343 : struct macro_hash_value *mhval = (struct macro_hash_value *) *slot;
1332 : 13343 : fprintf (go_dump_file, "const _%s = %s\n", mhval->name, mhval->value);
1333 : 13343 : return 1;
1334 : : }
1335 : :
1336 : : /* Build a hash table with the Go keywords. */
1337 : :
1338 : : static const char * const keywords[] = {
1339 : : "__asm__", "break", "case", "chan", "const", "continue", "default",
1340 : : "defer", "else", "fallthrough", "for", "func", "go", "goto", "if",
1341 : : "import", "interface", "map", "package", "range", "return", "select",
1342 : : "struct", "switch", "type", "var"
1343 : : };
1344 : :
1345 : : static void
1346 : 4 : keyword_hash_init (class godump_container *container)
1347 : : {
1348 : 4 : size_t i;
1349 : 4 : size_t count = ARRAY_SIZE (keywords);
1350 : 4 : void **slot;
1351 : :
1352 : 108 : for (i = 0; i < count; i++)
1353 : : {
1354 : 104 : slot = htab_find_slot (container->keyword_hash, keywords[i], INSERT);
1355 : 104 : *slot = CONST_CAST (void *, (const void *) keywords[i]);
1356 : : }
1357 : 4 : }
1358 : :
1359 : : /* Traversing the pot_dummy_types and seeing which types are present
1360 : : in the global types hash table and creating dummy definitions if
1361 : : not found. This function is invoked by hash_set::traverse. */
1362 : :
1363 : : bool
1364 : 223 : find_dummy_types (const char *const &ptr, godump_container *adata)
1365 : : {
1366 : 223 : class godump_container *data = (class godump_container *) adata;
1367 : 223 : const char *type = (const char *) ptr;
1368 : 223 : void **slot;
1369 : 223 : void **islot;
1370 : :
1371 : 223 : slot = htab_find_slot (data->type_hash, type, NO_INSERT);
1372 : 223 : islot = htab_find_slot (data->invalid_hash, type, NO_INSERT);
1373 : 223 : if (slot == NULL || islot != NULL)
1374 : 21 : fprintf (go_dump_file, "type _%s struct {}\n", type);
1375 : 223 : return true;
1376 : : }
1377 : :
1378 : : /* Output symbols. */
1379 : :
1380 : : static void
1381 : 4 : go_finish (const char *filename)
1382 : : {
1383 : 4 : class godump_container container;
1384 : 4 : unsigned int ix;
1385 : 4 : tree decl;
1386 : :
1387 : 4 : real_debug_hooks->finish (filename);
1388 : :
1389 : 4 : container.type_hash = htab_create (100, htab_hash_string,
1390 : : htab_eq_string, NULL);
1391 : 4 : container.invalid_hash = htab_create (10, htab_hash_string,
1392 : : htab_eq_string, NULL);
1393 : 4 : container.keyword_hash = htab_create (50, htab_hash_string,
1394 : : htab_eq_string, NULL);
1395 : 4 : obstack_init (&container.type_obstack);
1396 : :
1397 : 4 : keyword_hash_init (&container);
1398 : :
1399 : 3728 : FOR_EACH_VEC_SAFE_ELT (queue, ix, decl)
1400 : : {
1401 : 3720 : switch (TREE_CODE (decl))
1402 : : {
1403 : 1876 : case FUNCTION_DECL:
1404 : 1876 : go_output_fndecl (&container, decl);
1405 : 1876 : break;
1406 : :
1407 : 1505 : case TYPE_DECL:
1408 : 1505 : go_output_typedef (&container, decl);
1409 : 1505 : break;
1410 : :
1411 : 339 : case VAR_DECL:
1412 : 339 : go_output_var (&container, decl);
1413 : 339 : break;
1414 : :
1415 : 0 : default:
1416 : 0 : gcc_unreachable ();
1417 : : }
1418 : : }
1419 : :
1420 : 4 : htab_traverse_noresize (macro_hash, go_print_macro, NULL);
1421 : :
1422 : : /* To emit dummy definitions. */
1423 : 4 : container.pot_dummy_types.traverse<godump_container *, find_dummy_types>
1424 : 227 : (&container);
1425 : :
1426 : 4 : htab_delete (container.type_hash);
1427 : 4 : htab_delete (container.invalid_hash);
1428 : 4 : htab_delete (container.keyword_hash);
1429 : 4 : obstack_free (&container.type_obstack, NULL);
1430 : :
1431 : 4 : vec_free (queue);
1432 : :
1433 : 4 : if (fclose (go_dump_file) != 0)
1434 : 0 : error ("could not close Go dump file: %m");
1435 : 4 : go_dump_file = NULL;
1436 : 4 : }
1437 : :
1438 : : /* Set up our hooks. */
1439 : :
1440 : : const struct gcc_debug_hooks *
1441 : 4 : dump_go_spec_init (const char *filename, const struct gcc_debug_hooks *hooks)
1442 : : {
1443 : 4 : go_dump_file = fopen (filename, "w");
1444 : 4 : if (go_dump_file == NULL)
1445 : : {
1446 : 0 : error ("could not open Go dump file %qs: %m", filename);
1447 : 0 : return hooks;
1448 : : }
1449 : :
1450 : 4 : go_debug_hooks = *hooks;
1451 : 4 : real_debug_hooks = hooks;
1452 : :
1453 : 4 : go_debug_hooks.finish = go_finish;
1454 : 4 : go_debug_hooks.define = go_define;
1455 : 4 : go_debug_hooks.undef = go_undef;
1456 : 4 : go_debug_hooks.function_decl = go_function_decl;
1457 : 4 : go_debug_hooks.early_global_decl = go_early_global_decl;
1458 : 4 : go_debug_hooks.late_global_decl = go_late_global_decl;
1459 : 4 : go_debug_hooks.type_decl = go_type_decl;
1460 : :
1461 : 4 : macro_hash = htab_create (100, macro_hash_hashval, macro_hash_eq,
1462 : : macro_hash_del);
1463 : :
1464 : 4 : return &go_debug_hooks;
1465 : : }
1466 : :
1467 : : #include "gt-godump.h"
|