return result;
}
\f
+/* Locate the ultimate base class of struct S. */
+
+static const_type_p
+get_ultimate_base_class (const_type_p s)
+{
+ while (s->u.s.base_class)
+ s = s->u.s.base_class;
+ return s;
+}
+\f
/* Input file handling. */
/* Table of all input files. */
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))
+ if (0 == strncmp (s, "gcc::", 5))
s += 5;
for (p = typedefs; p != NULL; p = p->next)
return p;
}
+/* 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_p
new_structure (const char *name, enum typekind kind, struct fileloc *pos,
- pair_p fields, options_p o)
+ pair_p fields, options_p o, type_p base_class)
{
type_p si;
type_p s = NULL;
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;
}
/* 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. */
create_string_option (union_fields->opt, "tag", "1");
union_type =
new_structure (xasprintf ("%s_%d", "fake_union", id++), TYPE_UNION,
- &lexer_line, union_fields, NULL);
+ &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. */
create_string_option (nodot, "tag", note_insn_name[c]);
}
note_union_tp = new_structure ("rtx_def_note_subunion", TYPE_UNION,
- &lexer_line, note_flds, NULL);
+ &lexer_line, note_flds, NULL, NULL);
}
/* Create a type to represent the various forms of SYMBOL_REF_DATA. */
{
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", TYPE_UNION,
- &lexer_line, sym_flds, NULL);
+ &lexer_line, sym_flds, NULL, NULL);
}
for (i = 0; i < NUM_RTX_CODE; i++)
{
sname = xasprintf ("rtx_def_%s", rtx_name[i]);
substruct = new_structure (sname, TYPE_STRUCT, &lexer_line, subfields,
- NULL);
+ NULL, NULL);
ftag = xstrdup (rtx_name[i]);
for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
flds->opt = create_string_option (nodot, "tag", ftag);
}
return new_structure ("rtx_def_subunion", TYPE_UNION, &lexer_line, flds,
- nodot);
+ nodot, NULL);
}
/* Handle `special("tree_exp")'. This is a special case for
flds->opt = create_string_option (flds->opt, "default", "");
return new_structure ("tree_exp_subunion", TYPE_UNION, &lexer_line, flds,
- nodot);
+ nodot, NULL);
}
/* Perform any special processing on a type T, about to become the type
process_gc_options (t->u.s.opt, level, &dummy, &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, param,
+ 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, param,
+ allow_undefined_types);
+
+ FOR_ALL_INHERITED_FIELDS(t, f)
{
int maybe_undef = 0;
int pass_param = 0;
"tree.h", "rtl.h", "wide-int.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",
- "except.h", "output.h", "gimple.h", "cfgloop.h",
+ "gimple.h", "gimple-iterator.h", "gimple-ssa.h", "tree-cfg.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", "ipa-prop.h", "lto-streamer.h", "target-globals.h",
"ipa-inline.h", "dwarf2out.h", NULL
};
REG_EXTENDED, NULL_REGEX,
"gt-objc-objc-map.h", "objc/objc-map.c", NULL_FRULACT },
- /* General cases. For header *.h and source *.c files, we need
- * special actions to handle the language. */
+ /* 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
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. */
else
{
/* This can happen only when files_rules is buggy! */
- gcc_unreachable();
+ gcc_unreachable ();
}
/* Always skip the character after the dollar. */
pt++;
}
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
break;
}
}
+ if (equal && EOF != fgetc (newfile))
+ equal = false;
fclose (newfile);
return equal;
}
case TYPE_LANG_STRUCT:
case TYPE_USER_STRUCT:
{
+ /* 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));
+ free (CONST_CAST (char *, id_for_tag));
}
break;
case TYPE_PARAM_STRUCT:
}
}
+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;
+}
+
+static void
+walk_subclasses (type_p base, struct walk_type_data *d)
+{
+ 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)
+ {
+ 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);
+ }
+}
/* 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
{
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;
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)
d->indent += 2;
oprintf (d->of, "%*s{\n", d->indent, "");
}
+ 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 (", 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 (f = t->u.s.fields; f; f = f->next)
+ FOR_ALL_INHERITED_FIELDS (t, f)
{
options_p oo;
int skip_p = 0;
}
endcounter = d->counter;
- for (f = t->u.s.fields; f; f = f->next)
+ FOR_ALL_INHERITED_FIELDS (t, f)
{
options_p oo;
const char *dot = ".";
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. */
+ walk_subclasses (t, d);
+
+ /* 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;
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));
+ free (CONST_CAST (char *, id_for_tag));
}
else if (s->kind == TYPE_PARAM_STRUCT)
{
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);
for (opt = s->u.s.opt; opt; opt = opt->next)
emitted afterwards. This is needed in plugin mode. */
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;
"#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));
+ free (CONST_CAST (char *, t_id_for_tag));
}
else
error_at_line (&s->u.s.line,
wtd->prefix, s_id_for_tag);
if (s_id_for_tag != s->u.s.tag)
- free (CONST_CAST(char *, s_id_for_tag));
+ free (CONST_CAST (char *, s_id_for_tag));
if (s->u.s.line.file == NULL)
{
{
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.process_field = write_types_local_process_field;
|| ((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"))))))
+ && 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? */
case TYPE_POINTER:
{
- type_p tp;
+ const_type_p tp;
if (!start_root_entry (f, v, name, line))
return;
if (!has_length && union_or_struct_p (tp))
{
+ 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)
else
oprintf (f, " NULL");
if (id_for_tag != tp->u.s.tag)
- free (CONST_CAST(char *, id_for_tag));
+ free (CONST_CAST (char *, id_for_tag));
}
else if (!has_length && tp->kind == TYPE_PARAM_STRUCT)
{
oprintf (f, ", n");
oprintf (f, " MEM_STAT_INFO)))\n");
if (type_name_as_id != type_name)
- free (CONST_CAST(char *, type_name_as_id));
+ free (CONST_CAST (char *, type_name_as_id));
}
/* Writes a typed allocator definition into output F for a struct or
relevant to plugin input files. */
if (nb_plugin_files > 0)
{
- struct fileloc* filoc = type_fileloc(s);
+ struct fileloc* filoc = type_fileloc (s);
if (!filoc || !filoc->file->inpisplugin)
continue;
};
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 ("double_int_storage", &pos));
- POS_HERE (do_scalar_typedef ("addr_wide_int", &pos));
- POS_HERE (do_scalar_typedef ("max_wide_int", &pos));
+ POS_HERE (do_scalar_typedef ("offset_int", &pos));
+ POS_HERE (do_scalar_typedef ("widest_int", &pos));
POS_HERE (do_scalar_typedef ("uint64_t", &pos));
POS_HERE (do_scalar_typedef ("uint8", &pos));
POS_HERE (do_scalar_typedef ("uintptr_t", &pos));