diff mbox

[cxx-conversion] Support garbage-collected C++ templates

Message ID 20120808195258.GA30576@google.com
State New
Headers show

Commit Message

Diego Novillo Aug. 8, 2012, 7:52 p.m. UTC
Support garbage-collected C++ templates.

This patch is the first step towards supporting user-defined GC and
PCH marking routines.

The patch introduces two major changes:

- Support in gengtype for a new type of structure TYPE_USER_STRUCT.
  This makes gengtype to rely on external marking functions provided
  by the user.

- Support for C++ templates.  Templates must rely on user-provided
  functions because gengtype does not know how to deal with specific
  instances (nor should it).  This allowed me to remove the hack that
  had been added to support VEC.  In vec.h, I added 4 functions that
  gengtype relies on to do the various marking actions for GGC and
  PCH.

There are some limitations with this patch that I will remove after
this is merged into mainline:

1- We should only ask users to generate 3 marking functions: one for
   GGC, one for PCH and another one for PCH's local pointer walking.
   Currently, PCH local pointer walking needs 2: one that takes a type
   'T' and walks its fields applying the given operation, another one
   that takes 'T *' and calls the operation on its address.

2- Only templates are supported for user-provided markers.

3- Types not referenced in template arguments cannot have
   user-callable entry points.

These limitations are due to the way gengtype generates marking code.
Most header files do not have actual type information for the types
they handle (their signatures take 'void *'), so they are limited to
the types known by the source file that includes them.

Ideally, all marking code would be overloads for the same function
taking different argument types. I started going down that road but I
quickly found myself having to add forward references, I could not add
type references as arguments, etc.

I needed to be able to compare the code generated against existing
code, so I decided to postpone a major reorganization of the generated
code until later.

There are many other things in gengtype that I would like to change.
It essentially needs to be killed with fire:

- With user-supported marking functions we should be able to remove
  most GTY() marking options and leave it up to the user to write the
  little snippets of code that traverse structures.  For instance, for
  vec_t, the attribute 'length' is no longer needed.

- gengtype currently emits a web of functions that call macros that
  call functions similarly named.  All that is largely unnecessary. It
  should emit proper C++ overloads.

- Functions should be emitted in files that have access to the
  structure where they were defined.  I'm not convinced that the
  current multiplicity of gt-*.[ch] files is even necessary. However,
  I would like the guidance of a gengtype maintainer. I don't think I
  fully understand all of it.

I've tested the patch on x86_64 with the page and zone collectors and
with --enable-checking=gc,gcac (boy was that a slow mistake).

I am now ready to start preparing the merge of the branch into trunk.
I will do one final merge from trunk, fix gengtype conflicts from
Laurynas's latest change and start sending the merge patches.

Committed to cxx-conversion branch.



2012-08-08  Diego Novillo  <dnovillo@google.com>

	* coretypes.h (gt_pointer_operator): Move from ...
	* ggc.h: ... here.
	* doc/gty.texi: Document support for C++ templates and
	user-provided markers.
	* gcc/gengtype-lex.l: Update copyright year.
	Remove support for recognizing DEF_VEC_O, DEF_VEC_P and
	DEFVEC_I.
	* gengtype-parse.c: Update copyright year.
	(token_names): Remove DEF_VEC_O, DEF_VEC_P and DEF_VEC_I.
	(require_template_declaration): New.
	(typedef_name): Call it.
	(type): Replace IS_UNION with KIND. Replace all users.
	(def_vec): Remove.  Update all users.
	* gengtype-state.c (type_lineloc): Handle TYPE_USER_STRUCT.
	(write_state_user_struct_type): New.
	(write_state_type): Call it.
	(read_state_user_struct_type): New.
	(read_state_type): Call it.
	* gengtype.c: Update copyright year.
	(dump_pair): Move declaration to the top.
	(dump_type): Likewise.
	(dump_type_list): Likewise.
	(dbgprint_count_type_at): Handle TYPE_USER_STRUCT.
	(create_user_defined_type): New.
	(resolve_typedef): Call it.
	(new_structure): Replace argument ISUNION with KIND.
	Change users to refer to KIND directly.
	Update all callers.
	(find_structure): Likewise.
	(set_gc_used_type): Handle TYPE_USER_STRUCT.
	(create_file): Update HDR to include new copyright year.
	(struct walk_type_data): Add field IN_PTR_FIELD.
	(output_mangled_typename): Handle TYPE_USER_STRUCT.
	(walk_type): Set D->IN_PTR_FILED when walking a TYPE_POINTER.
	Clear it afterwards.
	Handle TYPE_USER_STRUCT.
	(write_types_process_field): Handle TYPE_USER_STRUCT.
	(get_type_specifier): Move earlier in the file.
	(write_type_decl): New.
	(write_marker_function_name): New.
	(write_user_func_for_structure_ptr): New.
	(write_user_func_for_structure_body): New.
	(write_user_marking_functions): New.
	(write_func_for_structure): Call write_marker_function_name
	and write_type_decl.
	Do not call walk_type for TYPE_USER_STRUCT. Emit a call to the user
	function directly.
	Call write_user_marking_functions on TYPE_USER_STRUCTs.
	(write_types_local_user_process_field): New.
	(write_pch_user_walking_for_structure_body): New.
	(write_pch_user_walking_functions): New.
	(write_types_local_process_field): Handle TYPE_USER_STRUCT.
	(write_local_func_for_structure): Do not call walk_type for
	TYPE_USER_STRUCT. Instead, emit the call to gt_pch_nx directly.
	Call write_pch_user_walking_functions for TYPE_USER_STRUCTs.
	(write_root): Handle TYPE_USER_STRUCT.
	(vec_prefix_type): Remove.  Update all users.
	(note_def_vec): Remove.  Update all users.
	(dump_typekind): Handle TYPE_USER_STRUCT.
	(dump_type): Initialize SEEN_TYPES, if needed.
	Handle TYPE_USER_STRUCT.
	(dump_everything): Do not initialize SEEN_TYPES.
	* gengtype.h: Update copyright year.
	(enum typekind): Add TYPE_USER_STRUCT.
	(union_or_struct_p): Rename from UNION_OR_STRUCT_P.
	Convert into function.
	Add an overload taking const_type_p.
	Update all callers.
	(new_structure): Change second field to type enum typekind.
	Update all users.
	(find_structure): Likewise.
	(note_def_vec): Remove.
	(DEFVEC_OP): Remove.
	(DEFVEC_I): Remove.
	* ggc-page.c (gt_ggc_mx): Add entry points for marking
	'const char *&', 'unsigned char *&' and 'unsigned char&'.
	* ggc-zone.c (gt_ggc_mx): Add entry points for marking
	'const char *&' and 'unsigned char *&'.
	* stringpool.c (gt_pch_nx): Add entry points for marking
	'const char *&', 'unsigned char *&' and 'unsigned char&'.
	Add an entry point for the overload taking arguments 'unsigned char
	*', 'gt_pointer_operator' and 'void *'.
	* vec.h (struct vec_prefix): Remove GTY marker.
	(struct vec_t): Remove GTY((length)) attribute from field 'vec'.
	(gt_ggc_mx (vec_t<T> *)): New template function.
	(gt_pch_nx (vec_t<T> *)): New template function.
	(gt_pch_nx (vec_t<T *> *, gt_pointer_operator, void *)): New template
	function.
	(gt_pch_nx (vec_t<T> *, gt_pointer_operator, void *)): New template
	function.

Comments

Gabriel Dos Reis Aug. 8, 2012, 8:12 p.m. UTC | #1
hi Diego,

just a word on style in the documentation:

> +template<typename T>
> +void gt_pch_nx (TP<T> *tp)
> +@{
> +  extern void gt_pch_nx (T&);
> +
> +  /* This marks field 'fld' of type 'T'.  */
> +  gt_pch_nx (tp->fld);
> +@}

