There have been various discussions about how to handle inheritance within ggc and PCH: whether to extend gengtype to support C++ syntax such as templates, or to require people to use GTY((user)) and manually write field-traversal.
I've attempted to introduce class hierarchies in a few places recently, for example for the symtab types: http://gcc.gnu.org/ml/gcc-patches/2013-09/msg00668.html and the gimple types: http://gcc.gnu.org/ml/gcc-patches/2013-08/msg01788.html In each case the GTY((user)) is always the most painful part: it requires ugly hand-written code which must be kept up-to-date with changes to the underlying types, lest we run into difficult-to-track-down crashes inside the GC and PCH. I got sick of writing and debugging these GTY((user)) traversal functions, for IMHO quite modest use of C++ (no templates etc), so I had a go at implementing support for inheritance in gengtype, as seen in the following patch series. The key compromise I'm introducing, as I see it, is to require the user to "opt in" to the support for the inheritance, on a class-by-class basis, and not attempt to support all of C++, but only single inheritance, without templates. The idea is that if you add a GTY marker to a subclass, you are "opting in" to gengtype, and on any restrictions on the base class that gengtype needs to impose to avoid having to deal with all of C++ syntax: specifically, no multiple inheritance, and the base class can't be a template. If those restrictions are too much, e.g. you have something like: struct alloc_pool_hasher : typed_noop_remove <alloc_pool_descriptor> then don't GTY-mark the class, and gengtype won't attempt to parse the base class (as per the current parser). I can tweak things so that GTY((user)) classes are also excluded. This compromise allows gengtype to autogenerate traversal functions for simple uses of inheritance, avoiding the need for hand-maintaining them, whilst allowing all of C++ for places that need it, without having to support parsing all of that C++ syntax in gengtype - IMHO the best of both approaches. You put a "desc" GTY option on the base class to signify how to discriminate between subclasses in the marker function. Every concrete subclass should have a "tag" GTY option, and gengtype builds a single set of traversal functions, for the base class of the hierarchy, with a big switch statement on the desc, using the tag values as the cases. This is of course very similar to how unions are handled, and is similar to the first part of this proposal from Lawrence Crowl: http://gcc.gnu.org/ml/gcc/2012-08/msg00267.html Within such a hierarchy, traversal functions are only generated for the base class. I was able to use this to reimplement my port of the symtab types to a C++ class hierarchy. The old, ugly version of the patch can be seen at: http://gcc.gnu.org/ml/gcc-patches/2013-09/msg00672.html I've attached an updated version of the above patch to the following patch series, which uses the new gengtype inheritance support to eliminate all of the horrible hand-written traversal functions, and the ugly dummy GTY roots that are needed to workaround bugs in GTY((user)). Successfully bootstrapped and regtested this (plus the followup autogenerated symtab refactoring from: http://gcc.gnu.org/ml/gcc-patches/2013-09/msg00669.html ) OK for trunk? IMHO this is a much simpler approach; it avoids having to deal with GTY((user)) and manually-written markers. Presumably I would also need to update the docs. For reference, here's what one of the generated functions looks like (I believe this is not significantly uglier that what gtype-desc.c already contains). Note how the fields appear in reverse order of *types* (i.e. from deepest subclass up to parent), within a field they appear in natural order. So, for example, in "case SYMTAB_FUNCTION:" the cgraph fields appear, then the base symtab fields. The two pch functions are similar. void gt_ggc_mx_symtab_node_base (void *x_p) { struct symtab_node_base * const x = (struct symtab_node_base *)x_p; if (ggc_test_and_set_mark (x)) { switch (((*x)).type) { case SYMTAB_SYMBOL: gt_ggc_m_9tree_node ((*x).decl); gt_ggc_m_16symtab_node_base ((*x).next); gt_ggc_m_16symtab_node_base ((*x).previous); gt_ggc_m_16symtab_node_base ((*x).next_sharing_asm_name); gt_ggc_m_16symtab_node_base ((*x).previous_sharing_asm_name); gt_ggc_m_16symtab_node_base ((*x).same_comdat_group); gt_ggc_m_20vec_ipa_ref_t_va_gc_ ((*x).ref_list.references); gt_ggc_m_9tree_node ((*x).alias_target); gt_ggc_m_18lto_file_decl_data ((*x).lto_file_data); break; case SYMTAB_VARIABLE: { varpool_node *sub = static_cast <varpool_node *> (x); gt_ggc_m_9tree_node ((*sub).decl); gt_ggc_m_16symtab_node_base ((*sub).next); gt_ggc_m_16symtab_node_base ((*sub).previous); gt_ggc_m_16symtab_node_base ((*sub).next_sharing_asm_name); gt_ggc_m_16symtab_node_base ((*sub).previous_sharing_asm_name); gt_ggc_m_16symtab_node_base ((*sub).same_comdat_group); gt_ggc_m_20vec_ipa_ref_t_va_gc_ ((*sub).ref_list.references); gt_ggc_m_9tree_node ((*sub).alias_target); gt_ggc_m_18lto_file_decl_data ((*sub).lto_file_data); } break; case SYMTAB_FUNCTION: { cgraph_node *sub = static_cast <cgraph_node *> (x); gt_ggc_m_11cgraph_edge ((*sub).callers); gt_ggc_m_11cgraph_edge ((*sub).indirect_calls); gt_ggc_m_16symtab_node_base ((*sub).origin); gt_ggc_m_16symtab_node_base ((*sub).nested); gt_ggc_m_16symtab_node_base ((*sub).next_nested); gt_ggc_m_16symtab_node_base ((*sub).next_sibling_clone); gt_ggc_m_16symtab_node_base ((*sub).prev_sibling_clone); gt_ggc_m_16symtab_node_base ((*sub).clones); gt_ggc_m_16symtab_node_base ((*sub).clone_of); gt_ggc_m_P11cgraph_edge4htab ((*sub).call_site_hash); gt_ggc_m_9tree_node ((*sub).former_clone_of); gt_ggc_m_16symtab_node_base ((*sub).global.inlined_to); gt_ggc_m_28vec_ipa_replace_map_p_va_gc_ ((*sub).clone.tree_map); gt_ggc_m_15bitmap_head_def ((*sub).clone.args_to_skip); gt_ggc_m_15bitmap_head_def ((*sub).clone.combined_args_to_skip); gt_ggc_m_9tree_node ((*sub).thunk.alias); gt_ggc_m_9tree_node ((*sub).decl); gt_ggc_m_16symtab_node_base ((*sub).next); gt_ggc_m_16symtab_node_base ((*sub).previous); gt_ggc_m_16symtab_node_base ((*sub).next_sharing_asm_name); gt_ggc_m_16symtab_node_base ((*sub).previous_sharing_asm_name); gt_ggc_m_16symtab_node_base ((*sub).same_comdat_group); gt_ggc_m_20vec_ipa_ref_t_va_gc_ ((*sub).ref_list.references); gt_ggc_m_9tree_node ((*sub).alias_target); gt_ggc_m_18lto_file_decl_data ((*sub).lto_file_data); } break; } } } David Malcolm (3): Parse base classes for GTY-marked types Handle simple inheritance in gengtype. Convert symtab, cgraph and varpool nodes into a real class hierarchy gcc/cgraph.h | 38 +++++------------ gcc/gengtype-parse.c | 47 +++++++++++++++++++-- gcc/gengtype-state.c | 2 + gcc/gengtype.c | 115 +++++++++++++++++++++++++++++++++++++++++++++------ gcc/gengtype.h | 9 +++- gcc/ipa-ref.h | 6 +-- gcc/is-a.h | 6 +-- gcc/symtab.c | 4 +- 8 files changed, 175 insertions(+), 52 deletions(-) -- 1.7.11.7