Mercurial > hg > CbC > CbC_gcc
diff gcc/gengtype.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/gengtype.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/gengtype.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,6 +1,5 @@ /* Process source files and output type information. - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 - Free Software Foundation, Inc. + Copyright (C) 2002-2017 Free Software Foundation, Inc. This file is part of GCC. @@ -18,16 +17,20 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ +#ifdef HOST_GENERATOR_FILE +#include "config.h" +#define GENERATOR_FILE 1 +#else #include "bconfig.h" +#endif #include "system.h" #include "errors.h" /* for fatal */ #include "getopt.h" -#include "double-int.h" #include "version.h" /* for version_string & pkgversion_string. */ -#include "hashtab.h" #include "xregex.h" #include "obstack.h" #include "gengtype.h" +#include "filenames.h" /* Data types, macros, etc. used only in this file. */ @@ -84,6 +87,10 @@ static int get_prefix_langdir_index (const char *); static const char *get_file_langdir (const input_file *); + +static void dump_pair (int indent, pair_p p); +static void dump_type (int indent, type_p p); +static void dump_type_list (int indent, type_p p); /* Nonzero iff an error has occurred. */ @@ -111,22 +118,23 @@ va_end (ap); } - -/* asprintf, but produces fatal message on out-of-memory. */ -char * -xasprintf (const char *format, ...) + +/* Locate the ultimate base class of struct S. */ + +static const_type_p +get_ultimate_base_class (const_type_p s) { - int n; - char *result; - va_list ap; - - va_start (ap, format); - n = vasprintf (&result, format, ap); - if (result == NULL || n < 0) - fatal ("out of memory"); - va_end (ap); - - return result; + while (s->u.s.base_class) + s = s->u.s.base_class; + return s; +} + +static type_p +get_ultimate_base_class (type_p s) +{ + while (s->u.s.base_class) + s = s->u.s.base_class; + return s; } /* Input file handling. */ @@ -150,23 +158,24 @@ BASE_FILES entry for each language. */ static outf_p *base_files; - - -#if ENABLE_CHECKING /* Utility debugging function, printing the various type counts within - a list of types. Called thru the DBGPRINT_COUNT_TYPE macro. */ + a list of types. Called through the DBGPRINT_COUNT_TYPE macro. */ void dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t) { int nb_types = 0, nb_scalar = 0, nb_string = 0; int nb_struct = 0, nb_union = 0, nb_array = 0, nb_pointer = 0; - int nb_lang_struct = 0, nb_param_struct = 0; + int nb_lang_struct = 0; + int nb_user_struct = 0, nb_undefined = 0; type_p p = NULL; for (p = t; p; p = p->next) { nb_types++; switch (p->kind) { + case TYPE_UNDEFINED: + nb_undefined++; + break; case TYPE_SCALAR: nb_scalar++; break; @@ -176,6 +185,9 @@ case TYPE_STRUCT: nb_struct++; break; + case TYPE_USER_STRUCT: + nb_user_struct++; + break; case TYPE_UNION: nb_union++; break; @@ -188,10 +200,7 @@ case TYPE_LANG_STRUCT: nb_lang_struct++; break; - case TYPE_PARAM_STRUCT: - nb_param_struct++; - break; - default: + case TYPE_NONE: gcc_unreachable (); } } @@ -203,12 +212,14 @@ fprintf (stderr, "@@%%@@ %d structs, %d unions\n", nb_struct, nb_union); if (nb_pointer > 0 || nb_array > 0) fprintf (stderr, "@@%%@@ %d pointers, %d arrays\n", nb_pointer, nb_array); - if (nb_lang_struct > 0 || nb_param_struct > 0) - fprintf (stderr, "@@%%@@ %d lang_structs, %d param_structs\n", - nb_lang_struct, nb_param_struct); + if (nb_lang_struct > 0) + fprintf (stderr, "@@%%@@ %d lang_structs\n", nb_lang_struct); + if (nb_user_struct > 0) + fprintf (stderr, "@@%%@@ %d user_structs\n", nb_user_struct); + if (nb_undefined > 0) + fprintf (stderr, "@@%%@@ %d undefined types\n", nb_undefined); fprintf (stderr, "\n"); } -#endif /* ENABLE_CHECKING */ /* Scan the input file, LIST, and determine how much space we need to store strings in. Also, count the number of language directories @@ -429,6 +440,12 @@ lang_bitmap bitmap = get_lang_bitmap (gt_files[f]); const char *basename = get_file_basename (gt_files[f]); const char *slashpos = strchr (basename, '/'); +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + const char *slashpos2 = strchr (basename, '\\'); + + if (!slashpos || (slashpos2 && slashpos2 < slashpos)) + slashpos = slashpos2; +#endif if (slashpos) { @@ -475,12 +492,10 @@ /* Lists of various things. */ -pair_p typedefs; -type_p structures; -type_p param_structs; -pair_p variables; - -static type_p find_param_structure (type_p t, type_p param[NUM_PARAM]); +pair_p typedefs = NULL; +type_p structures = NULL; +pair_p variables = NULL; + static type_p adjust_field_tree_exp (type_p t, options_p opt); static type_p adjust_field_rtx_def (type_p t, options_p opt); @@ -501,7 +516,7 @@ for (p = typedefs; p != NULL; p = p->next) if (strcmp (p->name, s) == 0) { - if (p->type != t) + if (p->type != t && strcmp (s, "result_type") != 0) { error_at_line (pos, "type `%s' previously defined", s); error_at_line (&p->line, "previously defined here"); @@ -528,31 +543,212 @@ do_typedef (s, &scalar_nonchar, pos); } +/* Similar to strtok_r. */ + +static char * +strtoken (char *str, const char *delim, char **next) +{ + char *p; + + if (str == NULL) + str = *next; + + /* Skip the leading delimiters. */ + str += strspn (str, delim); + if (*str == '\0') + /* This is an empty token. */ + return NULL; + + /* The current token. */ + p = str; + + /* Find the next delimiter. */ + str += strcspn (str, delim); + if (*str == '\0') + /* This is the last token. */ + *next = str; + else + { + /* Terminate the current token. */ + *str = '\0'; + /* Advance to the next token. */ + *next = str + 1; + } + + return p; +} + +/* Define TYPE_NAME to be a user defined type at location POS. */ + +type_p +create_user_defined_type (const char *type_name, struct fileloc *pos) +{ + type_p ty = find_structure (type_name, TYPE_USER_STRUCT); + + /* We might have already seen an incomplete decl of the given type, + in which case we won't have yet seen a GTY((user)), and the type will + only have kind "TYPE_STRUCT". Mark it as a user struct. */ + ty->kind = TYPE_USER_STRUCT; + + ty->u.s.line = *pos; + ty->u.s.bitmap = get_lang_bitmap (pos->file); + do_typedef (type_name, ty, pos); + + /* If TYPE_NAME specifies a template, create references to the types + in the template by pretending that each type is a field of TY. + This is needed to make sure that the types referenced by the + template are marked as used. */ + char *str = xstrdup (type_name); + char *open_bracket = strchr (str, '<'); + if (open_bracket) + { + /* We only accept simple template declarations (see + require_template_declaration), so we only need to parse a + comma-separated list of strings, implicitly assumed to + be type names, potentially with "*" characters. */ + char *arg = open_bracket + 1; + /* Workaround -Wmaybe-uninitialized false positive during + profiledbootstrap by initializing it. */ + char *next = NULL; + char *type_id = strtoken (arg, ",>", &next); + pair_p fields = 0; + while (type_id) + { + /* Create a new field for every type found inside the template + parameter list. */ + + /* Support a single trailing "*" character. */ + const char *star = strchr (type_id, '*'); + int is_ptr = (star != NULL); + size_t offset_to_star = star - type_id; + if (is_ptr) + offset_to_star = star - type_id; + + if (strstr (type_id, "char*")) + { + type_id = strtoken (0, ",>", &next); + continue; + } + + char *field_name = xstrdup (type_id); + + type_p arg_type; + if (is_ptr) + { + /* Strip off the first '*' character (and any subsequent text). */ + *(field_name + offset_to_star) = '\0'; + + arg_type = find_structure (field_name, TYPE_STRUCT); + arg_type = create_pointer (arg_type); + } + else + arg_type = resolve_typedef (field_name, pos); + + fields = create_field_at (fields, arg_type, field_name, 0, pos); + type_id = strtoken (0, ",>", &next); + } + + /* Associate the field list to TY. */ + ty->u.s.fields = fields; + } + free (str); + + return ty; +} + + +/* Given a typedef name S, return its associated type. Return NULL if + S is not a registered type name. */ + +static type_p +type_for_name (const char *s) +{ + pair_p p; + + /* Special-case support for types within a "gcc::" namespace. Rather + than fully-supporting namespaces, simply strip off the "gcc::" prefix + where present. This allows us to have GTY roots of this form: + extern GTY(()) gcc::some_type *some_ptr; + where the autogenerated functions will refer to simply "some_type", + where they can be resolved into their namespace. */ + if (0 == strncmp (s, "gcc::", 5)) + s += 5; + + for (p = typedefs; p != NULL; p = p->next) + if (strcmp (p->name, s) == 0) + return p->type; + return NULL; +} + + +/* Create an undefined type with name S and location POS. Return the + newly created type. */ + +static type_p +create_undefined_type (const char *s, struct fileloc *pos) +{ + type_p ty = find_structure (s, TYPE_UNDEFINED); + ty->u.s.line = *pos; + ty->u.s.bitmap = get_lang_bitmap (pos->file); + do_typedef (s, ty, pos); + return ty; +} + + /* Return the type previously defined for S. Use POS to report errors. */ type_p resolve_typedef (const char *s, struct fileloc *pos) { - pair_p p; - for (p = typedefs; p != NULL; p = p->next) - if (strcmp (p->name, s) == 0) - return p->type; - error_at_line (pos, "unidentified type `%s'", s); - return &scalar_nonchar; /* treat as "int" */ + bool is_template_instance = (strchr (s, '<') != NULL); + type_p p = type_for_name (s); + + /* If we did not find a typedef registered, generate a TYPE_UNDEFINED + type for regular type identifiers. If the type identifier S is a + template instantiation, however, we treat it as a user defined + type. + + FIXME, this is actually a limitation in gengtype. Supporting + template types and their instances would require keeping separate + track of the basic types definition and its instances. This + essentially forces all template classes in GC to be marked + GTY((user)). */ + if (!p) + p = (is_template_instance) + ? create_user_defined_type (s, pos) + : create_undefined_type (s, pos); + + return p; } -/* Create and return a new structure with tag NAME (or a union iff - ISUNION is nonzero), at POS with fields FIELDS and options O. */ +/* Add SUBCLASS to head of linked list of BASE's subclasses. */ + +void add_subclass (type_p base, type_p subclass) +{ + gcc_assert (union_or_struct_p (base)); + gcc_assert (union_or_struct_p (subclass)); + + subclass->u.s.next_sibling_class = base->u.s.first_subclass; + base->u.s.first_subclass = subclass; +} + +/* Create and return a new structure with tag NAME at POS with fields + FIELDS and options O. The KIND of structure must be one of + TYPE_STRUCT, TYPE_UNION or TYPE_USER_STRUCT. */ type_p -new_structure (const char *name, int isunion, struct fileloc *pos, - pair_p fields, options_p o) +new_structure (const char *name, enum typekind kind, struct fileloc *pos, + pair_p fields, options_p o, type_p base_class) { type_p si; type_p s = NULL; lang_bitmap bitmap = get_lang_bitmap (pos->file); - - for (si = structures; si != NULL; si = si->next) + bool isunion = (kind == TYPE_UNION); + type_p *p = &structures; + + gcc_assert (union_or_struct_p (kind)); + + for (si = structures; si != NULL; p = &si->next, si = *p) if (strcmp (name, si->u.s.tag) == 0 && UNION_P (si) == isunion) { type_p ls = NULL; @@ -598,19 +794,17 @@ type_count++; s = XCNEW (struct type); s->state_number = -type_count; - s->next = structures; - structures = s; + *p = s; } - if (s->u.s.line.file != NULL - || (s->u.s.lang_struct && (s->u.s.lang_struct->u.s.bitmap & bitmap))) + if (s->u.s.lang_struct && (s->u.s.lang_struct->u.s.bitmap & bitmap)) { error_at_line (pos, "duplicate definition of '%s %s'", isunion ? "union" : "struct", s->u.s.tag); error_at_line (&s->u.s.line, "previous definition here"); } - s->kind = isunion ? TYPE_UNION : TYPE_STRUCT; + s->kind = kind; s->u.s.tag = name; s->u.s.line = *pos; s->u.s.fields = fields; @@ -618,62 +812,40 @@ s->u.s.bitmap = bitmap; if (s->u.s.lang_struct) s->u.s.lang_struct->u.s.bitmap |= bitmap; + s->u.s.base_class = base_class; + if (base_class) + add_subclass (base_class, s); return s; } -/* Return the previously-defined structure with tag NAME (or a union - iff ISUNION is nonzero), or a new empty structure or union if none - was defined previously. */ +/* Return the previously-defined structure or union with tag NAME, + or a new empty structure or union if none was defined previously. + The KIND of structure must be one of TYPE_STRUCT, TYPE_UNION or + TYPE_USER_STRUCT. */ type_p -find_structure (const char *name, int isunion) +find_structure (const char *name, enum typekind kind) { type_p s; - - for (s = structures; s != NULL; s = s->next) + bool isunion = (kind == TYPE_UNION); + type_p *p = &structures; + + gcc_assert (kind == TYPE_UNDEFINED || union_or_struct_p (kind)); + + for (s = structures; s != NULL; p = &s->next, s = *p) if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion) return s; type_count++; s = XCNEW (struct type); - s->next = structures; s->state_number = -type_count; - structures = s; - s->kind = isunion ? TYPE_UNION : TYPE_STRUCT; + s->kind = kind; s->u.s.tag = name; - structures = s; + *p = s; return s; } -/* Return the previously-defined parameterized structure for structure - T and parameters PARAM, or a new parameterized empty structure or - union if none was defined previously. */ - -static type_p -find_param_structure (type_p t, type_p param[NUM_PARAM]) -{ - type_p res; - - for (res = param_structs; res; res = res->next) - if (res->u.param_struct.stru == t - && memcmp (res->u.param_struct.param, param, - sizeof (type_p) * NUM_PARAM) == 0) - break; - if (res == NULL) - { - type_count++; - res = XCNEW (struct type); - res->kind = TYPE_PARAM_STRUCT; - res->next = param_structs; - res->state_number = -type_count; - param_structs = res; - res->u.param_struct.stru = t; - memcpy (res->u.param_struct.param, param, sizeof (type_p) * NUM_PARAM); - } - return res; -} - /* Return a scalar type with name NAME. */ type_p @@ -685,6 +857,7 @@ return &scalar_nonchar; } + /* Return a pointer to T. */ type_p @@ -818,7 +991,7 @@ /* Create a fake field with the given type and name. NEXT is the next field in the chain. */ #define create_field(next,type,name) \ - create_field_all(next,type,name, 0, this_file, __LINE__) + create_field_all (next,type,name, 0, this_file, __LINE__) /* Like create_field, but the field is only valid when condition COND is true. */ @@ -840,8 +1013,8 @@ union_fields->opt = create_string_option (union_fields->opt, "tag", "1"); union_type = - new_structure (xasprintf ("%s_%d", "fake_union", id++), 1, - &lexer_line, union_fields, NULL); + new_structure (xasprintf ("%s_%d", "fake_union", id++), TYPE_UNION, + &lexer_line, union_fields, NULL, NULL); /* Create the field and give it the new fake union type. Add a "desc" tag that specifies the condition under which the field is valid. */ @@ -929,8 +1102,8 @@ int k; rtx_next_new[i] = -1; - if (strncmp (rtx_format[i], "iuu", 3) == 0) - rtx_next_new[i] = 2; + if (strncmp (rtx_format[i], "uu", 2) == 0) + rtx_next_new[i] = 1; else if (i == COND_EXEC || i == SET || i == EXPR_LIST || i == INSN_LIST) rtx_next_new[i] = 1; else @@ -982,16 +1155,16 @@ nodot = create_string_option (NULL, "dot", ""); - rtx_tp = create_pointer (find_structure ("rtx_def", 0)); - rtvec_tp = create_pointer (find_structure ("rtvec_def", 0)); - tree_tp = create_pointer (find_structure ("tree_node", 1)); - mem_attrs_tp = create_pointer (find_structure ("mem_attrs", 0)); + rtx_tp = create_pointer (find_structure ("rtx_def", TYPE_STRUCT)); + rtvec_tp = create_pointer (find_structure ("rtvec_def", TYPE_STRUCT)); + tree_tp = create_pointer (find_structure ("tree_node", TYPE_UNION)); + mem_attrs_tp = create_pointer (find_structure ("mem_attrs", TYPE_STRUCT)); reg_attrs_tp = - create_pointer (find_structure ("reg_attrs", 0)); + create_pointer (find_structure ("reg_attrs", TYPE_STRUCT)); basic_block_tp = - create_pointer (find_structure ("basic_block_def", 0)); + create_pointer (find_structure ("basic_block_def", TYPE_STRUCT)); constant_tp = - create_pointer (find_structure ("constant_descriptor_rtx", 0)); + create_pointer (find_structure ("constant_descriptor_rtx", TYPE_STRUCT)); scalar_tp = &scalar_nonchar; /* rtunion int */ { @@ -1004,6 +1177,7 @@ { case NOTE_INSN_MAX: case NOTE_INSN_DELETED_LABEL: + case NOTE_INSN_DELETED_DEBUG_LABEL: note_flds = create_field (note_flds, &string_type, "rt_str"); break; @@ -1013,6 +1187,7 @@ break; case NOTE_INSN_VAR_LOCATION: + case NOTE_INSN_CALL_ARG_LOCATION: note_flds = create_field (note_flds, rtx_tp, "rt_rtx"); break; @@ -1029,8 +1204,8 @@ note_flds->opt = create_string_option (nodot, "tag", note_insn_name[c]); } - note_union_tp = new_structure ("rtx_def_note_subunion", 1, - &lexer_line, note_flds, NULL); + note_union_tp = new_structure ("rtx_def_note_subunion", TYPE_UNION, + &lexer_line, note_flds, NULL, NULL); } /* Create a type to represent the various forms of SYMBOL_REF_DATA. */ { @@ -1039,8 +1214,8 @@ sym_flds->opt = create_string_option (nodot, "default", ""); sym_flds = create_field (sym_flds, constant_tp, "rt_constant"); sym_flds->opt = create_string_option (nodot, "tag", "1"); - symbol_union_tp = new_structure ("rtx_def_symbol_subunion", 1, - &lexer_line, sym_flds, NULL); + symbol_union_tp = new_structure ("rtx_def_symbol_subunion", TYPE_UNION, + &lexer_line, sym_flds, NULL, NULL); } for (i = 0; i < NUM_RTX_CODE; i++) { @@ -1061,6 +1236,7 @@ case 'i': case 'n': case 'w': + case 'r': t = scalar_tp; subname = "rt_int"; break; @@ -1068,19 +1244,19 @@ case '0': if (i == MEM && aindex == 1) t = mem_attrs_tp, subname = "rt_mem"; - else if (i == JUMP_INSN && aindex == 8) + else if (i == JUMP_INSN && aindex == 7) t = rtx_tp, subname = "rt_rtx"; - else if (i == CODE_LABEL && aindex == 5) + else if (i == CODE_LABEL && aindex == 4) t = scalar_tp, subname = "rt_int"; - else if (i == CODE_LABEL && aindex == 4) + else if (i == CODE_LABEL && aindex == 3) t = rtx_tp, subname = "rt_rtx"; else if (i == LABEL_REF && (aindex == 1 || aindex == 2)) t = rtx_tp, subname = "rt_rtx"; - else if (i == NOTE && aindex == 4) + else if (i == NOTE && aindex == 3) t = note_union_tp, subname = ""; - else if (i == NOTE && aindex == 5) + else if (i == NOTE && aindex == 4) t = scalar_tp, subname = "rt_int"; - else if (i == NOTE && aindex >= 7) + else if (i == NOTE && aindex >= 6) t = scalar_tp, subname = "rt_int"; else if (i == ADDR_DIFF_VEC && aindex == 4) t = scalar_tp, subname = "rt_int"; @@ -1088,18 +1264,14 @@ t = scalar_tp, subname = "rt_int"; else if (i == DEBUG_EXPR && aindex == 0) t = tree_tp, subname = "rt_tree"; - else if (i == REG && aindex == 1) - t = scalar_tp, subname = "rt_int"; - else if (i == REG && aindex == 2) - t = reg_attrs_tp, subname = "rt_reg"; - else if (i == SCRATCH && aindex == 0) + else if (i == SYMBOL_REF && aindex == 1) + t = symbol_union_tp, subname = ""; + else if (i == JUMP_TABLE_DATA && aindex >= 4) t = scalar_tp, subname = "rt_int"; - else if (i == SYMBOL_REF && aindex == 1) + else if (i == BARRIER && aindex >= 2) t = scalar_tp, subname = "rt_int"; - else if (i == SYMBOL_REF && aindex == 2) - t = symbol_union_tp, subname = ""; - else if (i == BARRIER && aindex >= 3) - t = scalar_tp, subname = "rt_int"; + else if (i == ENTRY_VALUE && aindex == 0) + t = rtx_tp, subname = "rt_rtx"; else { error_at_line @@ -1166,18 +1338,22 @@ "CONSTANT_POOL_ADDRESS_P (&%0)"); } + if (i == REG) + subfields = create_field (subfields, reg_attrs_tp, "reg.attrs"); + if (i == SYMBOL_REF) { /* Add the "block_sym" field if SYMBOL_REF_HAS_BLOCK_INFO_P holds. */ - type_p field_tp = find_structure ("block_symbol", 0); + type_p field_tp = find_structure ("block_symbol", TYPE_STRUCT); subfields = create_optional_field (subfields, field_tp, "block_sym", "SYMBOL_REF_HAS_BLOCK_INFO_P (&%0)"); } sname = xasprintf ("rtx_def_%s", rtx_name[i]); - substruct = new_structure (sname, 0, &lexer_line, subfields, NULL); + substruct = new_structure (sname, TYPE_STRUCT, &lexer_line, subfields, + NULL, NULL); ftag = xstrdup (rtx_name[i]); for (nmindex = 0; nmindex < strlen (ftag); nmindex++) @@ -1185,7 +1361,8 @@ flds = create_field (flds, substruct, ""); flds->opt = create_string_option (nodot, "tag", ftag); } - return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot); + return new_structure ("rtx_def_subunion", TYPE_UNION, &lexer_line, flds, + nodot, NULL); } /* Handle `special("tree_exp")'. This is a special case for @@ -1214,7 +1391,8 @@ "TREE_OPERAND_LENGTH ((tree) &%0)"); flds->opt = create_string_option (flds->opt, "default", ""); - return new_structure ("tree_exp_subunion", 1, &lexer_line, flds, nodot); + return new_structure ("tree_exp_subunion", TYPE_UNION, &lexer_line, flds, + nodot, NULL); } /* Perform any special processing on a type T, about to become the type @@ -1232,40 +1410,19 @@ { int length_p = 0; const int pointer_p = t->kind == TYPE_POINTER; - type_p params[NUM_PARAM]; - int params_p = 0; - int i; - - for (i = 0; i < NUM_PARAM; i++) - params[i] = NULL; for (; opt; opt = opt->next) if (strcmp (opt->name, "length") == 0) - length_p = 1; - else if ((strcmp (opt->name, "param_is") == 0 - || (strncmp (opt->name, "param", 5) == 0 - && ISDIGIT (opt->name[5]) - && strcmp (opt->name + 6, "_is") == 0)) - && opt->kind == OPTION_TYPE) { - int num = ISDIGIT (opt->name[5]) ? opt->name[5] - '0' : 0; - - if (!UNION_OR_STRUCT_P (t) - && (t->kind != TYPE_POINTER || !UNION_OR_STRUCT_P (t->u.p))) + if (length_p) + error_at_line (&lexer_line, "duplicate `%s' option", opt->name); + if (t->u.p->kind == TYPE_SCALAR || t->u.p->kind == TYPE_STRING) { error_at_line (&lexer_line, - "option `%s' may only be applied to structures or structure pointers", - opt->name); - return t; + "option `%s' may not be applied to " + "arrays of atomic types", opt->name); } - - params_p = 1; - if (params[num] != NULL) - error_at_line (&lexer_line, "duplicate `%s' option", opt->name); - if (!ISDIGIT (opt->name[5])) - params[num] = create_pointer (opt->info.type); - else - params[num] = opt->info.type; + length_p = 1; } else if (strcmp (opt->name, "special") == 0 && opt->kind == OPTION_STRING) @@ -1279,16 +1436,6 @@ error_at_line (&lexer_line, "unknown special `%s'", special_name); } - if (params_p) - { - type_p realt; - - if (pointer_p) - t = t->u.p; - realt = find_param_structure (t, params); - t = pointer_p ? create_pointer (realt) : realt; - } - if (!length_p && pointer_p && t->u.p->kind == TYPE_SCALAR && t->u.p->u.scalar_is_char) return &string_type; @@ -1301,26 +1448,23 @@ } -static void set_gc_used_type (type_p, enum gc_used_enum, type_p *); +static void set_gc_used_type (type_p, enum gc_used_enum, bool = false); static void set_gc_used (pair_p); /* Handle OPT for set_gc_used_type. */ static void process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef, - int *pass_param, int *length, int *skip, - type_p *nested_ptr) + int *length, int *skip, type_p *nested_ptr) { options_p o; for (o = opt; o; o = o->next) if (strcmp (o->name, "ptr_alias") == 0 && level == GC_POINTED_TO && o->kind == OPTION_TYPE) set_gc_used_type (o->info.type, - GC_POINTED_TO, NULL); + GC_POINTED_TO); else if (strcmp (o->name, "maybe_undef") == 0) *maybe_undef = 1; - else if (strcmp (o->name, "use_params") == 0) - *pass_param = 1; else if (strcmp (o->name, "length") == 0) *length = 1; else if (strcmp (o->name, "skip") == 0) @@ -1331,9 +1475,31 @@ } -/* Set the gc_used field of T to LEVEL, and handle the types it references. */ +/* Set the gc_used field of T to LEVEL, and handle the types it references. + + If ALLOWED_UNDEFINED_TYPES is true, types of kind TYPE_UNDEFINED + are set to GC_UNUSED. Otherwise, an error is emitted for + TYPE_UNDEFINED types. This is used to support user-defined + template types with non-type arguments. + + For instance, when we parse a template type with enum arguments + (e.g. MyType<AnotherType, EnumValue>), the parser created two + artificial fields for 'MyType', one for 'AnotherType', the other + one for 'EnumValue'. + + At the time that we parse this type we don't know that 'EnumValue' + is really an enum value, so the parser creates a TYPE_UNDEFINED + type for it. Since 'EnumValue' is never resolved to a known + structure, it will stay with TYPE_UNDEFINED. + + Since 'MyType' is a TYPE_USER_STRUCT, we can simply ignore + 'EnumValue'. Generating marking code for it would cause + compilation failures since the marking routines assumes that + 'EnumValue' is a type. */ + static void -set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM]) +set_gc_used_type (type_p t, enum gc_used_enum level, + bool allow_undefined_types) { if (t->gc_used >= level) return; @@ -1344,69 +1510,67 @@ { case TYPE_STRUCT: case TYPE_UNION: + case TYPE_USER_STRUCT: { pair_p f; int dummy; type_p dummy2; - - process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy, + bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT); + + process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy2); - for (f = t->u.s.fields; f; f = f->next) + if (t->u.s.base_class) + set_gc_used_type (t->u.s.base_class, level, allow_undefined_types); + /* Anything pointing to a base class might actually be pointing + to a subclass. */ + for (type_p subclass = t->u.s.first_subclass; subclass; + subclass = subclass->u.s.next_sibling_class) + set_gc_used_type (subclass, level, allow_undefined_types); + + FOR_ALL_INHERITED_FIELDS(t, f) { int maybe_undef = 0; - int pass_param = 0; int length = 0; int skip = 0; type_p nested_ptr = NULL; - process_gc_options (f->opt, level, &maybe_undef, &pass_param, - &length, &skip, &nested_ptr); + process_gc_options (f->opt, level, &maybe_undef, &length, &skip, + &nested_ptr); if (nested_ptr && f->type->kind == TYPE_POINTER) - set_gc_used_type (nested_ptr, GC_POINTED_TO, - pass_param ? param : NULL); + set_gc_used_type (nested_ptr, GC_POINTED_TO); else if (length && f->type->kind == TYPE_POINTER) - set_gc_used_type (f->type->u.p, GC_USED, NULL); + set_gc_used_type (f->type->u.p, GC_USED); else if (maybe_undef && f->type->kind == TYPE_POINTER) - set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO, NULL); - else if (pass_param && f->type->kind == TYPE_POINTER && param) - set_gc_used_type (find_param_structure (f->type->u.p, param), - GC_POINTED_TO, NULL); + set_gc_used_type (f->type->u.p, GC_MAYBE_POINTED_TO); else if (skip) ; /* target type is not used through this field */ else - set_gc_used_type (f->type, GC_USED, pass_param ? param : NULL); + set_gc_used_type (f->type, GC_USED, allow_undefined_field_types); } break; } + case TYPE_UNDEFINED: + if (level > GC_UNUSED) + { + if (!allow_undefined_types) + error_at_line (&t->u.s.line, "undefined type `%s'", t->u.s.tag); + t->gc_used = GC_UNUSED; + } + break; + case TYPE_POINTER: - set_gc_used_type (t->u.p, GC_POINTED_TO, NULL); + set_gc_used_type (t->u.p, GC_POINTED_TO); break; case TYPE_ARRAY: - set_gc_used_type (t->u.a.p, GC_USED, param); + set_gc_used_type (t->u.a.p, GC_USED); break; case TYPE_LANG_STRUCT: for (t = t->u.s.lang_struct; t; t = t->next) - set_gc_used_type (t, level, param); - break; - - case TYPE_PARAM_STRUCT: - { - int i; - for (i = 0; i < NUM_PARAM; i++) - if (t->u.param_struct.param[i] != 0) - set_gc_used_type (t->u.param_struct.param[i], GC_USED, NULL); - } - if (t->u.param_struct.stru->gc_used == GC_POINTED_TO) - level = GC_POINTED_TO; - else - level = GC_USED; - t->u.param_struct.stru->gc_used = GC_UNUSED; - set_gc_used_type (t->u.param_struct.stru, level, - t->u.param_struct.param); + set_gc_used_type (t, level); break; default: @@ -1423,7 +1587,7 @@ pair_p p; for (p = variables; p; p = p->next) { - set_gc_used_type (p->type, GC_USED, NULL); + set_gc_used_type (p->type, GC_USED); nbvars++; }; if (verbosity_level >= 2) @@ -1443,7 +1607,7 @@ create_file (const char *name, const char *oname) { static const char *const hdr[] = { - " Copyright (C) 2004, 2007, 2009 Free Software Foundation, Inc.\n", + " Copyright (C) 2004-2017 Free Software Foundation, Inc.\n", "\n", "This file is part of GCC.\n", "\n", @@ -1542,14 +1706,21 @@ { /* The order of files here matters very much. */ static const char *const ifiles[] = { - "config.h", "system.h", "coretypes.h", "tm.h", - "hashtab.h", "splay-tree.h", "obstack.h", "bitmap.h", "input.h", - "tree.h", "rtl.h", "function.h", "insn-config.h", "expr.h", - "hard-reg-set.h", "basic-block.h", "cselib.h", "insn-addr.h", - "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h", - "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h", - "cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h", - "target.h", "ipa-prop.h", "lto-streamer.h", "target-globals.h", NULL + "config.h", "system.h", "coretypes.h", + "backend.h", "predict.h", "tree.h", + "rtl.h", "gimple.h", "fold-const.h", "insn-codes.h", "splay-tree.h", + "alias.h", "insn-config.h", "flags.h", "expmed.h", "dojump.h", + "explow.h", "calls.h", "cilk.h", "memmodel.h", "emit-rtl.h", "varasm.h", + "stmt.h", "expr.h", "alloc-pool.h", "cselib.h", "insn-addr.h", + "optabs.h", "libfuncs.h", "debug.h", "internal-fn.h", "gimple-fold.h", + "tree-eh.h", "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.h", + "tree-vrp.h", "tree-phinodes.h", "ssa-iterators.h", "stringpool.h", + "tree-ssanames.h", "tree-ssa-loop.h", "tree-ssa-loop-ivopts.h", + "tree-ssa-loop-manip.h", "tree-ssa-loop-niter.h", "tree-into-ssa.h", + "tree-dfa.h", "tree-ssa.h", "reload.h", "cpp-id-data.h", "tree-chrec.h", + "except.h", "output.h", "cfgloop.h", "target.h", "lto-streamer.h", + "target-globals.h", "ipa-ref.h", "cgraph.h", "symbol-summary.h", + "ipa-prop.h", "ipa-fnsummary.h", "dwarf2out.h", "omp-offload.h", NULL }; const char *const *ifp; outf_p gtype_desc_c; @@ -1561,6 +1732,13 @@ /* Make sure we handle "cfun" specially. */ oprintf (gtype_desc_c, "\n/* See definition in function.h. */\n"); oprintf (gtype_desc_c, "#undef cfun\n"); + + oprintf (gtype_desc_c, + "\n" + "/* Types with a \"gcc::\" namespace have it stripped\n" + " during gengtype parsing. Provide a \"using\" directive\n" + " to ensure that the fully-qualified types are found. */\n" + "using namespace gcc;\n"); } } @@ -1570,10 +1748,7 @@ static const char * get_file_realbasename (const input_file *inpf) { - const char *f = get_input_file_name (inpf); - const char *lastslash = strrchr (f, '/'); - - return (lastslash != NULL) ? lastslash + 1 : f; + return lbasename (get_input_file_name (inpf)); } /* For INPF a filename, return the relative path to INPF from @@ -1758,6 +1933,12 @@ matters, so change with extreme care! */ struct file_rule_st files_rules[] = { + /* The general rule assumes that files in subdirectories belong to a + particular front-end, and files not in subdirectories are shared. + The following rules deal with exceptions - files that are in + subdirectories and yet are shared, and files that are top-level, + but are not shared. */ + /* the c-family/ source directory is special. */ { DIR_PREFIX_REGEX "c-family/([[:alnum:]_-]*)\\.c$", REG_EXTENDED, NULL_REGEX, @@ -1767,12 +1948,12 @@ REG_EXTENDED, NULL_REGEX, "gt-c-family-$3.h", "c-family/$3.h", NULL_FRULACT}, - /* Both c-lang.h & c-tree.h gives gt-c-decl.h for c-decl.c ! */ - { DIR_PREFIX_REGEX "c-lang\\.h$", - REG_EXTENDED, NULL_REGEX, "gt-c-decl.h", "c-decl.c", NULL_FRULACT}, - - { DIR_PREFIX_REGEX "c-tree\\.h$", - REG_EXTENDED, NULL_REGEX, "gt-c-decl.h", "c-decl.c", NULL_FRULACT}, + /* Both c-lang.h & c-tree.h gives gt-c-c-decl.h for c-decl.c ! */ + { DIR_PREFIX_REGEX "c/c-lang\\.h$", + REG_EXTENDED, NULL_REGEX, "gt-c-c-decl.h", "c/c-decl.c", NULL_FRULACT}, + + { DIR_PREFIX_REGEX "c/c-tree\\.h$", + REG_EXTENDED, NULL_REGEX, "gt-c-c-decl.h", "c/c-decl.c", NULL_FRULACT}, /* cp/cp-tree.h gives gt-cp-tree.h for cp/tree.c ! */ { DIR_PREFIX_REGEX "cp/cp-tree\\.h$", @@ -1789,19 +1970,36 @@ REG_EXTENDED, NULL_REGEX, "gt-cp-name-lookup.h", "cp/name-lookup.c", NULL_FRULACT }, - /* objc/objc-act.h fives gt-objc-objc-act.h for objc/objc-act.c ! */ + /* cp/parser.h gives gt-cp-parser.h for cp/parser.c ! */ + { DIR_PREFIX_REGEX "cp/parser\\.h$", + REG_EXTENDED, NULL_REGEX, + "gt-cp-parser.h", "cp/parser.c", NULL_FRULACT }, + + /* objc/objc-act.h gives gt-objc-objc-act.h for objc/objc-act.c ! */ { DIR_PREFIX_REGEX "objc/objc-act\\.h$", REG_EXTENDED, NULL_REGEX, "gt-objc-objc-act.h", "objc/objc-act.c", NULL_FRULACT }, - /* General cases. For header *.h and source *.c files, we need - * special actions to handle the language. */ + /* objc/objc-map.h gives gt-objc-objc-map.h for objc/objc-map.c ! */ + { DIR_PREFIX_REGEX "objc/objc-map\\.h$", + REG_EXTENDED, NULL_REGEX, + "gt-objc-objc-map.h", "objc/objc-map.c", NULL_FRULACT }, + + /* General cases. For header *.h and source *.c or *.cc files, we + * need special actions to handle the language. */ /* Source *.c files are using get_file_gtfilename to compute their output_name and get_file_basename to compute their for_name - thru the source_dot_c_frul action. */ + through the source_dot_c_frul action. */ { DIR_PREFIX_REGEX "([[:alnum:]_-]*)\\.c$", REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.c", source_dot_c_frul}, + + /* Source *.cc files are using get_file_gtfilename to compute their + output_name and get_file_basename to compute their for_name + through the source_dot_c_frul action. */ + { DIR_PREFIX_REGEX "([[:alnum:]_-]*)\\.cc$", + REG_EXTENDED, NULL_REGEX, "gt-$3.h", "$3.cc", source_dot_c_frul}, + /* Common header files get "gtype-desc.c" as their output_name, * while language specific header files are handled specially. So * we need the header_dot_h_frul action. */ @@ -1914,7 +2112,7 @@ else { /* This can happen only when files_rules is buggy! */ - gcc_unreachable(); + gcc_unreachable (); } /* Always skip the character after the dollar. */ pt++; @@ -1925,7 +2123,7 @@ obstack_1grow (&str_obstack, '\0'); rawstr = XOBFINISH (&str_obstack, char *); str = xstrdup (rawstr); - obstack_free (&str_obstack, rawstr); + obstack_free (&str_obstack, NULL); DBGPRINTF ("matched replacement %s", str); rawstr = NULL; return str; @@ -1934,7 +2132,7 @@ /* An output file, suitable for definitions, that can see declarations made in INPF and is linked into every language that uses INPF. - Since the the result is cached inside INPF, that argument cannot be + Since the result is cached inside INPF, that argument cannot be declared constant, but is "almost" constant. */ outf_p @@ -1975,7 +2173,7 @@ /* Try each rule in sequence in files_rules until one is triggered. */ { int rulix = 0; - DBGPRINTF ("passing input file @ %p named %s thru the files_rules", + DBGPRINTF ("passing input file @ %p named %s through the files_rules", (void*) inpf, inpfname); for (; files_rules[rulix].frul_srcexpr != NULL; rulix++) @@ -2059,15 +2257,15 @@ } if (!output_name || !for_name) { - /* This is impossible, and could only happen if the files_rules is - incomplete or buggy. */ - gcc_unreachable (); + /* This should not be possible, and could only happen if the + files_rules is incomplete or buggy. */ + fatal ("failed to compute output name for %s", inpfname); } /* Look through to see if we've ever seen this output filename before. If found, cache the result in inpf. */ for (r = output_files; r; r = r->next) - if (strcmp (r->name, output_name) == 0) + if (filename_cmp (r->name, output_name) == 0) { inpf->inpoutf = r; DBGPRINTF ("found r @ %p for output_name %s for_name %s", (void*)r, @@ -2122,6 +2320,8 @@ break; } } + if (equal && EOF != fgetc (newfile)) + equal = false; fclose (newfile); return equal; } @@ -2137,7 +2337,6 @@ for (of = output_files; of; of = of->next) { - if (!is_file_equal (of)) { FILE *newfile = NULL; @@ -2209,35 +2408,32 @@ const char *marker_routine; const char *reorder_note_routine; const char *comment; - int skip_hooks; /* skip hook generation if non zero */ + enum write_types_kinds kind; }; static void output_escaped_param (struct walk_type_data *d, const char *, const char *); static void output_mangled_typename (outf_p, const_type_p); static void walk_type (type_p t, struct walk_type_data *d); -static void write_func_for_structure (type_p orig_s, type_p s, type_p *param, +static void write_func_for_structure (type_p orig_s, type_p s, const struct write_types_data *wtd); static void write_types_process_field (type_p f, const struct walk_type_data *d); static void write_types (outf_p output_header, type_p structures, - type_p param_structs, const struct write_types_data *wtd); static void write_types_local_process_field (type_p f, const struct walk_type_data *d); -static void write_local_func_for_structure - (const_type_p orig_s, type_p s, type_p *param); +static void write_local_func_for_structure (const_type_p orig_s, type_p s); static void write_local (outf_p output_header, - type_p structures, type_p param_structs); -static void write_enum_defn (type_p structures, type_p param_structs); + type_p structures); static int contains_scalar_p (type_p t); static void put_mangled_filename (outf_p, const input_file *); static void finish_root_table (struct flist *flp, const char *pfx, const char *tname, const char *lastname, const char *name); static void write_root (outf_p, pair_p, type_p, const char *, int, - struct fileloc *, const char *, bool); + struct fileloc *, bool); static void write_array (outf_p f, pair_p v, const struct write_types_data *wtd); static void write_roots (pair_p, bool); @@ -2256,14 +2452,46 @@ int counter; const struct fileloc *line; lang_bitmap bitmap; - type_p *param; int used_length; type_p orig_s; const char *reorder_fn; bool needs_cast_p; bool fn_wants_lvalue; + bool in_record_p; + int loopcounter; + bool in_ptr_field; + bool have_this_obj; }; + +/* Given a string TYPE_NAME, representing a C++ typename, return a valid + pre-processor identifier to use in a #define directive. This replaces + special characters used in C++ identifiers like '>', '<' and ':' with + '_'. + + If no C++ special characters are found in TYPE_NAME, return + TYPE_NAME. Otherwise, return a copy of TYPE_NAME with the special + characters replaced with '_'. In this case, the caller is + responsible for freeing the allocated string. */ + +static const char * +filter_type_name (const char *type_name) +{ + if (strchr (type_name, '<') || strchr (type_name, ':')) + { + size_t i; + char *s = xstrdup (type_name); + for (i = 0; i < strlen (s); i++) + if (s[i] == '<' || s[i] == '>' || s[i] == ':' || s[i] == ',' + || s[i] == '*') + s[i] = '_'; + return s; + } + else + return type_name; +} + + /* Print a mangled name representing T to OF. */ static void @@ -2275,6 +2503,7 @@ switch (t->kind) { case TYPE_NONE: + case TYPE_UNDEFINED: gcc_unreachable (); break; case TYPE_POINTER: @@ -2290,16 +2519,17 @@ case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: - oprintf (of, "%lu%s", (unsigned long) strlen (t->u.s.tag), - t->u.s.tag); - break; - case TYPE_PARAM_STRUCT: + case TYPE_USER_STRUCT: { - int i; - for (i = 0; i < NUM_PARAM; i++) - if (t->u.param_struct.param[i] != NULL) - output_mangled_typename (of, t->u.param_struct.param[i]); - output_mangled_typename (of, t->u.param_struct.stru); + /* For references to classes within an inheritance hierarchy, + only ever reference the ultimate base class, since only + it will have gt_ functions. */ + t = get_ultimate_base_class (t); + const char *id_for_tag = filter_type_name (t->u.s.tag); + oprintf (of, "%lu%s", (unsigned long) strlen (id_for_tag), + id_for_tag); + if (id_for_tag != t->u.s.tag) + free (CONST_CAST (char *, id_for_tag)); } break; case TYPE_ARRAY: @@ -2348,6 +2578,76 @@ } } +const char * +get_string_option (options_p opt, const char *key) +{ + for (; opt; opt = opt->next) + if (strcmp (opt->name, key) == 0) + return opt->info.string; + return NULL; +} + +/* Machinery for avoiding duplicate tags within switch statements. */ +struct seen_tag +{ + const char *tag; + struct seen_tag *next; +}; + +int +already_seen_tag (struct seen_tag *seen_tags, const char *tag) +{ + /* Linear search, so O(n^2), but n is currently small. */ + while (seen_tags) + { + if (!strcmp (seen_tags->tag, tag)) + return 1; + seen_tags = seen_tags->next; + } + /* Not yet seen this tag. */ + return 0; +} + +void +mark_tag_as_seen (struct seen_tag **seen_tags, const char *tag) +{ + /* Add to front of linked list. */ + struct seen_tag *new_node = XCNEW (struct seen_tag); + new_node->tag = tag; + new_node->next = *seen_tags; + *seen_tags = new_node; +} + +static void +walk_subclasses (type_p base, struct walk_type_data *d, + struct seen_tag **seen_tags) +{ + for (type_p sub = base->u.s.first_subclass; sub != NULL; + sub = sub->u.s.next_sibling_class) + { + const char *type_tag = get_string_option (sub->u.s.opt, "tag"); + if (type_tag && !already_seen_tag (*seen_tags, type_tag)) + { + mark_tag_as_seen (seen_tags, type_tag); + oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag); + d->indent += 2; + oprintf (d->of, "%*s{\n", d->indent, ""); + d->indent += 2; + oprintf (d->of, "%*s%s *sub = static_cast <%s *> (x);\n", + d->indent, "", sub->u.s.tag, sub->u.s.tag); + const char *old_val = d->val; + d->val = "(*sub)"; + walk_type (sub, d); + d->val = old_val; + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); + oprintf (d->of, "%*sbreak;\n", d->indent, ""); + d->indent -= 2; + } + walk_subclasses (sub, d, seen_tags); + } +} + /* Call D->PROCESS_FIELD for every field (or subfield) of D->VAL, which is of type T. Write code to D->OF to constrain execution (at the point that D->PROCESS_FIELD is called) to the appropriate @@ -2356,17 +2656,16 @@ containing the current object, D->OPT is a list of options to apply, D->INDENT is the current indentation level, D->LINE is used to print error messages, D->BITMAP indicates which languages to - print the structure for, and D->PARAM is the current parameter - (from an enclosing param_is option). */ + print the structure for. */ static void walk_type (type_p t, struct walk_type_data *d) { const char *length = NULL; const char *desc = NULL; + const char *type_tag = NULL; int maybe_undef_p = 0; - int use_param_num = -1; - int use_params_p = 0; + int atomic_p = 0; options_p oo; const struct nested_ptr_data *nested_ptr_d = NULL; @@ -2376,33 +2675,23 @@ length = oo->info.string; else if (strcmp (oo->name, "maybe_undef") == 0) maybe_undef_p = 1; - else if (strncmp (oo->name, "use_param", 9) == 0 - && (oo->name[9] == '\0' || ISDIGIT (oo->name[9]))) - use_param_num = oo->name[9] == '\0' ? 0 : oo->name[9] - '0'; - else if (strcmp (oo->name, "use_params") == 0) - use_params_p = 1; else if (strcmp (oo->name, "desc") == 0 && oo->kind == OPTION_STRING) desc = oo->info.string; - else if (strcmp (oo->name, "mark_hook") == 0) - ; else if (strcmp (oo->name, "nested_ptr") == 0 && oo->kind == OPTION_NESTED) nested_ptr_d = (const struct nested_ptr_data *) oo->info.nested; else if (strcmp (oo->name, "dot") == 0) ; else if (strcmp (oo->name, "tag") == 0) - ; + type_tag = oo->info.string; else if (strcmp (oo->name, "special") == 0) ; else if (strcmp (oo->name, "skip") == 0) ; + else if (strcmp (oo->name, "atomic") == 0) + atomic_p = 1; else if (strcmp (oo->name, "default") == 0) ; - else if (strcmp (oo->name, "param_is") == 0) - ; - else if (strncmp (oo->name, "param", 5) == 0 - && ISDIGIT (oo->name[5]) && strcmp (oo->name + 6, "_is") == 0) - ; else if (strcmp (oo->name, "chain_next") == 0) ; else if (strcmp (oo->name, "chain_prev") == 0) @@ -2413,47 +2702,16 @@ ; else if (strcmp (oo->name, "variable_size") == 0) ; + else if (strcmp (oo->name, "for_user") == 0) + ; else error_at_line (d->line, "unknown option `%s'\n", oo->name); if (d->used_length) length = NULL; - if (use_params_p) - { - int pointer_p = t->kind == TYPE_POINTER; - - if (pointer_p) - t = t->u.p; - if (!UNION_OR_STRUCT_P (t)) - error_at_line (d->line, "`use_params' option on unimplemented type"); - else - t = find_param_structure (t, d->param); - if (pointer_p) - t = create_pointer (t); - } - - if (use_param_num != -1) - { - if (d->param != NULL && d->param[use_param_num] != NULL) - { - type_p nt = d->param[use_param_num]; - - if (t->kind == TYPE_ARRAY) - nt = create_array (nt, t->u.a.len); - else if (length != NULL && t->kind == TYPE_POINTER) - nt = create_pointer (nt); - d->needs_cast_p = (t->kind != TYPE_POINTER - && (nt->kind == TYPE_POINTER - || nt->kind == TYPE_STRING)); - t = nt; - } - else - error_at_line (d->line, "no parameter defined for `%s'", d->val); - } - if (maybe_undef_p - && (t->kind != TYPE_POINTER || !UNION_OR_STRUCT_P (t->u.p))) + && (t->kind != TYPE_POINTER || !union_or_struct_p (t->u.p))) { error_at_line (d->line, "field `%s' has invalid option `maybe_undef_p'\n", @@ -2461,6 +2719,12 @@ return; } + if (atomic_p && (t->kind != TYPE_POINTER) && (t->kind != TYPE_STRING)) + { + error_at_line (d->line, "field `%s' has invalid option `atomic'\n", d->val); + return; + } + switch (t->kind) { case TYPE_SCALAR: @@ -2470,16 +2734,35 @@ case TYPE_POINTER: { + d->in_ptr_field = true; if (maybe_undef_p && t->u.p->u.s.line.file == NULL) { oprintf (d->of, "%*sgcc_assert (!%s);\n", d->indent, "", d->val); break; } + /* If a pointer type is marked as "atomic", we process the + field itself, but we don't walk the data that they point to. + + There are two main cases where we walk types: to mark + pointers that are reachable, and to relocate pointers when + writing a PCH file. In both cases, an atomic pointer is + itself marked or relocated, but the memory that it points + to is left untouched. In the case of PCH, that memory will + be read/written unchanged to the PCH file. */ + if (atomic_p) + { + oprintf (d->of, "%*sif (%s != NULL) {\n", d->indent, "", d->val); + d->indent += 2; + d->process_field (t, d); + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); + break; + } + if (!length) { - if (!UNION_OR_STRUCT_P (t->u.p) - && t->u.p->kind != TYPE_PARAM_STRUCT) + if (!union_or_struct_p (t->u.p)) { error_at_line (d->line, "field `%s' is pointer to unimplemented type", @@ -2491,7 +2774,7 @@ { const char *oldprevval2 = d->prev_val[2]; - if (!UNION_OR_STRUCT_P (nested_ptr_d->type)) + if (!union_or_struct_p (nested_ptr_d->type)) { error_at_line (d->line, "field `%s' has invalid " @@ -2535,7 +2818,7 @@ } else { - int loopcounter = d->counter++; + int loopcounter = d->loopcounter; const char *oldval = d->val; const char *oldprevval3 = d->prev_val[3]; char *newval; @@ -2545,7 +2828,13 @@ oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter); oprintf (d->of, "%*sfor (i%d = 0; i%d != (size_t)(", d->indent, "", loopcounter, loopcounter); - output_escaped_param (d, length, "length"); + if (!d->in_record_p) + output_escaped_param (d, length, "length"); + else + oprintf (d->of, "l%d", loopcounter); + if (d->have_this_obj) + /* Try to unswitch loops (see PR53880). */ + oprintf (d->of, ") && ((void *)%s == this_obj", oldval); oprintf (d->of, "); i%d++) {\n", loopcounter); d->indent += 2; d->val = newval = xasprintf ("%s[i%d]", oldval, loopcounter); @@ -2562,12 +2851,13 @@ d->indent -= 2; oprintf (d->of, "%*s}\n", d->indent, ""); } + d->in_ptr_field = false; } break; case TYPE_ARRAY: { - int loopcounter = d->counter++; + int loopcounter; const char *oldval = d->val; char *newval; @@ -2576,6 +2866,11 @@ if (t->u.a.p->kind == TYPE_SCALAR) break; + if (length) + loopcounter = d->loopcounter; + else + loopcounter = d->counter++; + /* When walking an array, compute the length and store it in a local variable before walking the array elements, instead of recomputing the length expression each time through the loop. @@ -2586,13 +2881,16 @@ oprintf (d->of, "%*s{\n", d->indent, ""); d->indent += 2; oprintf (d->of, "%*ssize_t i%d;\n", d->indent, "", loopcounter); - oprintf (d->of, "%*ssize_t l%d = (size_t)(", - d->indent, "", loopcounter); - if (length) - output_escaped_param (d, length, "length"); - else - oprintf (d->of, "%s", t->u.a.len); - oprintf (d->of, ");\n"); + if (!d->in_record_p || !length) + { + oprintf (d->of, "%*ssize_t l%d = (size_t)(", + d->indent, "", loopcounter); + if (length) + output_escaped_param (d, length, "length"); + else + oprintf (d->of, "%s", t->u.a.len); + oprintf (d->of, ");\n"); + } oprintf (d->of, "%*sfor (i%d = 0; i%d != l%d; i%d++) {\n", d->indent, "", @@ -2621,6 +2919,9 @@ const int union_p = t->kind == TYPE_UNION; int seen_default_p = 0; options_p o; + int lengths_seen = 0; + int endcounter; + bool any_length_seen = false; if (!t->u.s.line.file) error_at_line (d->line, "incomplete structure `%s'", t->u.s.tag); @@ -2650,20 +2951,83 @@ t->u.s.tag); desc = "1"; } - oprintf (d->of, "%*sswitch (", d->indent, ""); + oprintf (d->of, "%*sswitch ((int) (", d->indent, ""); output_escaped_param (d, desc, "desc"); - oprintf (d->of, ")\n"); + oprintf (d->of, "))\n"); d->indent += 2; oprintf (d->of, "%*s{\n", d->indent, ""); } - for (f = t->u.s.fields; f; f = f->next) + else if (desc) + { + /* We have a "desc" option on a struct, signifying the + base class within a GC-managed inheritance hierarchy. + The current code specialcases the base class, then walks + into subclasses, recursing into this routine to handle them. + This organization requires the base class to have a case in + the switch statement, and hence a tag value is mandatory + for the base class. This restriction could be removed, but + it would require some restructing of this code. */ + if (!type_tag) + { + error_at_line (d->line, + "missing `tag' option for type `%s'", + t->u.s.tag); + } + oprintf (d->of, "%*sswitch ((int) (", d->indent, ""); + output_escaped_param (d, desc, "desc"); + oprintf (d->of, "))\n"); + d->indent += 2; + oprintf (d->of, "%*s{\n", d->indent, ""); + oprintf (d->of, "%*scase %s:\n", d->indent, "", type_tag); + d->indent += 2; + } + + FOR_ALL_INHERITED_FIELDS (t, f) + { + options_p oo; + int skip_p = 0; + const char *fieldlength = NULL; + + d->reorder_fn = NULL; + for (oo = f->opt; oo; oo = oo->next) + if (strcmp (oo->name, "skip") == 0) + skip_p = 1; + else if (strcmp (oo->name, "length") == 0 + && oo->kind == OPTION_STRING) + fieldlength = oo->info.string; + + if (skip_p) + continue; + if (fieldlength) + { + lengths_seen++; + d->counter++; + if (!union_p) + { + if (!any_length_seen) + { + oprintf (d->of, "%*s{\n", d->indent, ""); + d->indent += 2; + } + any_length_seen = true; + + oprintf (d->of, "%*ssize_t l%d = (size_t)(", + d->indent, "", d->counter - 1); + output_escaped_param (d, fieldlength, "length"); + oprintf (d->of, ");\n"); + } + } + } + endcounter = d->counter; + + FOR_ALL_INHERITED_FIELDS (t, f) { options_p oo; const char *dot = "."; const char *tagid = NULL; int skip_p = 0; int default_p = 0; - int use_param_p = 0; + const char *fieldlength = NULL; char *newval; d->reorder_fn = NULL; @@ -2681,9 +3045,9 @@ else if (strcmp (oo->name, "reorder") == 0 && oo->kind == OPTION_STRING) d->reorder_fn = oo->info.string; - else if (strncmp (oo->name, "use_param", 9) == 0 - && (oo->name[9] == '\0' || ISDIGIT (oo->name[9]))) - use_param_p = 1; + else if (strcmp (oo->name, "length") == 0 + && oo->kind == OPTION_STRING) + fieldlength = oo->info.string; if (skip_p) continue; @@ -2717,15 +3081,20 @@ "field `%s' is missing `tag' or `default' option", f->name); + if (fieldlength) + { + d->loopcounter = endcounter - lengths_seen--; + } + d->line = &f->line; d->val = newval = xasprintf ("%s%s%s", oldval, dot, f->name); d->opt = f->opt; d->used_length = false; - - if (union_p && use_param_p && d->param == NULL) - oprintf (d->of, "%*sgcc_unreachable ();\n", d->indent, ""); - else - walk_type (f->type, d); + d->in_record_p = !union_p; + + walk_type (f->type, d); + + d->in_record_p = false; free (newval); @@ -2746,11 +3115,42 @@ oprintf (d->of, "%*sdefault:\n", d->indent, ""); oprintf (d->of, "%*s break;\n", d->indent, ""); } + + if (desc && !union_p) + { + oprintf (d->of, "%*sbreak;\n", d->indent, ""); + d->indent -= 2; + } if (union_p) { oprintf (d->of, "%*s}\n", d->indent, ""); d->indent -= 2; } + else if (desc) + { + /* Add cases to handle subclasses. */ + struct seen_tag *tags = NULL; + walk_subclasses (t, d, &tags); + + /* Ensure that if someone forgets a "tag" option that we don't + silent fail to traverse that subclass's fields. */ + if (!seen_default_p) + { + oprintf (d->of, "%*s/* Unrecognized tag value. */\n", + d->indent, ""); + oprintf (d->of, "%*sdefault: gcc_unreachable (); \n", + d->indent, ""); + } + + /* End of the switch statement */ + oprintf (d->of, "%*s}\n", d->indent, ""); + d->indent -= 2; + } + if (any_length_seen) + { + d->indent -= 2; + oprintf (d->of, "%*s}\n", d->indent, ""); + } } break; @@ -2768,17 +3168,12 @@ } break; - case TYPE_PARAM_STRUCT: - { - type_p *oldparam = d->param; - - d->param = t->u.param_struct.param; - walk_type (t->u.param_struct.stru, d); - d->param = oldparam; - } + case TYPE_USER_STRUCT: + d->process_field (t, d); break; - default: + case TYPE_NONE: + case TYPE_UNDEFINED: gcc_unreachable (); } } @@ -2795,13 +3190,33 @@ switch (f->kind) { case TYPE_NONE: + case TYPE_UNDEFINED: gcc_unreachable (); case TYPE_POINTER: oprintf (d->of, "%*s%s (%s%s", d->indent, "", wtd->subfield_marker_routine, cast, d->val); if (wtd->param_prefix) { - oprintf (d->of, ", %s", d->prev_val[3]); + if (f->u.p->kind == TYPE_SCALAR) + /* The current type is a pointer to a scalar (so not + considered like a pointer to instances of user defined + types) and we are seeing it; it means we must be even + more careful about the second argument of the + SUBFIELD_MARKER_ROUTINE call. That argument must + always be the instance of the type for which + write_func_for_structure was called - this really is + what the function SUBFIELD_MARKER_ROUTINE expects. + That is, it must be an instance of the ORIG_S type + parameter of write_func_for_structure. The convention + is that that argument must be "x" in that case (as set + by write_func_for_structure). The problem is, we can't + count on d->prev_val[3] to be always set to "x" in that + case. Sometimes walk_type can set it to something else + (to e.g cooperate with write_array when called from + write_roots). So let's set it to "x" here then. */ + oprintf (d->of, ", x"); + else + oprintf (d->of, ", %s", d->prev_val[3]); if (d->orig_s) { oprintf (d->of, ", gt_%s_", wtd->param_prefix); @@ -2809,20 +3224,6 @@ } else oprintf (d->of, ", gt_%sa_%s", wtd->param_prefix, d->prev_val[0]); - - if (f->u.p->kind == TYPE_PARAM_STRUCT - && f->u.p->u.s.line.file != NULL) - { - oprintf (d->of, ", gt_e_"); - output_mangled_typename (d->of, f); - } - else if (UNION_OR_STRUCT_P (f) && f->u.p->u.s.line.file != NULL) - { - oprintf (d->of, ", gt_ggc_e_"); - output_mangled_typename (d->of, f); - } - else - oprintf (d->of, ", gt_types_enum_last"); } oprintf (d->of, ");\n"); if (d->reorder_fn && wtd->reorder_note_routine) @@ -2835,14 +3236,27 @@ case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: - case TYPE_PARAM_STRUCT: - oprintf (d->of, "%*sgt_%s_", d->indent, "", wtd->prefix); - output_mangled_typename (d->of, f); - oprintf (d->of, " (%s%s);\n", cast, d->val); - if (d->reorder_fn && wtd->reorder_note_routine) - oprintf (d->of, "%*s%s (%s%s, %s%s, %s);\n", d->indent, "", - wtd->reorder_note_routine, cast, d->val, cast, d->val, - d->reorder_fn); + case TYPE_USER_STRUCT: + if (f->kind == TYPE_USER_STRUCT && !d->in_ptr_field) + { + /* If F is a user-defined type and the field is not a + pointer to the type, then we should not generate the + standard pointer-marking code. All we need to do is call + the user-provided marking function to process the fields + of F. */ + oprintf (d->of, "%*sgt_%sx (&(%s));\n", d->indent, "", wtd->prefix, + d->val); + } + else + { + oprintf (d->of, "%*sgt_%s_", d->indent, "", wtd->prefix); + output_mangled_typename (d->of, f); + oprintf (d->of, " (%s%s);\n", cast, d->val); + if (d->reorder_fn && wtd->reorder_note_routine) + oprintf (d->of, "%*s%s (%s%s, %s%s, %s);\n", d->indent, "", + wtd->reorder_note_routine, cast, d->val, cast, d->val, + d->reorder_fn); + } break; case TYPE_SCALAR: @@ -2853,69 +3267,227 @@ } } -/* A subroutine of write_func_for_structure. Write the enum tag for S. */ - -static void -output_type_enum (outf_p of, type_p s) -{ - if (s->kind == TYPE_PARAM_STRUCT && s->u.param_struct.line.file != NULL) - { - oprintf (of, ", gt_e_"); - output_mangled_typename (of, s); - } - else if (UNION_OR_STRUCT_P (s) && s->u.s.line.file != NULL) - { - oprintf (of, ", gt_ggc_e_"); - output_mangled_typename (of, s); - } - else - oprintf (of, ", gt_types_enum_last"); -} - /* Return an output file that is suitable for definitions which can reference struct S */ static outf_p -get_output_file_for_structure (const_type_p s, type_p *param) +get_output_file_for_structure (const_type_p s) { const input_file *fn; - int i; - - gcc_assert (UNION_OR_STRUCT_P (s)); + + gcc_assert (union_or_struct_p (s)); fn = s->u.s.line.file; - /* This is a hack, and not the good kind either. */ - for (i = NUM_PARAM - 1; i >= 0; i--) - if (param && param[i] && param[i]->kind == TYPE_POINTER - && UNION_OR_STRUCT_P (param[i]->u.p)) - fn = param[i]->u.p->u.s.line.file; - /* The call to get_output_file_with_visibility may update fn by caching its result inside, so we need the CONST_CAST. */ return get_output_file_with_visibility (CONST_CAST (input_file*, fn)); } -/* For S, a structure that's part of ORIG_S, and using parameters - PARAM, write out a routine that: + +/* Returns the specifier keyword for a string or union type S, empty string + otherwise. */ + +static const char * +get_type_specifier (const type_p s) +{ + if (s->kind == TYPE_STRUCT) + return "struct "; + else if (s->kind == TYPE_LANG_STRUCT) + return get_type_specifier (s->u.s.lang_struct); + else if (s->kind == TYPE_UNION) + return "union "; + return ""; +} + + +/* Emits a declaration for type TY (assumed to be a union or a + structure) on stream OUT. */ + +static void +write_type_decl (outf_p out, type_p ty) +{ + if (union_or_struct_p (ty)) + oprintf (out, "%s%s", get_type_specifier (ty), ty->u.s.tag); + else if (ty->kind == TYPE_SCALAR) + { + if (ty->u.scalar_is_char) + oprintf (out, "const char"); + else + oprintf (out, "void"); + } + else if (ty->kind == TYPE_POINTER) + { + write_type_decl (out, ty->u.p); + oprintf (out, " *"); + } + else if (ty->kind == TYPE_ARRAY) + { + write_type_decl (out, ty->u.a.p); + oprintf (out, " *"); + } + else if (ty->kind == TYPE_STRING) + { + oprintf (out, "const char *"); + } + else + gcc_unreachable (); +} + + +/* Write on OF the name of the marker function for structure S. PREFIX + is the prefix to use (to distinguish ggc from pch markers). */ + +static void +write_marker_function_name (outf_p of, type_p s, const char *prefix) +{ + if (union_or_struct_p (s)) + { + const char *id_for_tag = filter_type_name (s->u.s.tag); + oprintf (of, "gt_%sx_%s", prefix, id_for_tag); + if (id_for_tag != s->u.s.tag) + free (CONST_CAST (char *, id_for_tag)); + } + else + gcc_unreachable (); +} + +/* Write on OF a user-callable routine to act as an entry point for + the marking routine for S, generated by write_func_for_structure. + WTD distinguishes between ggc and pch markers. */ + +static void +write_user_func_for_structure_ptr (outf_p of, type_p s, const write_types_data *wtd) +{ + gcc_assert (union_or_struct_p (s)); + + type_p alias_of = NULL; + for (options_p opt = s->u.s.opt; opt; opt = opt->next) + if (strcmp (opt->name, "ptr_alias") == 0) + { + /* ALIAS_OF is set if ORIG_S is marked "ptr_alias". This means that + we do not generate marking code for ORIG_S here. Instead, a + forwarder #define in gtype-desc.h will cause every call to its + marker to call the target of this alias. + + However, we still want to create a user entry code for the + aliased type. So, if ALIAS_OF is set, we only generate the + user-callable marker function. */ + alias_of = opt->info.type; + break; + } + + DBGPRINTF ("write_user_func_for_structure_ptr: %s %s", s->u.s.tag, + wtd->prefix); + + /* Only write the function once. */ + if (s->u.s.wrote_user_func_for_ptr[wtd->kind]) + return; + s->u.s.wrote_user_func_for_ptr[wtd->kind] = true; + + oprintf (of, "\nvoid\n"); + oprintf (of, "gt_%sx (", wtd->prefix); + write_type_decl (of, s); + oprintf (of, " *& x)\n"); + oprintf (of, "{\n"); + oprintf (of, " if (x)\n "); + write_marker_function_name (of, + alias_of ? alias_of : get_ultimate_base_class (s), + wtd->prefix); + oprintf (of, " ((void *) x);\n"); + oprintf (of, "}\n"); +} + + +/* Write a function to mark all the fields of type S on OF. PREFIX + and D are as in write_user_marking_functions. */ + +static void +write_user_func_for_structure_body (type_p s, const char *prefix, + struct walk_type_data *d) +{ + oprintf (d->of, "\nvoid\n"); + oprintf (d->of, "gt_%sx (", prefix); + write_type_decl (d->of, s); + oprintf (d->of, "& x_r ATTRIBUTE_UNUSED)\n"); + oprintf (d->of, "{\n"); + oprintf (d->of, " "); + write_type_decl (d->of, s); + oprintf (d->of, " * ATTRIBUTE_UNUSED x = &x_r;\n"); + d->val = "(*x)"; + d->indent = 2; + walk_type (s, d); + oprintf (d->of, "}\n"); +} + +/* Emit the user-callable functions needed to mark all the types used + by the user structure S. PREFIX is the prefix to use to + distinguish ggc and pch markers. D contains data needed to pass to + walk_type when traversing the fields of a type. + + For every type T referenced by S, two routines are generated: one + that takes 'T *', marks the pointer and calls the second routine, + which just marks the fields of T. */ + +static void +write_user_marking_functions (type_p s, + const write_types_data *w, + struct walk_type_data *d) +{ + gcc_assert (s->kind == TYPE_USER_STRUCT); + + for (pair_p fld = s->u.s.fields; fld; fld = fld->next) + { + type_p fld_type = fld->type; + if (fld_type->kind == TYPE_POINTER) + { + type_p pointed_to_type = fld_type->u.p; + if (union_or_struct_p (pointed_to_type)) + write_user_func_for_structure_ptr (d->of, pointed_to_type, w); + } + else if (union_or_struct_p (fld_type)) + write_user_func_for_structure_body (fld_type, w->prefix, d); + } +} + + +/* For S, a structure that's part of ORIG_S write out a routine that: - Takes a parameter, a void * but actually of type *S - If SEEN_ROUTINE returns nonzero, calls write_types_process_field on each field of S or its substructures and (in some cases) things - that are pointed to by S. -*/ + that are pointed to by S. */ static void -write_func_for_structure (type_p orig_s, type_p s, type_p *param, +write_func_for_structure (type_p orig_s, type_p s, const struct write_types_data *wtd) { const char *chain_next = NULL; const char *chain_prev = NULL; const char *chain_circular = NULL; - const char *mark_hook_name = NULL; options_p opt; struct walk_type_data d; + if (s->u.s.base_class) + { + /* Verify that the base class has a "desc", since otherwise + the traversal hooks there won't attempt to visit fields of + subclasses such as this one. */ + const_type_p ubc = get_ultimate_base_class (s); + if ((!opts_have (ubc->u.s.opt, "user") + && !opts_have (ubc->u.s.opt, "desc"))) + error_at_line (&s->u.s.line, + ("'%s' is a subclass of non-GTY(user) GTY class '%s'" + ", but '%s' lacks a discriminator 'desc' option"), + s->u.s.tag, ubc->u.s.tag, ubc->u.s.tag); + + /* Don't write fns for subclasses, only for the ultimate base class + within an inheritance hierarchy. */ + return; + } + memset (&d, 0, sizeof (d)); - d.of = get_output_file_for_structure (s, param); + d.of = get_output_file_for_structure (s); + + bool for_user = false; for (opt = s->u.s.opt; opt; opt = opt->next) if (strcmp (opt->name, "chain_next") == 0 && opt->kind == OPTION_STRING) @@ -2926,9 +3498,8 @@ else if (strcmp (opt->name, "chain_circular") == 0 && opt->kind == OPTION_STRING) chain_circular = opt->info.string; - else if (strcmp (opt->name, "mark_hook") == 0 - && opt->kind == OPTION_STRING) - mark_hook_name = opt->info.string; + else if (strcmp (opt->name, "for_user") == 0) + for_user = true; if (chain_prev != NULL && chain_next == NULL) error_at_line (&s->u.s.line, "chain_prev without chain_next"); if (chain_circular != NULL && chain_next != NULL) @@ -2942,30 +3513,31 @@ d.opt = s->u.s.opt; d.line = &s->u.s.line; d.bitmap = s->u.s.bitmap; - d.param = param; d.prev_val[0] = "*x"; d.prev_val[1] = "not valid postage"; /* Guarantee an error. */ d.prev_val[3] = "x"; d.val = "(*x)"; + d.have_this_obj = false; oprintf (d.of, "\n"); oprintf (d.of, "void\n"); - if (param == NULL) - oprintf (d.of, "gt_%sx_%s", wtd->prefix, orig_s->u.s.tag); - else - { - oprintf (d.of, "gt_%s_", wtd->prefix); - output_mangled_typename (d.of, orig_s); - } + write_marker_function_name (d.of, orig_s, wtd->prefix); oprintf (d.of, " (void *x_p)\n"); - oprintf (d.of, "{\n"); - oprintf (d.of, " %s %s * %sx = (%s %s *)x_p;\n", - s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag, - chain_next == NULL ? "const " : "", - s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); + oprintf (d.of, "{\n "); + write_type_decl (d.of, s); + oprintf (d.of, " * %sx = (", chain_next == NULL ? "const " : ""); + write_type_decl (d.of, s); + oprintf (d.of, " *)x_p;\n"); if (chain_next != NULL) - oprintf (d.of, " %s %s * xlimit = x;\n", - s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); + { + /* TYPE_USER_STRUCTs should not occur here. These structures + are completely handled by user code. */ + gcc_assert (orig_s->kind != TYPE_USER_STRUCT); + + oprintf (d.of, " "); + write_type_decl (d.of, s); + oprintf (d.of, " * xlimit = x;\n"); + } if (chain_next == NULL) { oprintf (d.of, " if (%s (x", wtd->marker_routine); @@ -2973,7 +3545,6 @@ { oprintf (d.of, ", x, gt_%s_", wtd->param_prefix); output_mangled_typename (d.of, orig_s); - output_type_enum (d.of, orig_s); } oprintf (d.of, "))\n"); } @@ -2987,22 +3558,15 @@ { oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix); output_mangled_typename (d.of, orig_s); - output_type_enum (d.of, orig_s); } oprintf (d.of, "))\n"); if (chain_circular != NULL) oprintf (d.of, " return;\n do\n"); - if (mark_hook_name && !wtd->skip_hooks) - { - oprintf (d.of, " {\n"); - oprintf (d.of, " %s (xlimit);\n ", mark_hook_name); - } + oprintf (d.of, " xlimit = ("); d.prev_val[2] = "*xlimit"; output_escaped_param (&d, chain_next, "chain_next"); oprintf (d.of, ");\n"); - if (mark_hook_name && !wtd->skip_hooks) - oprintf (d.of, " }\n"); if (chain_prev != NULL) { oprintf (d.of, " if (x != xlimit)\n"); @@ -3021,7 +3585,6 @@ { oprintf (d.of, ", xprev, gt_%s_", wtd->param_prefix); output_mangled_typename (d.of, orig_s); - output_type_enum (d.of, orig_s); } oprintf (d.of, ");\n"); oprintf (d.of, " }\n"); @@ -3033,24 +3596,25 @@ { oprintf (d.of, ", xlimit, gt_%s_", wtd->param_prefix); output_mangled_typename (d.of, orig_s); - output_type_enum (d.of, orig_s); } oprintf (d.of, "));\n"); - if (mark_hook_name && !wtd->skip_hooks) - oprintf (d.of, " %s (xlimit);\n", mark_hook_name); oprintf (d.of, " do\n"); } else oprintf (d.of, " while (x != xlimit)\n"); } oprintf (d.of, " {\n"); - if (mark_hook_name && chain_next == NULL && !wtd->skip_hooks) - { - oprintf (d.of, " %s (x);\n", mark_hook_name); - } + d.prev_val[2] = "*x"; d.indent = 6; - walk_type (s, &d); + if (orig_s->kind != TYPE_USER_STRUCT) + walk_type (s, &d); + else + { + /* User structures have no fields to walk. Simply generate a call + to the user-provided structure marker. */ + oprintf (d.of, "%*sgt_%sx (x);\n", d.indent, "", wtd->prefix); + } if (chain_next != NULL) { @@ -3063,35 +3627,51 @@ if (chain_circular != NULL) oprintf (d.of, " while (x != xlimit);\n"); oprintf (d.of, "}\n"); + + if (orig_s->kind == TYPE_USER_STRUCT) + write_user_marking_functions (orig_s, wtd, &d); + + if (for_user) + { + write_user_func_for_structure_body (orig_s, wtd->prefix, &d); + write_user_func_for_structure_ptr (d.of, orig_s, wtd); + } } + /* Write out marker routines for STRUCTURES and PARAM_STRUCTS. */ static void -write_types (outf_p output_header, type_p structures, type_p param_structs, +write_types (outf_p output_header, type_p structures, const struct write_types_data *wtd) { int nbfun = 0; /* Count the emitted functions. */ type_p s; oprintf (output_header, "\n/* %s*/\n", wtd->comment); + /* We first emit the macros and the declarations. Functions' code is emitted afterwards. This is needed in plugin mode. */ - oprintf (output_header, "/* macros and declarations */\n"); + oprintf (output_header, "/* Macros and declarations. */\n"); for (s = structures; s; s = s->next) - if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO) + /* Do not emit handlers for derived classes; we only ever deal with + the ultimate base class within an inheritance hierarchy. */ + if ((s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO) + && !s->u.s.base_class) { options_p opt; if (s->gc_used == GC_MAYBE_POINTED_TO && s->u.s.line.file == NULL) continue; + const char *s_id_for_tag = filter_type_name (s->u.s.tag); + oprintf (output_header, "#define gt_%s_", wtd->prefix); output_mangled_typename (output_header, s); oprintf (output_header, "(X) do { \\\n"); oprintf (output_header, " if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix, - s->u.s.tag); + s_id_for_tag); oprintf (output_header, " } while (0)\n"); for (opt = s->u.s.opt; opt; opt = opt->next) @@ -3101,9 +3681,14 @@ const_type_p const t = (const_type_p) opt->info.type; if (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT) - oprintf (output_header, - "#define gt_%sx_%s gt_%sx_%s\n", - wtd->prefix, s->u.s.tag, wtd->prefix, t->u.s.tag); + { + const char *t_id_for_tag = filter_type_name (t->u.s.tag); + oprintf (output_header, + "#define gt_%sx_%s gt_%sx_%s\n", + wtd->prefix, s->u.s.tag, wtd->prefix, t_id_for_tag); + if (t_id_for_tag != t->u.s.tag) + free (CONST_CAST (char *, t_id_for_tag)); + } else error_at_line (&s->u.s.line, "structure alias is not a structure"); @@ -3115,7 +3700,10 @@ /* Declare the marker procedure only once. */ oprintf (output_header, "extern void gt_%sx_%s (void *);\n", - wtd->prefix, s->u.s.tag); + wtd->prefix, s_id_for_tag); + + if (s_id_for_tag != s->u.s.tag) + free (CONST_CAST (char *, s_id_for_tag)); if (s->u.s.line.file == NULL) { @@ -3125,24 +3713,6 @@ } } - for (s = param_structs; s; s = s->next) - if (s->gc_used == GC_POINTED_TO) - { - type_p stru = s->u.param_struct.stru; - - /* Declare the marker procedure. */ - oprintf (output_header, "extern void gt_%s_", wtd->prefix); - output_mangled_typename (output_header, s); - oprintf (output_header, " (void *);\n"); - - if (stru->u.s.line.file == NULL) - { - fprintf (stderr, "warning: structure `%s' used but not defined\n", - s->u.s.tag); - continue; - } - } - /* At last we emit the functions code. */ oprintf (output_header, "\n/* functions code */\n"); for (s = structures; s; s = s->next) @@ -3166,7 +3736,7 @@ nbfun++; DBGPRINTF ("writing func #%d lang_struct ss @ %p '%s'", nbfun, (void*) ss, ss->u.s.tag); - write_func_for_structure (s, ss, NULL, wtd); + write_func_for_structure (s, ss, wtd); } } else @@ -3174,7 +3744,7 @@ nbfun++; DBGPRINTF ("writing func #%d struct s @ %p '%s'", nbfun, (void*) s, s->u.s.tag); - write_func_for_structure (s, s, NULL, wtd); + write_func_for_structure (s, s, wtd); } } else @@ -3185,38 +3755,6 @@ (int) s->gc_used); } - for (s = param_structs; s; s = s->next) - if (s->gc_used == GC_POINTED_TO) - { - type_p *param = s->u.param_struct.param; - type_p stru = s->u.param_struct.stru; - if (stru->u.s.line.file == NULL) - continue; - if (stru->kind == TYPE_LANG_STRUCT) - { - type_p ss; - for (ss = stru->u.s.lang_struct; ss; ss = ss->next) - { - nbfun++; - DBGPRINTF ("writing func #%d param lang_struct ss @ %p '%s'", - nbfun, (void*) ss, ss->u.s.tag); - write_func_for_structure (s, ss, param, wtd); - } - } - else - { - nbfun++; - DBGPRINTF ("writing func #%d param struct s @ %p stru @ %p '%s'", - nbfun, (void*) s, - (void*) stru, stru->u.s.tag); - write_func_for_structure (s, stru, param, wtd); - } - } - else - { - /* Param structure s is not pointed to, so should be ignored. */ - DBGPRINTF ("ignored s @ %p", (void*)s); - } if (verbosity_level >= 2) printf ("%s emitted %d routines for %s\n", progname, nbfun, wtd->comment); @@ -3225,22 +3763,28 @@ static const struct write_types_data ggc_wtd = { "ggc_m", NULL, "ggc_mark", "ggc_test_and_set_mark", NULL, "GC marker procedures. ", - FALSE + WTK_GGC }; static const struct write_types_data pch_wtd = { "pch_n", "pch_p", "gt_pch_note_object", "gt_pch_note_object", "gt_pch_note_reorder", "PCH type-walking procedures. ", - TRUE + WTK_PCH }; /* Write out the local pointer-walking routines. */ -/* process_field routine for local pointer-walking. */ +/* process_field routine for local pointer-walking for user-callable + routines. The difference between this and + write_types_local_process_field is that, in this case, we do not + need to check whether the given pointer matches the address of the + parent structure. This check was already generated by the call + to gt_pch_nx in the main gt_pch_p_*() function that is calling + this code. */ static void -write_types_local_process_field (type_p f, const struct walk_type_data *d) +write_types_local_user_process_field (type_p f, const struct walk_type_data *d) { switch (f->kind) { @@ -3248,21 +3792,113 @@ case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: - case TYPE_PARAM_STRUCT: + case TYPE_STRING: + oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + break; + + case TYPE_USER_STRUCT: + if (d->in_ptr_field) + oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + else + oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", + d->indent, "", d->val); + break; + + case TYPE_SCALAR: + break; + + case TYPE_ARRAY: + case TYPE_NONE: + case TYPE_UNDEFINED: + gcc_unreachable (); + } +} + + +/* Write a function to PCH walk all the fields of type S on OF. + D contains data needed by walk_type to recurse into the fields of S. */ + +static void +write_pch_user_walking_for_structure_body (type_p s, struct walk_type_data *d) +{ + oprintf (d->of, "\nvoid\n"); + oprintf (d->of, "gt_pch_nx ("); + write_type_decl (d->of, s); + oprintf (d->of, "* x ATTRIBUTE_UNUSED,\n" + "\tATTRIBUTE_UNUSED gt_pointer_operator op,\n" + "\tATTRIBUTE_UNUSED void *cookie)\n"); + oprintf (d->of, "{\n"); + d->val = "(*x)"; + d->indent = 2; + d->process_field = write_types_local_user_process_field; + walk_type (s, d); + oprintf (d->of, "}\n"); +} + + +/* Emit the user-callable functions needed to mark all the types used + by the user structure S. PREFIX is the prefix to use to + distinguish ggc and pch markers. CHAIN_NEXT is set if S has the + chain_next option defined. D contains data needed to pass to + walk_type when traversing the fields of a type. + + For every type T referenced by S, two routines are generated: one + that takes 'T *', marks the pointer and calls the second routine, + which just marks the fields of T. */ + +static void +write_pch_user_walking_functions (type_p s, struct walk_type_data *d) +{ + gcc_assert (s->kind == TYPE_USER_STRUCT); + + for (pair_p fld = s->u.s.fields; fld; fld = fld->next) + { + type_p fld_type = fld->type; + if (union_or_struct_p (fld_type)) + write_pch_user_walking_for_structure_body (fld_type, d); + } +} + + +/* process_field routine for local pointer-walking. */ + +static void +write_types_local_process_field (type_p f, const struct walk_type_data *d) +{ + gcc_assert (d->have_this_obj); + switch (f->kind) + { + case TYPE_POINTER: + case TYPE_STRUCT: + case TYPE_UNION: + case TYPE_LANG_STRUCT: case TYPE_STRING: oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", d->prev_val[3]); oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); break; + case TYPE_USER_STRUCT: + oprintf (d->of, "%*sif ((void *)(%s) == this_obj)\n", d->indent, "", + d->prev_val[3]); + if (d->in_ptr_field) + oprintf (d->of, "%*s op (&(%s), cookie);\n", d->indent, "", d->val); + else + oprintf (d->of, "%*s gt_pch_nx (&(%s), op, cookie);\n", + d->indent, "", d->val); + break; + case TYPE_SCALAR: break; - default: + case TYPE_ARRAY: + case TYPE_NONE: + case TYPE_UNDEFINED: gcc_unreachable (); } } + /* For S, a structure that's part of ORIG_S, and using parameters PARAM, write out a routine that: - Is of type gt_note_pointers @@ -3270,17 +3906,21 @@ */ static void -write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param) +write_local_func_for_structure (const_type_p orig_s, type_p s) { struct walk_type_data d; + /* Don't write fns for subclasses, only for the ultimate base class + within an inheritance hierarchy. */ + if (s->u.s.base_class) + return; + memset (&d, 0, sizeof (d)); - d.of = get_output_file_for_structure (s, param); + d.of = get_output_file_for_structure (s); d.process_field = write_types_local_process_field; d.opt = s->u.s.opt; d.line = &s->u.s.line; d.bitmap = s->u.s.bitmap; - d.param = param; d.prev_val[0] = d.prev_val[2] = "*x"; d.prev_val[1] = "not valid postage"; /* Guarantee an error. */ d.prev_val[3] = "x"; @@ -3296,23 +3936,48 @@ "\tATTRIBUTE_UNUSED gt_pointer_operator op,\n" "\tATTRIBUTE_UNUSED void *cookie)\n"); oprintf (d.of, "{\n"); - oprintf (d.of, " %s %s * const x ATTRIBUTE_UNUSED = (%s %s *)x_p;\n", + oprintf (d.of, " %s %s * x ATTRIBUTE_UNUSED = (%s %s *)x_p;\n", s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag, s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag); d.indent = 2; - walk_type (s, &d); + d.have_this_obj = true; + + if (s->kind != TYPE_USER_STRUCT) + walk_type (s, &d); + else + { + /* User structures have no fields to walk. Simply generate a + call to the user-provided PCH walker. */ + oprintf (d.of, "%*sif ((void *)(%s) == this_obj)\n", d.indent, "", + d.prev_val[3]); + oprintf (d.of, "%*s gt_pch_nx (&(%s), op, cookie);\n", + d.indent, "", d.val); + } + oprintf (d.of, "}\n"); + + /* Write user-callable entry points for the PCH walking routines. */ + if (orig_s->kind == TYPE_USER_STRUCT) + write_pch_user_walking_functions (s, &d); + + for (options_p o = s->u.s.opt; o; o = o->next) + if (strcmp (o->name, "for_user") == 0) + { + write_pch_user_walking_for_structure_body (s, &d); + break; + } } /* Write out local marker routines for STRUCTURES and PARAM_STRUCTS. */ static void -write_local (outf_p output_header, type_p structures, type_p param_structs) +write_local (outf_p output_header, type_p structures) { type_p s; if (!output_header) return; + oprintf (output_header, "\n/* Local pointer-walking routines. */\n"); for (s = structures; s; s = s->next) if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO) @@ -3353,99 +4018,28 @@ { type_p ss; for (ss = s->u.s.lang_struct; ss; ss = ss->next) - write_local_func_for_structure (s, ss, NULL); + write_local_func_for_structure (s, ss); } else - write_local_func_for_structure (s, s, NULL); - } - - for (s = param_structs; s; s = s->next) - if (s->gc_used == GC_POINTED_TO) - { - type_p *param = s->u.param_struct.param; - type_p stru = s->u.param_struct.stru; - - /* Declare the marker procedure. */ - oprintf (output_header, "extern void gt_pch_p_"); - output_mangled_typename (output_header, s); - oprintf (output_header, - "\n (void *, void *, gt_pointer_operator, void *);\n"); - - if (stru->u.s.line.file == NULL) - { - fprintf (stderr, "warning: structure `%s' used but not defined\n", - s->u.s.tag); - continue; - } - - if (stru->kind == TYPE_LANG_STRUCT) - { - type_p ss; - for (ss = stru->u.s.lang_struct; ss; ss = ss->next) - write_local_func_for_structure (s, ss, param); - } - else - write_local_func_for_structure (s, stru, param); + write_local_func_for_structure (s, s); } } /* Nonzero if S is a type for which typed GC allocators should be output. */ #define USED_BY_TYPED_GC_P(s) \ - (((s->kind == TYPE_POINTER) \ - && ((s->u.p->gc_used == GC_POINTED_TO) \ - || (s->u.p->gc_used == GC_USED))) \ - || (UNION_OR_STRUCT_P (s) && \ - (((s)->gc_used == GC_POINTED_TO) \ - || ((s)->gc_used == GC_MAYBE_POINTED_TO \ - && s->u.s.line.file != NULL) \ - || ((s)->gc_used == GC_USED \ - && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous")))))) - - -/* Write out the 'enum' definition for gt_types_enum. */ - -static void -write_enum_defn (type_p structures, type_p param_structs) -{ - type_p s; - int nbstruct = 0; - int nbparamstruct = 0; - - if (!header_file) - return; - oprintf (header_file, "\n/* Enumeration of types known. */\n"); - oprintf (header_file, "enum gt_types_enum {\n"); - for (s = structures; s; s = s->next) - if (USED_BY_TYPED_GC_P (s)) - { - nbstruct++; - DBGPRINTF ("write_enum_defn s @ %p nbstruct %d", - (void*) s, nbstruct); - if (UNION_OR_STRUCT_P (s)) - DBGPRINTF ("write_enum_defn s %p #%d is unionorstruct tagged %s", - (void*) s, nbstruct, s->u.s.tag); - oprintf (header_file, " gt_ggc_e_"); - output_mangled_typename (header_file, s); - oprintf (header_file, ",\n"); - } - for (s = param_structs; s; s = s->next) - if (s->gc_used == GC_POINTED_TO) - { - nbparamstruct++; - DBGPRINTF ("write_enum_defn s %p nbparamstruct %d", - (void*) s, nbparamstruct); - oprintf (header_file, " gt_e_"); - output_mangled_typename (header_file, s); - oprintf (header_file, ",\n"); - } - oprintf (header_file, " gt_types_enum_last\n"); - oprintf (header_file, "};\n"); - if (verbosity_level >= 2) - printf ("%s handled %d GTY-ed structures & %d parameterized structures.\n", - progname, nbstruct, nbparamstruct); - -} + ((s->kind == TYPE_POINTER \ + && (s->u.p->gc_used == GC_POINTED_TO \ + || s->u.p->gc_used == GC_USED)) \ + || (union_or_struct_p (s) \ + && ((s)->gc_used == GC_POINTED_TO \ + || ((s)->gc_used == GC_MAYBE_POINTED_TO \ + && s->u.s.line.file != NULL) \ + || ((s)->gc_used == GC_USED \ + && strncmp (s->u.s.tag, "anonymous", strlen ("anonymous"))) \ + || (s->u.s.base_class && opts_have (s->u.s.opt, "tag"))))) + + /* Might T contain any non-pointer elements? */ @@ -3459,6 +4053,9 @@ return 0; case TYPE_ARRAY: return contains_scalar_p (t->u.a.p); + case TYPE_USER_STRUCT: + /* User-marked structures will typically contain pointers. */ + return 0; default: /* Could also check for structures that have no non-pointer fields, but there aren't enough of those to worry about. */ @@ -3552,6 +4149,60 @@ } } +/* Finish off the created gt_clear_caches_file_c functions. */ + +static void +finish_cache_funcs (flist *flp) +{ + struct flist *fli2; + + for (fli2 = flp; fli2; fli2 = fli2->next) + if (fli2->started_p) + { + oprintf (fli2->f, "}\n\n"); + } + + for (fli2 = flp; fli2 && base_files; fli2 = fli2->next) + if (fli2->started_p) + { + lang_bitmap bitmap = get_lang_bitmap (fli2->file); + int fnum; + + for (fnum = 0; bitmap != 0; fnum++, bitmap >>= 1) + if (bitmap & 1) + { + oprintf (base_files[fnum], "extern void gt_clear_caches_"); + put_mangled_filename (base_files[fnum], fli2->file); + oprintf (base_files[fnum], " ();\n"); + } + } + + for (size_t fnum = 0; base_files && fnum < num_lang_dirs; fnum++) + oprintf (base_files[fnum], "void\ngt_clear_caches ()\n{\n"); + + for (fli2 = flp; fli2; fli2 = fli2->next) + if (fli2->started_p) + { + lang_bitmap bitmap = get_lang_bitmap (fli2->file); + int fnum; + + fli2->started_p = 0; + + for (fnum = 0; base_files && bitmap != 0; fnum++, bitmap >>= 1) + if (bitmap & 1) + { + oprintf (base_files[fnum], " gt_clear_caches_"); + put_mangled_filename (base_files[fnum], fli2->file); + oprintf (base_files[fnum], " ();\n"); + } + } + + for (size_t fnum = 0; base_files && fnum < num_lang_dirs; fnum++) + { + oprintf (base_files[fnum], "}\n"); + } +} + /* Write the first three fields (pointer, count and stride) for root NAME to F. V and LINE are as for write_root. @@ -3591,17 +4242,16 @@ static void write_field_root (outf_p f, pair_p v, type_p type, const char *name, - int has_length, struct fileloc *line, const char *if_marked, + int has_length, struct fileloc *line, bool emit_pch, type_p field_type, const char *field_name) { + struct pair newv; /* If the field reference is relative to V, rather than to some subcomponent of V, we can mark any subarrays with a single stride. We're effectively treating the field as a global variable in its own right. */ if (v && type == v->type) { - struct pair newv; - newv = *v; newv.type = field_type; newv.name = ACONCAT ((v->name, ".", field_name, NULL)); @@ -3612,7 +4262,7 @@ else if (field_type->kind == TYPE_ARRAY) v = NULL; write_root (f, v, field_type, ACONCAT ((name, ".", field_name, NULL)), - has_length, line, if_marked, emit_pch); + has_length, line, emit_pch); } /* Write out to F the table entry and any marker routines needed to @@ -3627,12 +4277,11 @@ - the C variable that contains NAME, if NAME is not part of an array. LINE is the line of the C source that declares the root variable. - HAS_LENGTH is nonzero iff V was a variable-length array. IF_MARKED - is nonzero iff we are building the root table for hash table caches. */ + HAS_LENGTH is nonzero iff V was a variable-length array. */ static void write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length, - struct fileloc *line, const char *if_marked, bool emit_pch) + struct fileloc *line, bool emit_pch) { switch (type->kind) { @@ -3651,8 +4300,6 @@ else if (strcmp (o->name, "desc") == 0 && o->kind == OPTION_STRING) desc = o->info.string; - else if (strcmp (o->name, "param_is") == 0) - ; else error_at_line (line, "field `%s' of global `%s' has unknown option `%s'", @@ -3683,8 +4330,8 @@ validf = ufld; } if (validf != NULL) - write_field_root (f, v, type, name, 0, line, if_marked, - emit_pch, validf->type, + write_field_root (f, v, type, name, 0, line, emit_pch, + validf->type, ACONCAT ((fld->name, ".", validf->name, NULL))); } @@ -3693,8 +4340,8 @@ "global `%s.%s' has `desc' option but is not union", name, fld->name); else - write_field_root (f, v, type, name, 0, line, if_marked, - emit_pch, fld->type, fld->name); + write_field_root (f, v, type, name, 0, line, emit_pch, fld->type, + fld->name); } } break; @@ -3703,43 +4350,40 @@ { char *newname; newname = xasprintf ("%s[0]", name); - write_root (f, v, type->u.a.p, newname, has_length, line, if_marked, - emit_pch); + write_root (f, v, type->u.a.p, newname, has_length, line, emit_pch); free (newname); } break; + case TYPE_USER_STRUCT: + error_at_line (line, "`%s' must be a pointer type, because it is " + "a GC root and its type is marked with GTY((user))", + v->name); + break; + case TYPE_POINTER: { - type_p tp; + const_type_p tp; if (!start_root_entry (f, v, name, line)) return; tp = type->u.p; - if (!has_length && UNION_OR_STRUCT_P (tp)) + if (!has_length && union_or_struct_p (tp)) { - oprintf (f, " >_ggc_mx_%s,\n", tp->u.s.tag); + tp = get_ultimate_base_class (tp); + const char *id_for_tag = filter_type_name (tp->u.s.tag); + oprintf (f, " >_ggc_mx_%s,\n", id_for_tag); if (emit_pch) - oprintf (f, " >_pch_nx_%s", tp->u.s.tag); + oprintf (f, " >_pch_nx_%s", id_for_tag); else oprintf (f, " NULL"); - } - else if (!has_length && tp->kind == TYPE_PARAM_STRUCT) - { - oprintf (f, " >_ggc_m_"); - output_mangled_typename (f, tp); - if (emit_pch) - { - oprintf (f, ",\n >_pch_n_"); - output_mangled_typename (f, tp); - } - else - oprintf (f, ",\n NULL"); + if (id_for_tag != tp->u.s.tag) + free (CONST_CAST (char *, id_for_tag)); } else if (has_length - && (tp->kind == TYPE_POINTER || UNION_OR_STRUCT_P (tp))) + && (tp->kind == TYPE_POINTER || union_or_struct_p (tp))) { oprintf (f, " >_ggc_ma_%s,\n", name); if (emit_pch) @@ -3753,8 +4397,6 @@ "global `%s' is pointer to unimplemented type", name); } - if (if_marked) - oprintf (f, ",\n &%s", if_marked); oprintf (f, "\n },\n"); } break; @@ -3773,7 +4415,10 @@ case TYPE_SCALAR: break; - default: + case TYPE_NONE: + case TYPE_UNDEFINED: + case TYPE_UNION: + case TYPE_LANG_STRUCT: error_at_line (line, "global `%s' is unimplemented type", name); } } @@ -3793,7 +4438,6 @@ d.line = &v->line; d.opt = v->opt; d.bitmap = get_lang_bitmap (v->line.file); - d.param = NULL; d.prev_val[3] = prevval3 = xasprintf ("&%s", v->name); @@ -3810,6 +4454,7 @@ oprintf (d.of, "{\n"); d.prev_val[0] = d.prev_val[1] = d.prev_val[2] = d.val = v->name; d.process_field = write_types_local_process_field; + d.have_this_obj = true; walk_type (v->type, &d); oprintf (f, "}\n\n"); } @@ -3821,6 +4466,7 @@ oprintf (f, "{\n"); d.prev_val[0] = d.prev_val[1] = d.prev_val[2] = d.val = v->name; d.process_field = write_types_process_field; + d.have_this_obj = false; walk_type (v->type, &d); free (prevval3); oprintf (f, "}\n\n"); @@ -3849,12 +4495,7 @@ length = o->info.string; else if (strcmp (o->name, "deletable") == 0) deletable_p = 1; - else if (strcmp (o->name, "param_is") == 0) - ; - else if (strncmp (o->name, "param", 5) == 0 - && ISDIGIT (o->name[5]) && strcmp (o->name + 6, "_is") == 0) - ; - else if (strcmp (o->name, "if_marked") == 0) + else if (strcmp (o->name, "cache") == 0) ; else error_at_line (&v->line, @@ -3900,8 +4541,7 @@ for (o = v->opt; o; o = o->next) if (strcmp (o->name, "length") == 0) length_p = 1; - else if (strcmp (o->name, "deletable") == 0 - || strcmp (o->name, "if_marked") == 0) + else if (strcmp (o->name, "deletable") == 0) skip_p = 1; if (skip_p) @@ -3919,7 +4559,7 @@ oprintf (f, "[] = {\n"); } - write_root (f, v, v->type, v->name, length_p, &v->line, NULL, emit_pch); + write_root (f, v, v->type, v->name, length_p, &v->line, emit_pch); } finish_root_table (flp, "ggc_r", "LAST_GGC_ROOT_TAB", "ggc_root_tab", @@ -3936,8 +4576,6 @@ for (o = v->opt; o; o = o->next) if (strcmp (o->name, "deletable") == 0) skip_p = 0; - else if (strcmp (o->name, "if_marked") == 0) - skip_p = 1; if (skip_p) continue; @@ -3966,65 +4604,13 @@ outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*, v->line.file)); struct flist *fli; - const char *if_marked = NULL; - int length_p = 0; + bool cache = false; options_p o; for (o = v->opt; o; o = o->next) - if (strcmp (o->name, "length") == 0) - length_p = 1; - else if (strcmp (o->name, "if_marked") == 0 - && o->kind == OPTION_STRING) - if_marked = o->info.string; - if (if_marked == NULL) - continue; - if (v->type->kind != TYPE_POINTER - || v->type->u.p->kind != TYPE_PARAM_STRUCT - || v->type->u.p->u.param_struct.stru != find_structure ("htab", 0)) - { - error_at_line (&v->line, - "if_marked option used but not hash table"); - continue; - } - - for (fli = flp; fli; fli = fli->next) - if (fli->f == f) - break; - if (!fli->started_p) - { - fli->started_p = 1; - - oprintf (f, "EXPORTED_CONST struct ggc_cache_tab gt_ggc_rc_"); - put_mangled_filename (f, v->line.file); - oprintf (f, "[] = {\n"); - } - - write_root (f, v, v->type->u.p->u.param_struct.param[0], - v->name, length_p, &v->line, if_marked, emit_pch); - } - - finish_root_table (flp, "ggc_rc", "LAST_GGC_CACHE_TAB", "ggc_cache_tab", - "gt_ggc_cache_rtab"); - - if (!emit_pch) - return; - - for (v = variables; v; v = v->next) - { - outf_p f = get_output_file_with_visibility (CONST_CAST (input_file*, - v->line.file)); - struct flist *fli; - int length_p = 0; - int if_marked_p = 0; - options_p o; - - for (o = v->opt; o; o = o->next) - if (strcmp (o->name, "length") == 0) - length_p = 1; - else if (strcmp (o->name, "if_marked") == 0) - if_marked_p = 1; - - if (!if_marked_p) + if (strcmp (o->name, "cache") == 0) + cache = true; + if (!cache) continue; for (fli = flp; fli; fli = fli->next) @@ -4034,16 +4620,18 @@ { fli->started_p = 1; - oprintf (f, "EXPORTED_CONST struct ggc_root_tab gt_pch_rc_"); + oprintf (f, "void\ngt_clear_caches_"); put_mangled_filename (f, v->line.file); - oprintf (f, "[] = {\n"); + oprintf (f, " ()\n{\n"); } - write_root (f, v, v->type, v->name, length_p, &v->line, NULL, emit_pch); + oprintf (f, " gt_cleare_cache (%s);\n", v->name); } - finish_root_table (flp, "pch_rc", "LAST_GGC_ROOT_TAB", "ggc_root_tab", - "gt_pch_cache_rtab"); + finish_cache_funcs (flp); + + if (!emit_pch) + return; for (v = variables; v; v = v->next) { @@ -4054,9 +4642,11 @@ options_p o; for (o = v->opt; o; o = o->next) - if (strcmp (o->name, "deletable") == 0 - || strcmp (o->name, "if_marked") == 0) - skip_p = 1; + if (strcmp (o->name, "deletable") == 0) + { + skip_p = 1; + break; + } if (skip_p) continue; @@ -4084,277 +4674,11 @@ "gt_pch_scalar_rtab"); } -/* Record the definition of a generic VEC structure, as if we had expanded - the macros in vec.h: - - typedef struct VEC_<type>_base GTY(()) { - unsigned num; - unsigned alloc; - <type> GTY((length ("%h.num"))) vec[1]; - } VEC_<type>_base - - where the GTY(()) tags are only present if is_scalar is _false_. */ - -void -note_def_vec (const char *type_name, bool is_scalar, struct fileloc *pos) -{ - pair_p fields; - type_p t; - options_p o; - type_p len_ty = create_scalar_type ("unsigned"); - const char *name = concat ("VEC_", type_name, "_base", (char *) 0); - - if (is_scalar) - { - t = create_scalar_type (type_name); - o = 0; - } - else - { - t = resolve_typedef (type_name, pos); - o = create_string_option (0, "length", "%h.num"); - } - /* We assemble the field list in reverse order. */ - fields = create_field_at (0, create_array (t, "1"), "vec", o, pos); - fields = create_field_at (fields, len_ty, "alloc", 0, pos); - fields = create_field_at (fields, len_ty, "num", 0, pos); - - do_typedef (name, new_structure (name, 0, pos, fields, 0), pos); -} - -/* Record the definition of an allocation-specific VEC structure, as if - we had expanded the macros in vec.h: - - typedef struct VEC_<type>_<astrat> { - VEC_<type>_base base; - } VEC_<type>_<astrat>; -*/ -void -note_def_vec_alloc (const char *type, const char *astrat, struct fileloc *pos) -{ - const char *astratname = concat ("VEC_", type, "_", astrat, (char *) 0); - const char *basename = concat ("VEC_", type, "_base", (char *) 0); - - pair_p field = create_field_at (0, resolve_typedef (basename, pos), - "base", 0, pos); - - do_typedef (astratname, new_structure (astratname, 0, pos, field, 0), pos); -} - -/* Returns the specifier keyword for a string or union type S, empty string - otherwise. */ - -static const char * -get_type_specifier (const type_p s) -{ - if (s->kind == TYPE_STRUCT || s->kind == TYPE_LANG_STRUCT) - return "struct "; - if (s->kind == TYPE_UNION) - return "union "; - return ""; -} - -/* TRUE if type S has the GTY variable_size annotation. */ - -static bool -variable_size_p (const type_p s) -{ - options_p o; - for (o = s->u.s.opt; o; o = o->next) - if (strcmp (o->name, "variable_size") == 0) - return true; - return false; -} - -enum alloc_quantity -{ single, vector }; -enum alloc_zone -{ any_zone, specific_zone }; - -/* Writes one typed allocator definition for type identifier TYPE_NAME with - optional type specifier TYPE_SPECIFIER. The allocator name will contain - ALLOCATOR_TYPE. If VARIABLE_SIZE is true, the allocator will have an extra - parameter specifying number of bytes to allocate. If QUANTITY is set to - VECTOR, a vector allocator will be output, if ZONE is set to SPECIFIC_ZONE, - the allocator will be zone-specific. */ - -static void -write_typed_alloc_def (bool variable_size, const char *type_specifier, - const char *type_name, const char *allocator_type, - enum alloc_quantity quantity, enum alloc_zone zone) -{ - bool two_args = variable_size && (quantity == vector); - bool third_arg = ((zone == specific_zone) - && (variable_size || (quantity == vector))); - - oprintf (header_file, "#define ggc_alloc_%s%s", allocator_type, type_name); - oprintf (header_file, "(%s%s%s%s%s) ", - (variable_size ? "SIZE" : ""), - (two_args ? ", " : ""), - (quantity == vector) ? "n" : "", - (third_arg ? ", " : ""), (zone == specific_zone) ? "z" : ""); - oprintf (header_file, "((%s%s *)", type_specifier, type_name); - oprintf (header_file, "(ggc_internal_%salloc_stat (", allocator_type); - if (zone == specific_zone) - oprintf (header_file, "z, "); - if (variable_size) - oprintf (header_file, "SIZE"); - else - oprintf (header_file, "sizeof (%s%s)", type_specifier, type_name); - if (quantity == vector) - oprintf (header_file, ", n"); - oprintf (header_file, " MEM_STAT_INFO)))\n"); -} - -/* Writes a typed allocator definition for a struct or union S. */ - -static void -write_typed_struct_alloc_def (const type_p s, const char *allocator_type, - enum alloc_quantity quantity, - enum alloc_zone zone) -{ - write_typed_alloc_def (variable_size_p (s), get_type_specifier (s), - s->u.s.tag, allocator_type, quantity, zone); -} - -/* Writes a typed allocator definition for a typedef P. */ - -static void -write_typed_typedef_alloc_def (const pair_p p, const char *allocator_type, - enum alloc_quantity quantity, - enum alloc_zone zone) -{ - write_typed_alloc_def (variable_size_p (p->type), "", p->name, - allocator_type, quantity, zone); -} - -/* Writes typed allocator definitions for the types in STRUCTURES and - TYPEDEFS that are used by GC. */ - -static void -write_typed_alloc_defns (const type_p structures, const pair_p typedefs) -{ - type_p s; - pair_p p; - - oprintf (header_file, - "\n/* Allocators for known structs and unions. */\n\n"); - for (s = structures; s; s = s->next) - { - if (!USED_BY_TYPED_GC_P (s)) - continue; - write_typed_struct_alloc_def (s, "", single, any_zone); - write_typed_struct_alloc_def (s, "cleared_", single, any_zone); - write_typed_struct_alloc_def (s, "vec_", vector, any_zone); - write_typed_struct_alloc_def (s, "cleared_vec_", vector, any_zone); - write_typed_struct_alloc_def (s, "zone_", single, specific_zone); - write_typed_struct_alloc_def (s, "zone_cleared_", single, - specific_zone); - write_typed_struct_alloc_def (s, "zone_vec_", vector, specific_zone); - write_typed_struct_alloc_def (s, "zone_cleared_vec_", vector, - specific_zone); - } - - oprintf (header_file, "\n/* Allocators for known typedefs. */\n"); - for (p = typedefs; p; p = p->next) - { - s = p->type; - if (!USED_BY_TYPED_GC_P (s) || (strcmp (p->name, s->u.s.tag) == 0)) - continue; - write_typed_typedef_alloc_def (p, "", single, any_zone); - write_typed_typedef_alloc_def (p, "cleared_", single, any_zone); - write_typed_typedef_alloc_def (p, "vec_", vector, any_zone); - write_typed_typedef_alloc_def (p, "cleared_vec_", vector, any_zone); - write_typed_typedef_alloc_def (p, "zone_", single, specific_zone); - write_typed_typedef_alloc_def (p, "zone_cleared_", single, - specific_zone); - write_typed_typedef_alloc_def (p, "zone_cleared_vec_", vector, - specific_zone); - } -} - /* Prints not-as-ugly version of a typename of T to OF. Trades the uniquness guaranteee for somewhat increased readability. If name conflicts do happen, this funcion will have to be adjusted to be more like output_mangled_typename. */ -static void -output_typename (outf_p of, const_type_p t) -{ - switch (t->kind) - { - case TYPE_STRING: - oprintf (of, "str"); - break; - case TYPE_SCALAR: - oprintf (of, "scalar"); - break; - case TYPE_POINTER: - output_typename (of, t->u.p); - break; - case TYPE_STRUCT: - case TYPE_UNION: - case TYPE_LANG_STRUCT: - oprintf (of, "%s", t->u.s.tag); - break; - case TYPE_PARAM_STRUCT: - { - int i; - for (i = 0; i < NUM_PARAM; i++) - if (t->u.param_struct.param[i] != NULL) - { - output_typename (of, t->u.param_struct.param[i]); - oprintf (of, "_"); - } - output_typename (of, t->u.param_struct.stru); - break; - } - default: - gcc_unreachable (); - } -} - -/* Writes a typed GC allocator for type S that is suitable as a callback for - the splay tree implementation in libiberty. */ - -static void -write_splay_tree_allocator_def (const_type_p s) -{ - outf_p of = get_output_file_with_visibility (NULL); - oprintf (of, "void * ggc_alloc_splay_tree_"); - output_typename (of, s); - oprintf (of, " (int sz, void * nl)\n"); - oprintf (of, "{\n"); - oprintf (of, " return ggc_splay_alloc ("); - oprintf (of, "gt_e_"); - output_mangled_typename (of, s); - oprintf (of, ", sz, nl);\n"); - oprintf (of, "}\n\n"); -} - -/* Writes typed GC allocators for PARAM_STRUCTS that are suitable as callbacks - for the splay tree implementation in libiberty. */ - -static void -write_splay_tree_allocators (const_type_p param_structs) -{ - const_type_p s; - - oprintf (header_file, "\n/* Splay tree callback allocators. */\n"); - for (s = param_structs; s; s = s->next) - if (s->gc_used == GC_POINTED_TO) - { - oprintf (header_file, "extern void * ggc_alloc_splay_tree_"); - output_typename (header_file, s); - oprintf (header_file, " (int, void *);\n"); - write_splay_tree_allocator_def (s); - } -} - -static void dump_pair (int indent, pair_p p); -static void dump_type (int indent, type_p p); -static void dump_type_list (int indent, type_p p); - #define INDENT 2 /* Dumps the value of typekind KIND. */ @@ -4374,6 +4698,12 @@ case TYPE_STRUCT: printf ("TYPE_STRUCT"); break; + case TYPE_UNDEFINED: + printf ("TYPE_UNDEFINED"); + break; + case TYPE_USER_STRUCT: + printf ("TYPE_USER_STRUCT"); + break; case TYPE_UNION: printf ("TYPE_UNION"); break; @@ -4386,9 +4716,6 @@ case TYPE_LANG_STRUCT: printf ("TYPE_LANG_STRUCT"); break; - case TYPE_PARAM_STRUCT: - printf ("TYPE_PARAM_STRUCT"); - break; default: gcc_unreachable (); } @@ -4469,8 +4796,7 @@ { pair_p fields; - gcc_assert (t->kind == TYPE_STRUCT || t->kind == TYPE_UNION - || t->kind == TYPE_LANG_STRUCT); + gcc_assert (union_or_struct_p (t)); printf ("%*cu.s.tag = %s\n", indent, ' ', t->u.s.tag); dump_fileloc (indent, t->u.s.line); printf ("%*cu.s.fields =\n", indent, ' '); @@ -4500,25 +4826,6 @@ dump_type_list (indent + INDENT, t->u.a.p); } -/* Recursively dumps the parameterized struct T. */ - -static void -dump_type_u_param_struct (int indent, type_p t) -{ - int i; - gcc_assert (t->kind == TYPE_PARAM_STRUCT); - printf ("%*cu.param_struct.stru:\n", indent, ' '); - dump_type_list (indent, t->u.param_struct.stru); - dump_fileloc (indent, t->u.param_struct.line); - for (i = 0; i < NUM_PARAM; i++) - { - if (t->u.param_struct.param[i] == NULL) - continue; - printf ("%*cu.param_struct.param[%d]:\n", indent, ' ', i); - dump_type (indent + INDENT, t->u.param_struct.param[i]); - } -} - /* Recursively dumps the type list T. */ static void @@ -4542,6 +4849,16 @@ PTR *slot; printf ("%*cType at %p: ", indent, ' ', (void *) t); + if (t->kind == TYPE_UNDEFINED) + { + gcc_assert (t->gc_used == GC_UNUSED); + printf ("undefined.\n"); + return; + } + + if (seen_types == NULL) + seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL); + slot = htab_find_slot (seen_types, t, INSERT); if (*slot != NULL) { @@ -4566,6 +4883,7 @@ case TYPE_STRUCT: case TYPE_UNION: case TYPE_LANG_STRUCT: + case TYPE_USER_STRUCT: dump_type_u_s (indent + INDENT, t); break; case TYPE_POINTER: @@ -4575,9 +4893,6 @@ case TYPE_ARRAY: dump_type_u_a (indent + INDENT, t); break; - case TYPE_PARAM_STRUCT: - dump_type_u_param_struct (indent + INDENT, t); - break; default: gcc_unreachable (); } @@ -4625,11 +4940,11 @@ static void dump_everything (void) { - seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL); dump_pair_list ("typedefs", typedefs); dump_structures ("structures", structures); - dump_structures ("param_structs", param_structs); dump_pair_list ("variables", variables); + + /* Allocated with the first call to dump_type. */ htab_delete (seen_types); } @@ -4788,6 +5103,7 @@ f = XCNEWVAR (input_file, sizeof (input_file)+namlen+2); f->inpbitmap = 0; f->inpoutf = NULL; + f->inpisplugin = false; strcpy (f->inpname, name); slot = htab_find_slot (input_file_htab, f, INSERT); gcc_assert (slot != NULL); @@ -4817,7 +5133,7 @@ const input_file *inpfx = (const input_file *) x; const input_file *inpfy = (const input_file *) y; gcc_assert (inpfx != NULL && inpfy != NULL); - return !strcmp (get_input_file_name (inpfx), get_input_file_name (inpfy)); + return !filename_cmp (get_input_file_name (inpfx), get_input_file_name (inpfy)); } @@ -4842,7 +5158,6 @@ parse_program_options (argc, argv); -#if ENABLE_CHECKING if (do_debug) { time_t now = (time_t) 0; @@ -4850,7 +5165,6 @@ DBGPRINTF ("gengtype started pid %d at %s", (int) getpid (), ctime (&now)); } -#endif /* ENABLE_CHECKING */ /* Parse the input list and the input files. */ DBGPRINTF ("inputlist %s", inputlist); @@ -4861,7 +5175,6 @@ inputlist, read_state_filename); read_state (read_state_filename); DBGPRINT_COUNT_TYPE ("structures after read_state", structures); - DBGPRINT_COUNT_TYPE ("param_structs after read_state", param_structs); } else if (inputlist) { @@ -4869,16 +5182,21 @@ we can see them. We should initialize them before calling read_input_list. */ #define POS_HERE(Call) do { pos.file = this_file; pos.line = __LINE__; \ - Call;} while(0) + Call;} while (0) POS_HERE (do_scalar_typedef ("CUMULATIVE_ARGS", &pos)); POS_HERE (do_scalar_typedef ("REAL_VALUE_TYPE", &pos)); POS_HERE (do_scalar_typedef ("FIXED_VALUE_TYPE", &pos)); POS_HERE (do_scalar_typedef ("double_int", &pos)); + POS_HERE (do_scalar_typedef ("offset_int", &pos)); + POS_HERE (do_scalar_typedef ("widest_int", &pos)); + POS_HERE (do_scalar_typedef ("int64_t", &pos)); POS_HERE (do_scalar_typedef ("uint64_t", &pos)); POS_HERE (do_scalar_typedef ("uint8", &pos)); + POS_HERE (do_scalar_typedef ("uintptr_t", &pos)); POS_HERE (do_scalar_typedef ("jword", &pos)); POS_HERE (do_scalar_typedef ("JCF_u2", &pos)); POS_HERE (do_scalar_typedef ("void", &pos)); + POS_HERE (do_scalar_typedef ("machine_mode", &pos)); POS_HERE (do_typedef ("PTR", create_pointer (resolve_typedef ("void", &pos)), &pos)); @@ -4895,8 +5213,6 @@ progname, (int) num_gt_files, type_count); DBGPRINT_COUNT_TYPE ("structures after parsing", structures); - DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs); - } else fatal ("either an input list or a read state file should be given"); @@ -4919,8 +5235,11 @@ /* Parse our plugin files and augment the state. */ for (ix = 0; ix < nb_plugin_files; ix++) - parse_file (get_input_file_name (plugin_files[ix])); - + { + input_file* pluginput = plugin_files [ix]; + pluginput->inpisplugin = true; + parse_file (get_input_file_name (pluginput)); + } if (hit_error) return 1; @@ -4938,17 +5257,27 @@ gen_rtx_next (); - /* The call to set_gc_used may indirectly call find_param_structure - hence enlarge the param_structs list of types. */ set_gc_used (variables); + for (type_p t = structures; t; t = t->next) + { + bool for_user = false; + for (options_p o = t->u.s.opt; o; o = o->next) + if (strcmp (o->name, "for_user") == 0) + { + for_user = true; + break; + } + + if (for_user) + set_gc_used_type (t, GC_POINTED_TO); + } /* The state at this point is read from the state input file or by parsing source files and optionally augmented by parsing plugin source files. Write it now. */ if (write_state_filename) { DBGPRINT_COUNT_TYPE ("structures before write_state", structures); - DBGPRINT_COUNT_TYPE ("param_structs before write_state", param_structs); if (hit_error) fatal ("didn't write state file %s after errors", @@ -4971,25 +5300,18 @@ open_base_files (); - write_enum_defn (structures, param_structs); - write_typed_alloc_defns (structures, typedefs); output_header = plugin_output ? plugin_output : header_file; DBGPRINT_COUNT_TYPE ("structures before write_types outputheader", structures); - DBGPRINT_COUNT_TYPE ("param_structs before write_types outputheader", - param_structs); - - write_types (output_header, structures, param_structs, &ggc_wtd); + + write_types (output_header, structures, &ggc_wtd); if (plugin_files == NULL) { DBGPRINT_COUNT_TYPE ("structures before write_types headerfil", structures); - DBGPRINT_COUNT_TYPE ("param_structs before write_types headerfil", - param_structs); - write_types (header_file, structures, param_structs, &pch_wtd); - write_local (header_file, structures, param_structs); + write_types (header_file, structures, &pch_wtd); + write_local (header_file, structures); } - write_splay_tree_allocators (param_structs); write_roots (variables, plugin_files == NULL); write_rtx_next (); close_output_files ();