'extern'  declaration at local scope if considered an extremely
poor style in C++.  Furthermore, it does not interact
well with template instantiations and scope rules; plus
it does not work well when the function actually has an
internal linkage.

A proper way to bring a symbol into local scope is through
a using-declaration:

     using ::gt_pch_nx;

-- Gaby
Diego Novillo Aug. 8, 2012, 8:37 p.m. UTC | #2
On 12-08-08 16:12 , Gabriel Dos Reis wrote:
> hi Diego,
>
> just a word on style in the documentation:
>
>> +template<typename T>
>> +void gt_pch_nx (TP<T> *tp)
>> +@{
>> +  extern void gt_pch_nx (T&);
>> +
>> +  /* This marks field 'fld' of type 'T'.  */
>> +  gt_pch_nx (tp->fld);
>> +@}
>
> 'extern'  declaration at local scope if considered an extremely
> poor style in C++.  Furthermore, it does not interact
> well with template instantiations and scope rules; plus
> it does not work well when the function actually has an
> internal linkage.
>
> A proper way to bring a symbol into local scope is through
> a using-declaration:
>
>       using ::gt_pch_nx;

I struggled a bit with this. I need to tell the template function that 
there exists a free function gt_pch_nx that takes a T&. This is not 
something that any header file has at the point of this declaration.

The function gt_pch_nx(T&) is declared and defined later in one of the 
gt-*.h files.  This is another problem with the way that gengtype works 
today.

The using-declaration that you propose does not seem to give me what I 
want, though. How does it know that the function takes a T&?


Diego.
Gabriel Dos Reis Aug. 8, 2012, 8:47 p.m. UTC | #3
On Wed, Aug 8, 2012 at 3:37 PM, Diego Novillo <dnovillo@google.com> wrote:
> On 12-08-08 16:12 , Gabriel Dos Reis wrote:
>>
>> hi Diego,
>>
>> just a word on style in the documentation:
>>
>>> +template<typename T>
>>> +void gt_pch_nx (TP<T> *tp)
>>> +@{
>>> +  extern void gt_pch_nx (T&);
>>> +
>>> +  /* This marks field 'fld' of type 'T'.  */
>>> +  gt_pch_nx (tp->fld);
>>> +@}
>>
>>
>> 'extern'  declaration at local scope if considered an extremely
>> poor style in C++.  Furthermore, it does not interact
>> well with template instantiations and scope rules; plus
>> it does not work well when the function actually has an
>> internal linkage.
>>
>> A proper way to bring a symbol into local scope is through
>> a using-declaration:
>>
>>       using ::gt_pch_nx;
>
>
> I struggled a bit with this. I need to tell the template function that there
> exists a free function gt_pch_nx that takes a T&. This is not something that
> any header file has at the point of this declaration.
>
> The function gt_pch_nx(T&) is declared and defined later in one of the
> gt-*.h files.  This is another problem with the way that gengtype works
> today.
>
> The using-declaration that you propose does not seem to give me what I want,
> though. How does it know that the function takes a T&?

So, if the issue that the function does not exist at the point of the template
definition, but will definitely exist at the point where it is instantiated
because of inclusion of a header file (later or in a different
translation unit),
then the usual way is to write no declaration at all.  The compiler will perform
a lookup at the point of instantiation and resolve the name
appropriate, or error.

you can just write:

void gt_pch_nx (TP<T> *tp)
{
     /* This marks field 'fld' of type 'T'.  */
     gt_pch_nx (tp->fld);

}

Am I understanding you correctly?

-- Gaby
Diego Novillo Aug. 8, 2012, 8:58 p.m. UTC | #4
On Wed, Aug 8, 2012 at 4:47 PM, Gabriel Dos Reis
<gdr@integrable-solutions.net> wrote:

> So, if the issue that the function does not exist at the point of the template
> definition, but will definitely exist at the point where it is instantiated
> because of inclusion of a header file (later or in a different
> translation unit),
> then the usual way is to write no declaration at all.  The compiler will perform
> a lookup at the point of instantiation and resolve the name
> appropriate, or error.

>
> you can just write:
>
> void gt_pch_nx (TP<T> *tp)
> {
>      /* This marks field 'fld' of type 'T'.  */
>      gt_pch_nx (tp->fld);
>
> }

Oh, but if I do that I get the error

In file included from tree.h:29:0,
                 from cp/tree.c:28:
vec.h: In instantiation of 'void gt_ggc_mx(vec_t<T>*) [with T = tree_node*]':
./gt-cp-tree.h:571:59:   required from here
vec.h:180:5: error: no matching function for call to 'gt_ggc_mx(tree_node*&)'
     gt_ggc_mx (v->vec[i]);
     ^

Because no declaration for gt_ggc_mx(tree_node *) exists at that
point.  It will exist in some other header file that's been generated
by gengtype (which is included at the *end* of the .c file).


Diego.
Gabriel Dos Reis Aug. 8, 2012, 9:25 p.m. UTC | #5
On Wed, Aug 8, 2012 at 3:58 PM, Diego Novillo <dnovillo@google.com> wrote:
> On Wed, Aug 8, 2012 at 4:47 PM, Gabriel Dos Reis
> <gdr@integrable-solutions.net> wrote:
>
>> So, if the issue that the function does not exist at the point of the template
>> definition, but will definitely exist at the point where it is instantiated
>> because of inclusion of a header file (later or in a different
>> translation unit),
>> then the usual way is to write no declaration at all.  The compiler will perform
>> a lookup at the point of instantiation and resolve the name
>> appropriate, or error.
>
>>
>> you can just write:
>>
>> void gt_pch_nx (TP<T> *tp)
>> {
>>      /* This marks field 'fld' of type 'T'.  */
>>      gt_pch_nx (tp->fld);
>>
>> }
>
> Oh, but if I do that I get the error
>
> In file included from tree.h:29:0,
>                  from cp/tree.c:28:
> vec.h: In instantiation of 'void gt_ggc_mx(vec_t<T>*) [with T = tree_node*]':
> ./gt-cp-tree.h:571:59:   required from here
> vec.h:180:5: error: no matching function for call to 'gt_ggc_mx(tree_node*&)'
>      gt_ggc_mx (v->vec[i]);
>      ^
>
> Because no declaration for gt_ggc_mx(tree_node *) exists at that
> point.  It will exist in some other header file that's been generated
> by gengtype (which is included at the *end* of the .c file).
>

Aha, so it is an ordering issue, e.g. declarations being generated
after they have been seen used in an instantiation.

We might want to consider  including the header file (that contains
only the declarations of the marking functions)  in the header
files that contain the GTY-marked type definition.  In this case, it would
be included near the end of tree.h

-- Gaby
Diego Novillo Aug. 8, 2012, 9:27 p.m. UTC | #6
On 12-08-08 17:25 , Gabriel Dos Reis wrote:

> Aha, so it is an ordering issue, e.g. declarations being generated
> after they have been seen used in an instantiation.
>
> We might want to consider  including the header file (that contains
> only the declarations of the marking functions)  in the header
> files that contain the GTY-marked type definition.  In this case, it would
> be included near the end of tree.h

Right. And that's the part of my plan that requires killing gengtype 
with fire first.  When I started down that path, it became a very messy 
re-write, so I decided it was better to do it in stages.


Diego.
Gabriel Dos Reis Aug. 8, 2012, 9:29 p.m. UTC | #7
On Wed, Aug 8, 2012 at 4:27 PM, Diego Novillo <dnovillo@google.com> wrote:
> On 12-08-08 17:25 , Gabriel Dos Reis wrote:
>
>> Aha, so it is an ordering issue, e.g. declarations being generated
>> after they have been seen used in an instantiation.
>>
>> We might want to consider  including the header file (that contains
>> only the declarations of the marking functions)  in the header
>> files that contain the GTY-marked type definition.  In this case, it would
>> be included near the end of tree.h
>
>
> Right. And that's the part of my plan that requires killing gengtype with
> fire first.  When I started down that path, it became a very messy re-write,
> so I decided it was better to do it in stages.

