Make gengtype more robust against user error

* doc/gty.texi ("Inheritance and GTY"): Make it clear that
	to use autogenerated markers for a class-hierarchy, every class
	must have a GTY marker.
	* gengtype.h (struct type): Add linked list of subclasses to
	the "s" member of the union.
	(add_subclass): New decl.
	* gengtype-state.c (read_state_struct_type): Set up subclass
	linked list.
	* gengtype.c (get_ultimate_base_class): New.
	(add_subclass): New.
	(new_structure): Set up subclass linked list.
	(set_gc_used_type): Propagate usage information to subclasses.
	(output_mangled_typename): Use get_ultimate_base_class.
	(walk_subclasses): Use the subclass linked list, avoiding an
	O(N^2) when writing out all types.
	(walk_type): Issue an error if the base class is missing a tag,
	rather than generating bogus C code.  Add a gcc_unreachable
	default case, in case people omit tags from concrete subclasses,
	or get the values wrong.
	(write_func_for_structure): Issue an error for subclasses for
	which the base doesn't have a "desc", since otherwise the
	autogenerated routines for the base would silently fail to visit
	any subclass fields.
	(write_root): Use get_ultimate_base_class, tweaking constness of
	tp to match that function's signature.

From-SVN: r204148
This commit is contained in:
David Malcolm 2013-10-29 01:16:05 +00:00 committed by David Malcolm
parent 1ed5a6cc50
commit 32fe52714e
5 changed files with 137 additions and 29 deletions

View File

@ -1,3 +1,31 @@
2013-10-29 David Malcolm <dmalcolm@redhat.com>
* doc/gty.texi ("Inheritance and GTY"): Make it clear that
to use autogenerated markers for a class-hierarchy, every class
must have a GTY marker.
* gengtype.h (struct type): Add linked list of subclasses to
the "s" member of the union.
(add_subclass): New decl.
* gengtype-state.c (read_state_struct_type): Set up subclass
linked list.
* gengtype.c (get_ultimate_base_class): New.
(add_subclass): New.
(new_structure): Set up subclass linked list.
(set_gc_used_type): Propagate usage information to subclasses.
(output_mangled_typename): Use get_ultimate_base_class.
(walk_subclasses): Use the subclass linked list, avoiding an
O(N^2) when writing out all types.
(walk_type): Issue an error if the base class is missing a tag,
rather than generating bogus C code. Add a gcc_unreachable
default case, in case people omit tags from concrete subclasses,
or get the values wrong.
(write_func_for_structure): Issue an error for subclasses for
which the base doesn't have a "desc", since otherwise the
autogenerated routines for the base would silently fail to visit
any subclass fields.
(write_root): Use get_ultimate_base_class, tweaking constness of
tp to match that function's signature.
2013-10-29 David Malcolm <dmalcolm@redhat.com>
* doc/gty.texi (GTY Options): Add note about inheritance to

View File

@ -497,6 +497,13 @@ The base class and its discriminator must be identified using the ``desc''
option. Each concrete subclass must use the ``tag'' option to identify
which value of the discriminator it corresponds to.
Every class in the hierarchy must have a @code{GTY(())} marker, as
gengtype will only attempt to parse classes that have such a marker
@footnote{Classes lacking such a marker will not be identified as being
part of the hierarchy, and so the marking routines will not handle them,
leading to a assertion failure within the marking routines due to an
unknown tag value (assuming that assertions are enabled).}.
@smallexample
class GTY((desc("%h.kind"), tag("0"))) example_base
@{

View File

@ -1615,6 +1615,8 @@ read_state_struct_type (type_p type)
read_state_lang_bitmap (&(type->u.s.bitmap));
read_state_type (&(type->u.s.lang_struct));
read_state_type (&(type->u.s.base_class));
if (type->u.s.base_class)
add_subclass (type->u.s.base_class, type);
}
else
{

View File

@ -137,6 +137,16 @@ xasprintf (const char *format, ...)
return result;
}
/* 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;
}
/* Input file handling. */
/* Table of all input files. */
@ -667,6 +677,16 @@ resolve_typedef (const char *s, struct fileloc *pos)
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
@ -749,6 +769,8 @@ new_structure (const char *name, enum typekind kind, struct fileloc *pos,
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;
}
@ -1535,6 +1557,12 @@ set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM],
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)
{
@ -2554,8 +2582,7 @@ output_mangled_typename (outf_p of, const_type_p t)
/* For references to classes within an inheritance hierarchy,
only ever reference the ultimate base class, since only
it will have gt_ functions. */
while (t->u.s.base_class)
t = t->u.s.base_class;
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);
@ -2630,30 +2657,28 @@ get_string_option (options_p opt, const char *key)
static void
walk_subclasses (type_p base, struct walk_type_data *d)
{
for (type_p sub = structures; sub != NULL; sub = sub->next)
for (type_p sub = base->u.s.first_subclass; sub != NULL;
sub = sub->u.s.next_sibling_class)
{
if (sub->u.s.base_class == base)
const char *type_tag = get_string_option (sub->u.s.opt, "tag");
if (type_tag)
{
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);
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);
}
}
@ -3023,6 +3048,20 @@ walk_type (type_p t, struct walk_type_data *d)
}
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");
@ -3188,6 +3227,16 @@ walk_type (type_p t, struct walk_type_data *d)
/* 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;
@ -3537,10 +3586,23 @@ write_func_for_structure (type_p orig_s, type_p s, type_p *param,
options_p opt;
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;
{
/* 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);
@ -4452,7 +4514,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
case TYPE_POINTER:
{
type_p tp;
const_type_p tp;
if (!start_root_entry (f, v, name, line))
return;
@ -4461,8 +4523,7 @@ write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
if (!has_length && union_or_struct_p (tp))
{
while (tp->u.s.base_class)
tp = tp->u.s.base_class;
tp = get_ultimate_base_class (tp);
const char *id_for_tag = filter_type_name (tp->u.s.tag);
oprintf (f, " &gt_ggc_mx_%s,\n", id_for_tag);
if (emit_pch)

View File

@ -293,6 +293,15 @@ struct type {
type_p lang_struct;
type_p base_class; /* the parent class, if any. */
/* The following two fields are not serialized in state files, and
are instead reconstructed on load. */
/* The head of a singly-linked list of immediate descendents in
the inheritance hierarchy. */
type_p first_subclass;
/* The next in that list. */
type_p next_sibling_class;
} s;
/* when TYPE_SCALAR: */
@ -424,6 +433,7 @@ extern char *xasprintf (const char *, ...) ATTRIBUTE_PRINTF_1;
extern void do_typedef (const char *s, type_p t, struct fileloc *pos);
extern void do_scalar_typedef (const char *s, struct fileloc *pos);
extern type_p resolve_typedef (const char *s, struct fileloc *pos);
extern void add_subclass (type_p base, type_p subclass);
extern type_p new_structure (const char *name, enum typekind kind,
struct fileloc *pos, pair_p fields,
options_p o, type_p base);