Aha, thanks.  (I am slowly catching up.)

-- Gaby
Laurynas Biveinis Aug. 9, 2012, 7:12 a.m. UTC | #8
Diego -

It's all good changes and your plan for future improvements sounds
good, including the part where gengtype is killed with fire.

> - Functions should be emitted in files that have access to the
>   structure where they were defined.  I'm not convinced that the
>   current multiplicity of gt-*.[ch] files is even necessary. However,
>   I would like the guidance of a gengtype maintainer. I don't think I
>   fully understand all of it.

Yes, I remember looking into splitting the output a few years ago. It
should be possible to split gtype-desc.h into header files to be
included in source header files defining the relevant types. I.e.
tree.h includes a generated gt-tree.h that provides allocator
definitions for the tree.h types. gtype-desc.h then would be left with
the master enum of all GTY-handled types. It should be also possible
to split gtype-desc.c into already-existing gt-foo.h too, although the
benefit of doing that is not as big I think.

> I've tested the patch on x86_64 with the page and zone collectors and
> with --enable-checking=gc,gcac (boy was that a slow mistake).

Might be also interesting to try valgrind. Good to hear the zone
collector hasn't bitrotten once again.

>         * doc/gty.texi: Document support for C++ templates and
>         user-provided markers.

The 1st node in this doc file needs s/C/C++/g and perhaps some more
explanation with an eye on C++.
Richard Biener Aug. 9, 2012, 9:03 a.m. UTC | #9
On Wed, Aug 8, 2012 at 11:27 PM, Diego Novillo <dnovillo@google.com> wrote:
> On 12-08-08 17:25 , Gabriel Dos Reis wrote:
>
>> Aha, so it is an ordering issue, e.g. declarations being generated
>> after they have been seen used in an instantiation.
>>
>> We might want to consider  including the header file (that contains
>> only the declarations of the marking functions)  in the header
>> files that contain the GTY-marked type definition.  In this case, it would
>> be included near the end of tree.h
>
>
> Right. And that's the part of my plan that requires killing gengtype with
> fire first.  When I started down that path, it became a very messy re-write,
> so I decided it was better to do it in stages.

But now with doing it in stages you end up with (this) first stage
that complicates
gengtype to support a very small subset of C++ types (namely the one special
case you need for vec.h).  Exactly what I did _not_ want!

I understood that you had the complete "killing of gengtype with fire" ready
(or almost ready).  Please finish it instead.

Thanks,
Richard.

>
> Diego.
Diego Novillo Aug. 9, 2012, 12:44 p.m. UTC | #10
On Thu, Aug 9, 2012 at 5:03 AM, Richard Guenther
<richard.guenther@gmail.com> wrote:

> But now with doing it in stages you end up with (this) first stage
> that complicates
> gengtype to support a very small subset of C++ types (namely the one special
> case you need for vec.h).  Exactly what I did _not_ want!

No. It supports all C++ types. All it needs is the user annotation.

> I understood that you had the complete "killing of gengtype with fire" ready
> (or almost ready).  Please finish it instead.

No. It was not even close. The full re-write will wait until the
branch is merged in trunk. It will touch too many files and the branch
is already hard to maintain as it is.

Adding support for explicit user annotations is easy enough. Patch coming up.


Diego.
Richard Biener Aug. 9, 2012, 1:05 p.m. UTC | #11
On Thu, Aug 9, 2012 at 2:44 PM, Diego Novillo <dnovillo@google.com> wrote:
> On Thu, Aug 9, 2012 at 5:03 AM, Richard Guenther
> <richard.guenther@gmail.com> wrote:
>
>> But now with doing it in stages you end up with (this) first stage
>> that complicates
>> gengtype to support a very small subset of C++ types (namely the one special
>> case you need for vec.h).  Exactly what I did _not_ want!
>
> No. It supports all C++ types. All it needs is the user annotation.

You said it only works for types in the template parameter list and there
you only support types (and not integers).  Which means I fail to see how
it works for VEC(tree).  As far as I understand you are not creating the
gt_pch_nx overloads for all GTYed types (which includes 'tree').  If you do
then I fail to see why it should be restricted at all?

>> I understood that you had the complete "killing of gengtype with fire" ready
>> (or almost ready).  Please finish it instead.
>
> No. It was not even close. The full re-write will wait until the
> branch is merged in trunk. It will touch too many files and the branch
> is already hard to maintain as it is.

Well.  So what are exactly the limitations?  If I can provide user-defined
gc routines for all C++ types and gengtype will pick them up automagically
when auto-generating gc routines for other types then fine.

What I do not understand is why you need a GTY(()) annotation on
C++ types with user-defined gc routines.  gengtype should treat all
types not marked with GTY(()) as having user-defined gc routines, no?

Richard.

> Adding support for explicit user annotations is easy enough. Patch coming up.
>
>
> Diego.
diff mbox

Patch

diff --git a/gcc/coretypes.h b/gcc/coretypes.h
index 02578f6..a2ca9c8 100644
--- a/gcc/coretypes.h
+++ b/gcc/coretypes.h
@@ -196,5 +196,9 @@  enum memmodel
 /* Suppose that higher bits are target dependant. */
 #define MEMMODEL_MASK ((1<<16)-1)
 
+/* Support for user-provided GGC and PCH markers.  The first parameter
+   is a pointer to a pointer, the second a cookie.  */
+typedef void (*gt_pointer_operator) (void *, void *);
+
 #endif /* coretypes.h */
 
diff --git a/gcc/ggc.h b/gcc/ggc.h
index d90eec2..5bfbab8 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -32,9 +32,6 @@  extern const char empty_string[];	/* empty string */
 /* Internal functions and data structures used by the GTY
    machinery, including the generated gt*.[hc] files.  */
 
-/* The first parameter is a pointer to a pointer, the second a cookie.  */
-typedef void (*gt_pointer_operator) (void *, void *);
-
 #include "gtype-desc.h"
 
 /* One of these applies its third parameter (with cookie in the fourth
diff --git a/gcc/doc/gty.texi b/gcc/doc/gty.texi
index cff3ffd..472738e 100644
--- a/gcc/doc/gty.texi
+++ b/gcc/doc/gty.texi
@@ -437,6 +437,82 @@  special case.  See @file{gengtype.c} for further details.  Avoid
 adding new special cases unless there is no other alternative.
 @end table
 
+@section Support for user-provided GC marking routines
+The garbage collector supports types for which no automatic marking
+code is generated.  For these types, the user is required to provide
+four functions: one to act as a marker for garbage collection, and
+three functions to act as marker and pointer walking for pre-compiled
+headers.
+
+User-provided types are currently supported for C++ template
+structures. When a template type @code{TP} is marked with @code{GTY},
+all instances of that type are considered user-provided types.  As
+such, the user needs to provide template functions to mark all the
+fields of the type.
+
+The following code snippets represent all the functions that need to
+be provided. Note that type @code{TP} may reference to more than one
+type. In these snippets, there is only one type @code{T}, but there
+could be more.
+
+@smallexample
+template<typename T>
+void gt_ggc_mx (TP<T> *tp)
+@{
+  extern void gt_ggc_mx (T&);
+
+  /* This marks field 'fld' of type 'T'.  */
+  gt_ggc_mx (tp->fld);
+@}
+
+template<typename T>
+void gt_pch_nx (TP<T> *tp)
+@{
+  extern void gt_pch_nx (T&);
+
+  /* This marks field 'fld' of type 'T'.  */
+  gt_pch_nx (tp->fld);
+@}
+
+template<typename T>
+void gt_pch_nx (TP<T *> *tp, gt_pointer_operator op, void *cookie)
+@{
+  /* For every field 'fld' of 'tp' with type 'T *', call the given
+     pointer operator.  */
+  op (&(tp->fld), cookie);
+@}
+
+template<typename T>
+void gt_pch_nx (TP<T> *tp, gt_pointer_operator, void *cookie)
+@{
+  extern void gt_pch_nx (T *, gt_pointer_operator, void *);
+
+  /* For every field 'fld' of 'tp' with type 'T', call the pointer
+     walker for all the fields of T.  */
+  gt_pch_nx (&(tp->fld), op, cookie);
+@}
+@end smallexample
+
+Support for user-defined types is currently limited. The following
+restrictions apply:
+
+@enumerate
+@item Type @code{TP} and all the argument types @code{T} must be
+marked with @code{GTY}.
+
+@item Type @code{TP} can only have type names in its argument list.
+
+@item The pointer walker functions are different for @code{TP<T>} and
+@code{TP<T *>}. In the case of @code{TP<T>}, references to
+@code{T} must be handled by calling @code{gt_pch_nx} (which
+will, in turn, walk all the pointers inside fields of @code{T}).
+In the case of @code{TP<T *>}, references to @code{T *} must be
+handled by calling the @code{op} function on the address of the
+pointer (see the code snippets above).
+
+@item Only template structures are supported at this time.
+@end enumerate
+
 @node GGC Roots
 @section Marking Roots for the Garbage Collector
 @cindex roots, marking
diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index edfd4a1..537acf6 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -1,6 +1,6 @@ 
 /* -*- indented-text -*- */
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2012
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -91,15 +91,6 @@  EOID	[^[:alnum:]_]
   BEGIN(in_struct);
   return STATIC;
 }
-
-^{HWS}DEF_VEC_[OP]/{EOID} {
-  BEGIN(in_struct);
-  return DEFVEC_OP;
-}
-^{HWS}DEF_VEC_I/{EOID} {
-  BEGIN(in_struct);
-  return DEFVEC_I;
-}
 }
 
 <in_struct>{
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
index 751edc8..b213585 100644
--- a/gcc/gengtype-parse.c
+++ b/gcc/gengtype-parse.c
@@ -1,5 +1,5 @@ 
 /* Process source files and output type information.
-   Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006, 2007, 2010, 2012 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -77,8 +77,6 @@  static const char *const token_names[] = {
   "struct",
   "enum",
   "VEC",
-  "DEF_VEC_[OP]",
-  "DEF_VEC_I",
   "...",
   "ptr_alias",
   "nested_ptr",
@@ -211,28 +209,70 @@  string_seq (void)
   return s1;
 }
 
-/* typedef_name: either an ID, or VEC(x,y) which is translated to VEC_x_y.
-   Use only where VEC(x,y) is legitimate, i.e. in positions where a
-   typedef name may appear.  */
+
+/* The caller has detected a template declaration that starts
+   with TMPL_NAME.  Parse up to the closing '>'.  This recognizes
+   simple template declarations of the form ID<ID1,ID2,...,IDn>.
+   It does not try to parse anything more sophisticated than that.
+
+   Returns the template declaration string "ID<ID1,ID2,...,IDn>".  */
+
+static const char *
+require_template_declaration (const char *tmpl_name)
+{
+  char *str;
+
+  /* Recognize the opening '<'.  */
+  require ('<');
+  str = concat (tmpl_name, "<", (char *) 0);
+
+  /* Read the comma-separated list of identifiers.  */
+  while (token () != '>')
+    {
+      const char *id = require2 (ID, ',');
+      if (id == NULL)
+	id = ",";
+      str = concat (str, id, (char *) 0);
+    }
+
+  /* Recognize the closing '>'.  */
+  require ('>');
+  str = concat (str, ">", (char *) 0);
+
+  return str;
+}
+
+
+/* typedef_name: either an ID, or VEC(x,y), or a template type
+   specification of the form ID<t1,t2,...,tn>.
+
+   FIXME cxx-conversion.  VEC(x,y) is currently translated to the
+   template 'vec_t<x>'.  This is to support the transition to C++ and
+   avoid re-writing all the 'VEC(x,y)' declarations in the code.  This
+   needs to be fixed when the branch is merged into trunk.  */
+
 static const char *
 typedef_name (void)
 {
   if (token () == VEC_TOKEN)
     {
-      const char *c1, *c2, *r;
+      const char *c1, *r;
       advance ();
       require ('(');
       c1 = require2 (ID, SCALAR);
       require (',');
-      c2 = require (ID);
+      require (ID);
       require (')');
       r = concat ("vec_t<", c1, ">", (char *) 0);
       free (CONST_CAST (char *, c1));
-      free (CONST_CAST (char *, c2));
       return r;
     }
+
+  const char *id = require (ID);
+  if (token () == '<')
+    return require_template_declaration (id);
   else
-    return require (ID);
+    return id;
 }
 
 /* Absorb a sequence of tokens delimited by balanced ()[]{}.  */
@@ -734,7 +774,7 @@  type (options_p *optsp, bool nested)
 	  GTY_BEFORE_ID,
 	  GTY_AFTER_ID
 	} is_gty = NO_GTY;
-	bool is_union = (token () == UNION);
+	enum typekind kind = (token () == UNION) ? TYPE_UNION : TYPE_STRUCT;
 	advance ();
 
 	/* Top-level structures that are not explicitly tagged GTY(())
@@ -775,14 +815,14 @@  type (options_p *optsp, bool nested)
 		advance ();
 		fields = struct_field_seq ();
 		require ('}');
-		return new_structure (s, is_union, &lexer_line, fields, opts);
+		return new_structure (s, kind, &lexer_line, fields, opts);
 	      }
 	  }
 	else if (token () == '{')
 	  consume_balanced ('{', '}');
 	if (opts)
 	  *optsp = opts;
-	return find_structure (s, is_union);
+	return find_structure (s, kind);
       }
 
     case ENUM:
@@ -890,30 +930,6 @@  extern_or_static (void)
     }
 }
 
-/* Definition of a generic VEC structure:
-
-   'DEF_VEC_[IPO]' '(' id ')' ';'
-
-   Scalar VECs require slightly different treatment than otherwise -
-   that's handled in note_def_vec, we just pass it along.*/
-static void
-def_vec (void)
-{
-  bool is_scalar = (token () == DEFVEC_I);
-  const char *type;
-
-  require2 (DEFVEC_OP, DEFVEC_I);
-  require ('(');
-  type = require2 (ID, SCALAR);
-  require (')');
-  require (';');
-
-  if (!type)
-    return;
-
-  note_def_vec (type, is_scalar, &lexer_line);
-}
-
 /* Parse the file FNAME for GC-relevant declarations and definitions.
    This is the only entry point to this file.  */
 void
@@ -938,11 +954,6 @@  parse_file (const char *fname)
 	  typedef_decl ();
 	  break;
 
-	case DEFVEC_OP:
-	case DEFVEC_I:
-	  def_vec ();
-	  break;
-
 	case EOF_TOKEN:
 	  goto eof;
 
diff --git a/gcc/gengtype-state.c b/gcc/gengtype-state.c
index d7ea9b4..c94d50b 100644
--- a/gcc/gengtype-state.c
+++ b/gcc/gengtype-state.c
@@ -51,6 +51,7 @@  type_lineloc (const_type_p ty)
     case TYPE_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
+    case TYPE_USER_STRUCT:
       return CONST_CAST (struct fileloc*, &ty->u.s.line);
     case TYPE_PARAM_STRUCT:
       return CONST_CAST (struct fileloc*, &ty->u.param_struct.line);
@@ -798,6 +799,22 @@  write_state_struct_type (type_p current)
   write_state_type (current->u.s.lang_struct);
 }
 
+/* Write a GTY user-defined struct type.  */
+static void
+write_state_user_struct_type (type_p current)
+{
+  DBGPRINTF ("user_struct type @ %p #%d '%s'", (void *) current,
+	     current->state_number, current->u.s.tag);
+  fprintf (state_file, "user_struct ");
+  write_state_common_type_content (current);
+  if (current->u.s.tag != NULL)
+    write_state_a_string (current->u.s.tag);
+  else
+    fprintf (state_file, "nil");
+  write_state_fileloc (type_lineloc (current));
+  write_state_fields (current->u.s.fields);
+}
+
 /* write a GTY union type.  */
 static void
 write_state_union_type (type_p current)
@@ -828,7 +845,7 @@  write_state_lang_struct_type (type_p current)
       DBGPRINTF ("homonymous #%d hty @ %p #%d '%s'", nbhomontype,
 		 (void *) hty, hty->state_number, hty->u.s.tag);
       /* Every member of the homonymous list should have the same tag.  */
-      gcc_assert (UNION_OR_STRUCT_P (hty));
+      gcc_assert (union_or_struct_p (hty));
       gcc_assert (hty->u.s.lang_struct == current);
       if (!homoname)
 	homoname = hty->u.s.tag;
@@ -947,6 +964,9 @@  write_state_type (type_p current)
 	case TYPE_STRUCT:
 	  write_state_struct_type (current);
 	  break;
+	case TYPE_USER_STRUCT:
+	  write_state_user_struct_type (current);
+	  break;
 	case TYPE_UNION:
 	  write_state_union_type (current);
 	  break;
@@ -1365,6 +1385,42 @@  read_state_struct_type (type_p type)
 }
 
 
+/* Read a GTY-ed user-provided struct TYPE.  */
+
+static void
+read_state_user_struct_type (type_p type)
+{
+  struct state_token_st *t0;
+
+  type->kind = TYPE_USER_STRUCT;
+  read_state_common_type_content (type);
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      if (state_token_is_name (t0, "nil"))
+	{
+	  type->u.s.tag = NULL;
+	  DBGPRINTF ("read anonymous struct type @%p #%d",
+		     (void *) type, type->state_number);
+	}
+      else
+	{
+	  type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+	  DBGPRINTF ("read struct type @%p #%d '%s'",
+		     (void *) type, type->state_number, type->u.s.tag);
+	}
+
+      next_state_tokens (1);
+      read_state_fileloc (&(type->u.s.line));
+      read_state_fields (&(type->u.s.fields));
+    }
+  else
+    {
+      fatal_reading_state (t0, "Bad tag in user-struct type");
+    }
+}
+
+
 /* Read a GTY-ed union type.  */
 static void
 read_state_union_type (type_p type)
@@ -1655,6 +1711,12 @@  read_state_type (type_p *current)
 	      next_state_tokens (1);
 	      read_state_array_type (*current);
 	    }
+	  else if (state_token_is_name (t0, "user_struct"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_user_struct_type (*current);
+	    }
 	  else
 	    fatal_reading_state (t0, "bad type in (!type");
 	}
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 986e3fe..baf2f28 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -1,5 +1,6 @@ 
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011,
+   2012
    Free Software Foundation, Inc.
 
    This file is part of GCC.
@@ -89,6 +91,10 @@  static const char *get_file_realbasename (const input_file *);
 
 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.  */
@@ -166,6 +172,7 @@  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_user_struct = 0;
   type_p p = NULL;
   for (p = t; p; p = p->next)
     {
@@ -181,6 +188,9 @@  dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
 	case TYPE_STRUCT:
 	  nb_struct++;
 	  break;
+	case TYPE_USER_STRUCT:
+	  nb_user_struct++;
+	  break;
 	case TYPE_UNION:
 	  nb_union++;
 	  break;
@@ -211,6 +221,8 @@  dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
   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_user_struct > 0)
+    fprintf (stderr, "@@%%@@ %d user_structs\n", nb_user_struct);
   fprintf (stderr, "\n");
 }
 #endif /* ENABLE_CHECKING */
@@ -539,6 +551,50 @@  do_scalar_typedef (const char *s, struct fileloc *pos)
   do_typedef (s, &scalar_nonchar, pos);
 }
 
+
+/* Define TYPE_NAME to be a user defined type at location POS.  */
+
+static type_p
+create_user_defined_type (const char *type_name, struct fileloc *pos)
+{
+  type_p ty = find_structure (type_name, 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 preteding 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.  */
+      char *arg = open_bracket + 1;
+      char *type_id = strtok (arg, ",>");
+      pair_p fields = 0;
+      while (type_id)
+	{
+	  /* Create a new field for every type found inside the template
+	     parameter list.  */
+	  const char *field_name = xstrdup (type_id);
+	  type_p arg_type = resolve_typedef (field_name, pos);
+	  fields = create_field_at (fields, arg_type, field_name, 0, pos);
+	  type_id = strtok (0, ",>");
+	}
+
+      /* Associate the field list to TY.  */
+      ty->u.s.fields = fields;
+    }
+  free (str);
+
+  return ty;
+}
+
+
 /* Return the type previously defined for S.  Use POS to report errors.  */
 
 type_p
@@ -548,20 +604,30 @@  resolve_typedef (const char *s, struct fileloc *pos)
   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" */
+
+  /* If we did not find a typedef registered, assume this is a name
+     for a user-defined type which will need to provide its own
+     marking functions.
+
+     FIXME cxx-conversion. Emit an error once explicit annotations
+     for marking user types are implemented.  */
+  return create_user_defined_type (s, pos);
 }
 
-/* Create and return a new structure with tag NAME (or a union iff
-   ISUNION is nonzero), at POS with fields FIELDS and options O.  */
+/* 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,
+new_structure (const char *name, enum typekind kind, struct fileloc *pos,
 	       pair_p fields, options_p o)
 {
   type_p si;
   type_p s = NULL;
   lang_bitmap bitmap = get_lang_bitmap (pos->file);
+  bool isunion = (kind == TYPE_UNION);
+
+  gcc_assert (union_or_struct_p (kind));
 
   for (si = structures; si != NULL; si = si->next)
     if (strcmp (name, si->u.s.tag) == 0 && UNION_P (si) == isunion)
@@ -621,7 +687,7 @@  new_structure (const char *name, int isunion, struct fileloc *pos,
       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;
@@ -633,14 +699,18 @@  new_structure (const char *name, int isunion, struct fileloc *pos,
   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;
+  bool isunion = (kind == TYPE_UNION);
+
+  gcc_assert (union_or_struct_p (kind));
 
   for (s = structures; s != NULL; s = s->next)
     if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion)
@@ -651,7 +721,7 @@  find_structure (const char *name, int isunion)
   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;
   return s;
@@ -851,7 +921,7 @@  create_optional_field_ (pair_p next, type_p type, const char *name,
   union_fields->opt = 
     create_string_option (union_fields->opt, "tag", "1");
   union_type = 
-    new_structure (xasprintf ("%s_%d", "fake_union", id++), 1,
+    new_structure (xasprintf ("%s_%d", "fake_union", id++), TYPE_UNION,
                    &lexer_line, union_fields, NULL);
 
   /* Create the field and give it the new fake union type.  Add a "desc"
@@ -993,16 +1063,16 @@  adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
 
   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 */
 
   {
@@ -1042,7 +1112,7 @@  adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
 	  note_flds->opt = 
 	    create_string_option (nodot, "tag", note_insn_name[c]);
       }
-    note_union_tp = new_structure ("rtx_def_note_subunion", 1,
+    note_union_tp = new_structure ("rtx_def_note_subunion", TYPE_UNION,
 				   &lexer_line, note_flds, NULL);
   }
   /* Create a type to represent the various forms of SYMBOL_REF_DATA.  */
@@ -1052,7 +1122,7 @@  adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
     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,
+    symbol_union_tp = new_structure ("rtx_def_symbol_subunion", TYPE_UNION,
 				     &lexer_line, sym_flds, NULL);
   }
   for (i = 0; i < NUM_RTX_CODE; i++)
@@ -1185,14 +1255,15 @@  adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
 	{
 	  /* 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);
 
       ftag = xstrdup (rtx_name[i]);
       for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
@@ -1200,7 +1271,8 @@  adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
       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);
 }
 
 /* Handle `special("tree_exp")'.  This is a special case for
@@ -1229,7 +1301,8 @@  adjust_field_tree_exp (type_p t, options_p opt ATTRIBUTE_UNUSED)
 				    "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);
 }
 
 /* Perform any special processing on a type T, about to become the type
@@ -1265,8 +1338,8 @@  adjust_field_type (type_p t, options_p opt)
       {
 	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 (!union_or_struct_p (t)
+	    && (t->kind != TYPE_POINTER || !union_or_struct_p (t->u.p)))
 	  {
 	    error_at_line (&lexer_line,
 			   "option `%s' may only be applied to structures or structure pointers",
@@ -1359,6 +1432,7 @@  set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
     {
     case TYPE_STRUCT:
     case TYPE_UNION:
+    case TYPE_USER_STRUCT:
       {
 	pair_p f;
 	int dummy;
@@ -1458,7 +1532,7 @@  static outf_p
 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, 2007, 2009, 2012 Free Software Foundation, Inc.\n",
     "\n",
     "This file is part of GCC.\n",
     "\n",
@@ -2166,7 +2240,6 @@  close_output_files (void)
 
   for (of = output_files; of; of = of->next)
     {
-
       if (!is_file_equal (of))
 	{
 	  FILE *newfile = NULL;
@@ -2293,6 +2366,7 @@  struct walk_type_data
   bool fn_wants_lvalue;
   bool in_record_p;
   int loopcounter;
+  bool in_ptr_field;
 };
 
 
@@ -2349,6 +2423,7 @@  output_mangled_typename (outf_p of, const_type_p t)
       case TYPE_STRUCT:
       case TYPE_UNION:
       case TYPE_LANG_STRUCT:
+      case TYPE_USER_STRUCT:
 	{
 	  const char *id_for_tag = filter_type_name (t->u.s.tag);
 	  oprintf (of, "%lu%s", (unsigned long) strlen (id_for_tag),
@@ -2412,6 +2487,7 @@  output_escaped_param (struct walk_type_data *d, const char *param,
 	}
 }
 
+
 /* 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
@@ -2492,7 +2568,7 @@  walk_type (type_p t, struct walk_type_data *d)
 
       if (pointer_p)
 	t = t->u.p;
-      if (!UNION_OR_STRUCT_P (t))
+      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);
@@ -2520,7 +2596,7 @@  walk_type (type_p t, struct walk_type_data *d)
     }
 
   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",
@@ -2543,6 +2619,7 @@  walk_type (type_p t, struct walk_type_data *d)
 
     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);
@@ -2570,7 +2647,7 @@  walk_type (type_p t, struct walk_type_data *d)
 
 	if (!length)
 	  {
-	    if (!UNION_OR_STRUCT_P (t->u.p)
+	    if (!union_or_struct_p (t->u.p)
 		&& t->u.p->kind != TYPE_PARAM_STRUCT)
 	      {
 		error_at_line (d->line,
@@ -2583,7 +2660,7 @@  walk_type (type_p t, struct walk_type_data *d)
 	      {
 		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 "
@@ -2657,6 +2734,7 @@  walk_type (type_p t, struct walk_type_data *d)
 	    d->indent -= 2;
 	    oprintf (d->of, "%*s}\n", d->indent, "");
 	  }
+	d->in_ptr_field = false;
       }
       break;
 
@@ -2940,6 +3018,10 @@  walk_type (type_p t, struct walk_type_data *d)
       }
       break;
 
+    case TYPE_USER_STRUCT:
+      d->process_field (t, d);
+      break;
+
     default:
       gcc_unreachable ();
     }
@@ -2997,7 +3079,7 @@  write_types_process_field (type_p f, const struct walk_type_data *d)
 	      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)
+	  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);
@@ -3017,13 +3099,27 @@  write_types_process_field (type_p f, const struct walk_type_data *d)
     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:
@@ -3044,7 +3140,7 @@  output_type_enum (outf_p of, type_p s)
       oprintf (of, ", gt_e_");
       output_mangled_typename (of, s);
     }
-  else if (UNION_OR_STRUCT_P (s) && s->u.s.line.file != NULL)
+  else if (union_or_struct_p (s) && s->u.s.line.file != NULL)
     {
       oprintf (of, ", gt_ggc_e_");
       output_mangled_typename (of, s);
@@ -3062,13 +3158,13 @@  get_output_file_for_structure (const_type_p s, type_p *param)
   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))
+	&& 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
@@ -3076,13 +3172,185 @@  get_output_file_for_structure (const_type_p s, type_p *param)
   return get_output_file_with_visibility (CONST_CAST (input_file*, fn));
 }
 
+
+/* 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 if (s->kind == TYPE_PARAM_STRUCT)
+    {
+      oprintf (of, "gt_%s_", prefix);
+      output_mangled_typename (of, s);
+    }
+  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.
+   PREFIX is the prefix to use to distinguish ggc and pch markers.  */
+
+static void
+write_user_func_for_structure_ptr (outf_p of, type_p s, const char *prefix)
+{
+  /* Parameterized structures are not supported in user markers. There
+     is no way for the marker function to know which specific type
+     to use to generate the call to the void * entry point.  For
+     instance, a marker for struct htab may need to call different
+     routines to mark the fields, depending on the paramN_is attributes.
+
+     A user-defined marker that accepts 'struct htab' as its argument
+     would not know which variant to call. Generating several entry
+     points accepting 'struct htab' would cause multiply-defined
+     errors during compilation.  */
+  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;
+      }
+
+  oprintf (of, "\nvoid\n");
+  oprintf (of, "gt_%sx (", 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 : s, 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 char *prefix,
+			      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, prefix);
+	}
+      else if (union_or_struct_p (fld_type))
+	write_user_func_for_structure_body (fld_type, prefix, d);
+    }
+}
+
+
 /* For S, a structure that's part of ORIG_S, and using parameters
    PARAM, 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,
@@ -3131,27 +3399,19 @@  write_func_for_structure (type_p orig_s, type_p s, type_p *param,
 
   oprintf (d.of, "\n");
   oprintf (d.of, "void\n");
-  if (param == NULL)
-    {
-      const char *id_for_tag = filter_type_name (orig_s->u.s.tag);
-      oprintf (d.of, "gt_%sx_%s", wtd->prefix, id_for_tag);
-      if (id_for_tag != orig_s->u.s.tag)
-	free (CONST_CAST(char *, id_for_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);
+    {
+      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);
@@ -3234,9 +3494,17 @@  write_func_for_structure (type_p orig_s, type_p s, type_p *param,
     {
       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)
     {
@@ -3249,8 +3517,12 @@  write_func_for_structure (type_p orig_s, type_p s, type_p *param,
   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->prefix, &d);
 }
 
+
 /* Write out marker routines for STRUCTURES and PARAM_STRUCTS.  */
 
 static void
@@ -3261,9 +3533,10 @@  write_types (outf_p output_header, type_p structures, type_p param_structs,
   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)
       {
@@ -3434,6 +3707,90 @@  static const struct write_types_data pch_wtd = {
 
 /* Write out the local pointer-walking routines.  */
 
+/* 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_user_process_field (type_p f, const struct walk_type_data *d)
+{
+  switch (f->kind)
+    {
+    case TYPE_POINTER:
+    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;
+
+    default:
+      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
@@ -3452,6 +3809,16 @@  write_types_local_process_field (type_p f, const struct walk_type_data *d)
       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;
 
@@ -3460,6 +3827,7 @@  write_types_local_process_field (type_p f, const struct walk_type_data *d)
     }
 }
 
+
 /* 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
@@ -3493,12 +3861,27 @@  write_local_func_for_structure (const_type_p orig_s, type_p s, type_p *param)
 	   "\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);
+  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);
 }
 
 /* Write out local marker routines for STRUCTURES and PARAM_STRUCTS.  */
@@ -3510,6 +3893,7 @@  write_local (outf_p output_header, type_p structures, type_p param_structs)
 
   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)
@@ -3589,15 +3973,15 @@  write_local (outf_p output_header, type_p structures, type_p param_structs)
 /* 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"))))))
+  ((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.  */
@@ -3619,7 +4003,7 @@  write_enum_defn (type_p structures, type_p param_structs)
 	nbstruct++;
 	DBGPRINTF ("write_enum_defn s @ %p nbstruct %d",
 		   (void*) s, nbstruct);
-	if (UNION_OR_STRUCT_P (s))
+	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_");
@@ -3905,6 +4289,11 @@  write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
       }
       break;
 
+    case TYPE_USER_STRUCT:
+      write_root (f, v, type->u.a.p, name, has_length, line, if_marked,
+		  emit_pch);
+      break;
+
     case TYPE_POINTER:
       {
 	type_p tp;
@@ -3914,7 +4303,7 @@  write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
 
 	tp = type->u.p;
 
-	if (!has_length && UNION_OR_STRUCT_P (tp))
+	if (!has_length && union_or_struct_p (tp))
 	  {
 	    const char *id_for_tag = filter_type_name (tp->u.s.tag);
 	    oprintf (f, "    &gt_ggc_mx_%s,\n", id_for_tag);
@@ -3938,7 +4327,7 @@  write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
 	      oprintf (f, ",\n    NULL");
 	  }
 	else if (has_length
-		 && (tp->kind == TYPE_POINTER || UNION_OR_STRUCT_P (tp)))
+		 && (tp->kind == TYPE_POINTER || union_or_struct_p (tp)))
 	  {
 	    oprintf (f, "    &gt_ggc_ma_%s,\n", name);
 	    if (emit_pch)
@@ -4179,7 +4568,8 @@  write_roots (pair_p variables, bool emit_pch)
 	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))
+	  || v->type->u.p->u.param_struct.stru != find_structure ("htab",
+	                                                          TYPE_STRUCT))
 	{
 	  error_at_line (&v->line,
 			 "if_marked option used but not hash table");
@@ -4282,77 +4672,6 @@  write_roots (pair_p variables, bool emit_pch)
   finish_root_table (flp, "pch_rs", "LAST_GGC_ROOT_TAB", "ggc_root_tab",
 		     "gt_pch_scalar_rtab");
 }
-/* Record the definition of the vec_prefix structure, as defined in vec.h:
-
-   struct vec_prefix GTY(()) {
-   unsigned num;
-   unsigned alloc;
-   };  */
-static type_p
-vec_prefix_type (void)
-{
-  static type_p prefix_type = NULL;
-  if (prefix_type == NULL)
-    {
-      pair_p fields;
-      static struct fileloc pos = { NULL, 0 };
-      type_p len_ty = create_scalar_type ("unsigned");
-      pos.file = input_file_by_name (__FILE__); pos.line = __LINE__;
-      fields = create_field_at (0, len_ty, "alloc", 0, &pos);
-      fields = create_field_at (fields, len_ty, "num", 0, &pos);
-      prefix_type = new_structure ("vec_prefix", 0, &pos, fields, 0);
-      prefix_type->u.s.bitmap = -1;
-    }
-  return prefix_type;
-}
-
-/* Record the definition of a generic VEC structure, as if we had expanded
-   the macros in vec.h:
-
-   typedef struct VEC_<type>_base GTY(()) {
-   struct vec_prefix prefix;
-   <type> GTY((length ("%h.prefix.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;
-  const char *name = concat ("vec_t<", type_name, ">", (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.prefix.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, vec_prefix_type (), "prefix", 0, pos);
-
-  do_typedef (name, new_structure (name, 0, pos, fields, 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.  */
 
@@ -4421,7 +4740,7 @@  write_typed_struct_alloc_def (outf_p f,
 			      enum alloc_quantity quantity,
 			      enum alloc_zone zone)
 {
-  gcc_assert (UNION_OR_STRUCT_P (s));
+  gcc_assert (union_or_struct_p (s));
   write_typed_alloc_def (f, variable_size_p (s), get_type_specifier (s),
                          s->u.s.tag, allocator_type, quantity, zone);
 }
@@ -4456,7 +4775,7 @@  write_typed_alloc_defns (outf_p f,
     {
       if (!USED_BY_TYPED_GC_P (s))
 	continue;
-      gcc_assert (UNION_OR_STRUCT_P (s));
+      gcc_assert (union_or_struct_p (s));
       /* In plugin mode onput output ggc_alloc macro definitions
 	 relevant to plugin input files.  */
       if (nb_plugin_files > 0 
@@ -4520,6 +4839,7 @@  output_typename (outf_p of, const_type_p t)
       output_typename (of, t->u.p);
       break;
     case TYPE_STRUCT:
+    case TYPE_USER_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
       oprintf (of, "%s", t->u.s.tag);
@@ -4578,10 +4898,6 @@  write_splay_tree_allocators (const_type_p param_structs)
       }
 }
 
-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.  */
@@ -4601,6 +4917,9 @@  dump_typekind (int indent, enum typekind kind)
     case TYPE_STRUCT:
       printf ("TYPE_STRUCT");
       break;
+    case TYPE_USER_STRUCT:
+      printf ("TYPE_USER_STRUCT");
+      break;
     case TYPE_UNION:
       printf ("TYPE_UNION");
       break;
@@ -4696,8 +5015,7 @@  dump_type_u_s (int indent, type_p t)
 {
   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, ' ');
@@ -4768,6 +5086,9 @@  dump_type (int indent, type_p t)
 {
   PTR *slot;
 
+  if (seen_types == NULL)
+    seen_types = htab_create (100, htab_hash_pointer, htab_eq_pointer, NULL);
+
   printf ("%*cType at %p: ", indent, ' ', (void *) t);
   slot = htab_find_slot (seen_types, t, INSERT);
   if (*slot != NULL)
@@ -4793,6 +5114,7 @@  dump_type (int indent, type_p t)
     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:
@@ -4852,11 +5174,12 @@  dump_structures (const char *name, type_p structures)
 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);
 }
 
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index 1ff4e3f..2ca0e4e 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -1,5 +1,5 @@ 
 /* Process source files and output type information.
-   Copyright (C) 2002, 2003, 2004, 2007, 2008, 2010, 2011 
+   Copyright (C) 2002, 2003, 2004, 2007, 2008, 2010, 2011, 2012
    Free Software Foundation, Inc.
 
    This file is part of GCC.
@@ -143,11 +143,14 @@  enum typekind {
   TYPE_LANG_STRUCT,     /* GCC front-end language specific structs.
                            Various languages may have homonymous but
                            different structs.  */
-  TYPE_PARAM_STRUCT     /* Type for parametrized structs, e.g. hash_t
+  TYPE_PARAM_STRUCT,    /* Type for parametrized structs, e.g. hash_t
                            hash-tables, ...  See (param_is, use_param,
                            param1_is, param2_is,... use_param1,
                            use_param_2,... use_params) GTY
                            options.  */
+  TYPE_USER_STRUCT	/* User defined type.  Walkers and markers for
+			   this type are assumed to be provided by the
+			   user.  */
 };
 
 /* Discriminating kind for options.  */
@@ -319,19 +322,27 @@  extern struct type scalar_char;
 
 /* Test if a type is a union, either a plain one or a language
    specific one.  */
-#define UNION_P(x)                                      \
-    ((x)->kind == TYPE_UNION ||                         \
-     ((x)->kind == TYPE_LANG_STRUCT                     \
-      && (x)->u.s.lang_struct->kind == TYPE_UNION))
+#define UNION_P(x)					\
+    ((x)->kind == TYPE_UNION				\
+     || ((x)->kind == TYPE_LANG_STRUCT			\
+         && (x)->u.s.lang_struct->kind == TYPE_UNION))
 
 /* Test if a type is a union or a structure, perhaps a language
    specific one.  */
-#define UNION_OR_STRUCT_P(x)			\
-    ((x)->kind == TYPE_UNION 			\
-     || (x)->kind == TYPE_STRUCT		\
-     || (x)->kind == TYPE_LANG_STRUCT)
-
+static inline bool
+union_or_struct_p (enum typekind kind)
+{
+  return (kind == TYPE_UNION
+	  || kind == TYPE_STRUCT
+          || kind == TYPE_LANG_STRUCT
+	  || kind == TYPE_USER_STRUCT);
+}
 
+static inline bool
+union_or_struct_p (const_type_p x)
+{
+  return union_or_struct_p (x->kind);
+}
 
 /* Give the file location of a type, if any. */
 static inline struct fileloc* 
@@ -339,7 +350,7 @@  type_fileloc (type_p t)
 {
   if (!t) 
     return NULL;
-  if (UNION_OR_STRUCT_P(t))
+  if (union_or_struct_p (t))
     return &t->u.s.line;
   if  (t->kind == TYPE_PARAM_STRUCT)
     return &t->u.param_struct.line;
@@ -410,10 +421,10 @@  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 type_p new_structure (const char *name, int isunion,
+extern type_p new_structure (const char *name, enum typekind kind,
 			     struct fileloc *pos, pair_p fields,
 			     options_p o);
-extern type_p find_structure (const char *s, int isunion);
+extern type_p find_structure (const char *s, enum typekind kind);
 extern type_p create_scalar_type (const char *name);
 extern type_p create_pointer (type_p t);
 extern type_p create_array (type_p t, const char *len);
@@ -424,8 +435,6 @@  extern pair_p nreverse_pairs (pair_p list);
 extern type_p adjust_field_type (type_p, options_p);
 extern void note_variable (const char *s, type_p t, options_p o,
 			   struct fileloc *pos);
-extern void note_def_vec (const char *type_name, bool is_scalar,
-			  struct fileloc *pos);
 
 /* Lexer and parser routines.  */
 extern int yylex (const char **yylval);
@@ -451,8 +460,6 @@  enum
     STRUCT,
     ENUM,
     VEC_TOKEN,
-    DEFVEC_OP,
-    DEFVEC_I,
     ELLIPSIS,
     PTR_ALIAS,
     NESTED_PTR,
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index ff23092..15e5a67 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -1445,6 +1445,26 @@  gt_ggc_m_S (const void *p)
   return;
 }
 
+
+/* User-callable entry point for marking string X.  */
+
+void
+gt_ggc_mx (const char *& x)
+{
+  gt_ggc_m_S (x);
+}
+
+void
+gt_ggc_mx (unsigned char *& x)
+{
+  gt_ggc_m_S (x);
+}
+
+void
+gt_ggc_mx (unsigned char& x ATTRIBUTE_UNUSED)
+{
+}
+
 /* If P is not marked, marks it and return false.  Otherwise return true.
    P must have been allocated by the GC allocator; it mustn't point to
    static objects, stack variables, or memory allocated with malloc.  */
diff --git a/gcc/ggc-zone.c b/gcc/ggc-zone.c
index 5257ada..a422b5c 100644
--- a/gcc/ggc-zone.c
+++ b/gcc/ggc-zone.c
@@ -1517,6 +1517,21 @@  gt_ggc_m_S (const void *p)
   ggc_set_mark (p);
 }
 
+
+/* User-callable entry point for marking string X.  */
+
+void
+gt_ggc_mx (const char *& x)
+{
+  gt_ggc_m_S (x);
+}
+
+void
+gt_ggc_mx (unsigned char *& x)
+{
+  gt_ggc_m_S (x);
+}
+
 /* If P is not marked, mark it and return false.  Otherwise return true.
    P must have been allocated by the GC allocator; it mustn't point to
    static objects, stack variables, or memory allocated with malloc.  */
diff --git a/gcc/stringpool.c b/gcc/stringpool.c
index c567587..281e550 100644
--- a/gcc/stringpool.c
+++ b/gcc/stringpool.c
@@ -210,6 +210,32 @@  gt_pch_n_S (const void *x)
   gt_pch_note_object (CONST_CAST (void *, x), CONST_CAST (void *, x),
 		      &gt_pch_p_S, gt_types_enum_last);
 }
+
+
+/* User-callable entry point for marking string X.  */
+
+void
+gt_pch_nx (const char *& x)
+{
+  gt_pch_n_S (x);
+}
+
+void
+gt_pch_nx (unsigned char *& x)
+{
+  gt_pch_n_S (x);
+}
+
+void
+gt_pch_nx (unsigned char& x ATTRIBUTE_UNUSED)
+{
+}
+
+void
+gt_pch_nx (unsigned char *x, gt_pointer_operator op, void *cookie)
+{
+  op (x, cookie);
+}
 
 /* Handle saving and restoring the string pool for PCH.  */
 
diff --git a/gcc/vec.h b/gcc/vec.h
index cc7e819..725e34d 100644
--- a/gcc/vec.h
+++ b/gcc/vec.h
@@ -156,7 +156,7 @@  extern void vec_assert_fail (const char *, const char * VEC_CHECK_DECL)
 
 enum vec_allocation_t { heap, gc, stack };
 
-struct GTY(()) vec_prefix
+struct vec_prefix
 {
   unsigned num;
   unsigned alloc;
@@ -167,9 +167,50 @@  template<typename T>
 struct GTY(()) vec_t
 {
   vec_prefix prefix;
-  T GTY((length ("%h.prefix.num"))) vec[1];
+  T vec[1];
 };
 
+/* Garbage collection support for vec_t.  */
+
+template<typename T>
+void
+gt_ggc_mx (vec_t<T> *v)
+{
+  extern void gt_ggc_mx (T&);
+  for (unsigned i = 0; i < v->prefix.num; i++)
+    gt_ggc_mx (v->vec[i]);
+}
+
+
+/* PCH support for vec_t.  */
+
+template<typename T>
+void
+gt_pch_nx (vec_t<T> *v)
+{
+  extern void gt_pch_nx (T&);
+  for (unsigned i = 0; i < v->prefix.num; i++)
+    gt_pch_nx (v->vec[i]);
+}
+
+template<typename T>
+void
+gt_pch_nx (vec_t<T *> *v, gt_pointer_operator op, void *cookie)
+{
+  for (unsigned i = 0; i < v->prefix.num; i++)
+    op (&(v->vec[i]), cookie);
+}
+
+template<typename T>
+void
+gt_pch_nx (vec_t<T> *v, gt_pointer_operator op, void *cookie)
+{
+  extern void gt_pch_nx (T *, gt_pointer_operator, void *);
+  for (unsigned i = 0; i < v->prefix.num; i++)
+    gt_pch_nx (&(v->vec[i]), op, cookie);
+}
+
+
 /* FIXME cxx-conversion.  Remove these definitions and update all
    calling sites.  */
 /* Vector of integer-like object.  */