Patchwork Merge C++ conversion into trunk (3/6 - gengtype C++ support)

login
register
mail settings
Submitter Diego Novillo
Date Aug. 12, 2012, 8:13 p.m.
Message ID <20120812201300.GA14743@google.com>
Download mbox | patch
Permalink /patch/176799/
State New
Headers show

Comments

Diego Novillo - Aug. 12, 2012, 8:13 p.m.
This merges the changes needed for supporting C++ types in
gengtype.

See http://gcc.gnu.org/ml/gcc-patches/2012-08/msg00711.html for
details.


Diego.

2012-08-12   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.

	* basic-block.h (struct edge_def): Mark GTY((user)).
	Remove all GTY markers from fields.
	(gt_ggc_mx): Declare.
	(gt_pch_nx): Declare.
	* tree-cfg.c (gt_ggc_mx): New.
	(gt_pch_nx): New.

	* gengtype-lex.l (USER_GTY): Add pattern for "user".
	* gengtype-parse.c (option): Handle USER_GTY.
	(opts_have): New.
	(type): Call it.
	If the keyword 'user' is used, do not walk the fields
	of the structure.
	* gengtype.h (USER_GTY): Add.
	* doc/gty.texi: Update.
Laurynas Biveinis - Aug. 14, 2012, 5:39 a.m.
Diego -

I have some relatively minor comments. In general, the these changes
and the adjusted GTY doc intro blurb you sent in the other email are
OK with the minor comments addressed and if no objections from global
maintainers.

>         (walk_type): Set D->IN_PTR_FILED when walking a TYPE_POINTER.

"FIELD"

> +fields is completely handled by user-provided routines.  Section
> +@ref{User GC} for details on what functions need to be provided.

"See Section ... " ?

> +code is generated.  For these types, the user is required to provide
> +three functions: one to act as a marker for garbage collection, and
> +two functions to act as marker and pointer walking for pre-compiled
> +headers.

s/walking/walker ?

> +In general, each marker @code{M} should call @code{M} for every
> +pointer field in the structure.  Fields that are not allocated in GC
> +or are not pointers can be ignored.

"must be ignored"

> +create_user_defined_type (const char *type_name, struct fileloc *pos)
...
> +     template by preteding that each type is a field of TY.  This is needed to

pretending

> @@ -548,20 +603,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);

Are "explicit annotations for marking user types" referring to GTY((user))?

> +static const char *
> +filter_type_name (const char *type_name)
> +{

Maybe this function should return const-less char *? The casts to cast
the const away for freeing it look a bit awkward.

> +      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));

For example, here.

> diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
> index d3d186d..f43d0c2 100644
> --- a/gcc/ggc-page.c
> +++ b/gcc/ggc-page.c
> @@ -1441,6 +1441,26 @@ gt_ggc_m_S (const void *p)
>    return;
>  }
>
> +
> +/* User-callable entry point for marking string X.  */

"points"

> +
> +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 baf8076..3fe0dd2 100644
> --- a/gcc/ggc-zone.c
> +++ b/gcc/ggc-zone.c
> @@ -1508,6 +1508,26 @@ gt_ggc_m_S (const void *p)
>    ggc_set_mark (p);
>  }
>
> +
> +/* User-callable entry point for marking string X.  */

"points"

> diff --git a/gcc/stringpool.c b/gcc/stringpool.c
> index 747db17..281e550 100644
> --- a/gcc/stringpool.c
> +++ b/gcc/stringpool.c
> @@ -49,7 +49,7 @@ static const char digit_vector[] = {
>
>  struct ht *ident_hash;
>
> -static hashnode alloc_node (hash_table *);
> +static hashnode alloc_node (cpp_hash_table *);
>  static int mark_ident (struct cpp_reader *, hashnode, const void *);
>
>  static void *
> @@ -70,7 +70,7 @@ init_stringpool (void)
>
>  /* Allocate a hash node.  */
>  static hashnode
> -alloc_node (hash_table *table ATTRIBUTE_UNUSED)
> +alloc_node (cpp_hash_table *table ATTRIBUTE_UNUSED)
>  {
>    return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
>  }

These changes are not in the ChangeLog, are they intentional?

> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c

> +/* Garbage collection support for edge_def.  */
> +
> +extern void gt_ggc_mx (tree&);
> +extern void gt_ggc_mx (gimple&);
> +extern void gt_ggc_mx (rtx&);
> +extern void gt_ggc_mx (basic_block&);

> +/* PCH support for edge_def.  */
> +
> +extern void gt_pch_nx (tree&);
> +extern void gt_pch_nx (gimple&);
> +extern void gt_pch_nx (rtx&);
> +extern void gt_pch_nx (basic_block&);

I wonder if these externs can be avoided by including gtype-desc.h. I
realize that gtype-desc.h declares a lot of stuff, but if tree-cfg.c
already declares GC roots, then it already should be pulling that
header in in through gt-tree-cfg.h.

--
Laurynas
Dodji Seketeli - Aug. 14, 2012, 8:38 a.m.
Hello Diego,

Just some minor comments.

Diego Novillo <dnovillo@google.com> a écrit:

[...]

> +@section User-provided marking routines for template types
> +When a template type @code{TP} is marked with @code{GTY}, all
> +instances of that type are considered user-provided types.  This means
> +that the individual instances of @code{TP} do not need to marked with

s/to marked/to be marked/

> +@code{GTY}.  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)
> +@{

Just for my education, for the marking routines in general why having
the parameter tp be a pointer, rather than TP<T> &tp ?

> +  extern void gt_ggc_mx (T&);
> +
> +  /* This marks field 'fld' of type 'T'.  */
> +  gt_ggc_mx (tp->fld);
> +@}

[...]
Diego Novillo - Aug. 14, 2012, 1:19 p.m.
On 12-08-14 01:39 , Laurynas Biveinis wrote:

>>          (walk_type): Set D->IN_PTR_FILED when walking a TYPE_POINTER.
>
> "FIELD"

Done.

>> +fields is completely handled by user-provided routines.  Section
>> +@ref{User GC} for details on what functions need to be provided.
>
> "See Section ... " ?

Done.

>> +code is generated.  For these types, the user is required to provide
>> +three functions: one to act as a marker for garbage collection, and
>> +two functions to act as marker and pointer walking for pre-compiled
>> +headers.
>
> s/walking/walker ?

Done.

>> +In general, each marker @code{M} should call @code{M} for every
>> +pointer field in the structure.  Fields that are not allocated in GC
>> +or are not pointers can be ignored.
>
> "must be ignored"

Done.

>> +create_user_defined_type (const char *type_name, struct fileloc *pos)
> ...
>> +     template by preteding that each type is a field of TY.  This is needed to
>
> pretending

Done.

>
>> @@ -548,20 +603,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);
>
> Are "explicit annotations for marking user types" referring to GTY((user))?

Actually, the comment is wrong.  When we don't recognize the type, we 
simply consider this type as implicitly user-defined.

>
>> +static const char *
>> +filter_type_name (const char *type_name)
>> +{
>
> Maybe this function should return const-less char *? The casts to cast
> the const away for freeing it look a bit awkward.

Done.

>> +
>> +/* User-callable entry point for marking string X.  */
>
> "points"

Done.

>> +
>> +/* User-callable entry point for marking string X.  */
>
> "points"

Done.

>> --- a/gcc/stringpool.c
>> +++ b/gcc/stringpool.c
>> @@ -49,7 +49,7 @@ static const char digit_vector[] = {
>>
>>   struct ht *ident_hash;
>>
>> -static hashnode alloc_node (hash_table *);
>> +static hashnode alloc_node (cpp_hash_table *);
>>   static int mark_ident (struct cpp_reader *, hashnode, const void *);
>>
>>   static void *
>> @@ -70,7 +70,7 @@ init_stringpool (void)
>>
>>   /* Allocate a hash node.  */
>>   static hashnode
>> -alloc_node (hash_table *table ATTRIBUTE_UNUSED)
>> +alloc_node (cpp_hash_table *table ATTRIBUTE_UNUSED)
>>   {
>>     return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
>>   }
>
> These changes are not in the ChangeLog, are they intentional?

Sorry.  They belong to the hash table patch.  Both patches touched the 
same file and I missed splitting these hunks.

>
>> diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
>
>> +/* Garbage collection support for edge_def.  */
>> +
>> +extern void gt_ggc_mx (tree&);
>> +extern void gt_ggc_mx (gimple&);
>> +extern void gt_ggc_mx (rtx&);
>> +extern void gt_ggc_mx (basic_block&);
>
>> +/* PCH support for edge_def.  */
>> +
>> +extern void gt_pch_nx (tree&);
>> +extern void gt_pch_nx (gimple&);
>> +extern void gt_pch_nx (rtx&);
>> +extern void gt_pch_nx (basic_block&);
>
> I wonder if these externs can be avoided by including gtype-desc.h. I
> realize that gtype-desc.h declares a lot of stuff, but if tree-cfg.c
> already declares GC roots, then it already should be pulling that
> header in in through gt-tree-cfg.h.

Not really.  These are never really defined anywhere.  They are emitted 
in gtype-desc.c, but we never emit prototypes for them.  Going down that 
road ends up in turning gengtype upside-down.


Diego.
Diego Novillo - Aug. 14, 2012, 1:21 p.m.
On 12-08-14 04:38 , Dodji Seketeli wrote:
> Hello Diego,
>
> Just some minor comments.
>
> Diego Novillo <dnovillo@google.com> a écrit:
>
> [...]
>
>> +@section User-provided marking routines for template types
>> +When a template type @code{TP} is marked with @code{GTY}, all
>> +instances of that type are considered user-provided types.  This means
>> +that the individual instances of @code{TP} do not need to marked with
>
> s/to marked/to be marked/

Done.

>> +@code{GTY}.  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)
>> +@{
>
> Just for my education, for the marking routines in general why having
> the parameter tp be a pointer, rather than TP<T> &tp ?

It would be better, yes.  But since gengtype does not generate files 
that include the proper headers, we can't.  We can get away with forward 
declaring the struct names and passing pointers around, but the minute 
you add a type reference, all hell breaks loose.


Diego.
Diego Novillo - Aug. 14, 2012, 1:28 p.m.
On 12-08-14 09:19 , Diego Novillo wrote:

>>
>>> +static const char *
>>> +filter_type_name (const char *type_name)
>>> +{
>>
>> Maybe this function should return const-less char *? The casts to cast
>> the const away for freeing it look a bit awkward.
>
> Done.

I was too quick.  The problem here is that we sometimes return 
TYPE_NAME, which must be 'const char *'.  So, the ugliness is unavoidable.


Diego.

Patch

diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index dff06e4..7d1ad4f 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -33,19 +33,19 @@  along with GCC; see the file COPYING3.  If not see
 typedef HOST_WIDEST_INT gcov_type;
 
 /* Control flow edge information.  */
-struct GTY(()) edge_def {
+struct GTY((user)) edge_def {
   /* The two blocks at the ends of the edge.  */
   basic_block src;
   basic_block dest;
 
   /* Instructions queued on the edge.  */
   union edge_def_insns {
-    gimple_seq GTY ((tag ("true"))) g;
-    rtx GTY ((tag ("false"))) r;
-  } GTY ((desc ("current_ir_type () == IR_GIMPLE"))) insns;
+    gimple_seq g;
+    rtx r;
+  } insns;
 
   /* Auxiliary info specific to a pass.  */
-  PTR GTY ((skip (""))) aux;
+  PTR aux;
 
   /* Location of any goto implicit in the edge and associated BLOCK.  */
   tree goto_block;
@@ -65,6 +65,11 @@  DEF_VEC_P(edge);
 DEF_VEC_ALLOC_P(edge,gc);
 DEF_VEC_ALLOC_P(edge,heap);
 
+/* Garbage collection and PCH support for edge_def.  */
+extern void gt_ggc_mx (edge_def *e);
+extern void gt_pch_nx (edge_def *e);
+extern void gt_pch_nx (edge_def *e, gt_pointer_operator, void *);
+
 /* Masks for edge.flags.  */
 #define DEF_EDGE_FLAG(NAME,IDX) EDGE_##NAME = 1 << IDX ,
 enum cfg_edge_flags {
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/doc/gty.texi b/gcc/doc/gty.texi
index ad0423a..3754b75 100644
--- a/gcc/doc/gty.texi
+++ b/gcc/doc/gty.texi
@@ -68,6 +68,7 @@  These don't need to be marked.
 @menu
 * GTY Options::         What goes inside a @code{GTY(())}.
 * GGC Roots::           Making global variables GGC roots.
+* User GC::		Adding user-provided GC marking routines.
 * Files::               How the generated files work.
 * Invoking the garbage collector::   How to invoke the garbage collector.
 * Troubleshooting::     When something does not work as expected.
@@ -440,8 +441,128 @@  The @code{special} option is used to mark types that have to be dealt
 with by special case machinery.  The parameter is the name of the
 special case.  See @file{gengtype.c} for further details.  Avoid
 adding new special cases unless there is no other alternative.
+
+@findex user
+@item user
+
+The @code{user} option indicates that the code to mark structure
+fields is completely handled by user-provided routines.  Section
+@ref{User GC} for details on what functions need to be provided.
 @end table
 
+@node User GC
+@section Support for user-provided GC marking routines
+@cindex user gc
+The garbage collector supports types for which no automatic marking
+code is generated.  For these types, the user is required to provide
+three functions: one to act as a marker for garbage collection, and
+two functions to act as marker and pointer walking for pre-compiled
+headers.
+
+Given a structure @code{struct GTY((user)) my_struct}, the following functions
+should be defined to mark @code{my_struct}:
+
+@smallexample
+void gt_ggc_mx (my_struct *p)
+@{
+  /* This marks field 'fld'.  */
+  gt_ggc_mx (p->fld);
+@}
+
+void gt_pch_nx (my_struct *p)
+@{
+  /* This marks field 'fld'.  */
+  gt_pch_nx (tp->fld);
+@}
+
+void gt_pch_nx (my_struct *p, gt_pointer_operator op, void *cookie)
+@{
+  /* For every field 'fld', call the given pointer operator.  */
+  op (&(tp->fld), cookie);
+@}
+@end smallexample
+
+In general, each marker @code{M} should call @code{M} for every
+pointer field in the structure.  Fields that are not allocated in GC
+or are not pointers can be ignored.
+
+For embedded lists (e.g., structures with a @code{next} or @code{prev}
+pointer), the marker must follow the chain and mark every element in
+it.
+
+Note that the rules for the pointer walker @code{gt_pch_nx (my_struct
+*, gt_pointer_operator, void *)} are slightly different.  In this
+case, the operation @code{op} must be applied to the @emph{address} of
+every pointer field.
+
+@section User-provided marking routines for template types
+When a template type @code{TP} is marked with @code{GTY}, all
+instances of that type are considered user-provided types.  This means
+that the individual instances of @code{TP} do not need to marked with
+@code{GTY}.  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).
+@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 a71cce0..5788a6a 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,19 +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;
-}
-^{HWS}DEF_VEC_ALLOC_[IOP]/{EOID} {
-  BEGIN(in_struct);
-  return DEFVEC_ALLOC;
-}
 }
 
 <in_struct>{
@@ -121,6 +108,7 @@  EOID	[^[:alnum:]_]
 "enum"/{EOID}			{ return ENUM; }
 "ptr_alias"/{EOID}	  	{ return PTR_ALIAS; }
 "nested_ptr"/{EOID}		{ return NESTED_PTR; }
+"user"/{EOID}			{ return USER_GTY; }
 [0-9]+				{ return NUM; }
 "param"[0-9]*"_is"/{EOID}		{
   *yylval = XDUPVAR (const char, yytext, yyleng, yyleng+1);
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
index c0ad403..03ee781 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,9 +77,6 @@  static const char *const token_names[] = {
   "struct",
   "enum",
   "VEC",
-  "DEF_VEC_[OP]",
-  "DEF_VEC_I",
-  "DEF_VEC_ALLOC_[IOP]",
   "...",
   "ptr_alias",
   "nested_ptr",
@@ -212,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_", c1, "_", c2, (char *) 0);
+      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 ()[]{}.  */
@@ -460,6 +499,10 @@  option (options_p prev)
       advance ();
       return nestedptr_optvalue (prev);
 
+    case USER_GTY:
+      advance ();
+      return create_string_option (prev, "user", "");
+
     default:
       parse_error ("expected an option keyword, have %s", print_cur_token ());
       advance ();
@@ -694,6 +737,18 @@  struct_field_seq (void)
   return nreverse_pairs (f);
 }
 
+/* Return true if OPTS contain the option named STR.  */
+
+static bool
+opts_have (options_p opts, const char *str)
+{
+  for (options_p opt = opts; opt; opt = opt->next)
+    if (strcmp (opt->name, str) == 0)
+      return true;
+  return false;
+}
+
+
 /* This is called type(), but what it parses (sort of) is what C calls
    declaration-specifiers and specifier-qualifier-list:
 
@@ -735,7 +790,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(())
@@ -766,6 +821,7 @@  type (options_p *optsp, bool nested)
 
 	if (is_gty)
 	  {
+	    bool is_user_gty = opts_have (opts, "user");
 	    if (token () == '{')
 	      {
 		pair_p fields;
@@ -773,17 +829,28 @@  type (options_p *optsp, bool nested)
 		if (is_gty == GTY_AFTER_ID)
 		  parse_error ("GTY must be specified before identifier");
 
-		advance ();
-		fields = struct_field_seq ();
-		require ('}');
-		return new_structure (s, is_union, &lexer_line, fields, opts);
+		if (!is_user_gty)
+		  {
+		    advance ();
+		    fields = struct_field_seq ();
+		    require ('}');
+		  }
+		else
+		  {
+		    /* Do not look inside user defined structures.  */
+		    fields = NULL;
+		    kind = TYPE_USER_STRUCT;
+		    consume_balanced ('{', '}');
+		  }
+
+		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:
@@ -891,55 +958,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);
-  note_def_vec_alloc (type, "none", &lexer_line);
-}
-
-/* Definition of an allocation strategy for a VEC structure:
-
-   'DEF_VEC_ALLOC_[IPO]' '(' id ',' id ')' ';'
-
-   For purposes of gengtype, this just declares a wrapper structure.  */
-static void
-def_vec_alloc (void)
-{
-  const char *type, *astrat;
-
-  require (DEFVEC_ALLOC);
-  require ('(');
-  type = require2 (ID, SCALAR);
-  require (',');
-  astrat = require (ID);
-  require (')');
-  require (';');
-
-  if (!type || !astrat)
-    return;
-
-  note_def_vec_alloc (type, astrat, &lexer_line);
-}
-
 /* Parse the file FNAME for GC-relevant declarations and definitions.
    This is the only entry point to this file.  */
 void
@@ -964,15 +982,6 @@  parse_file (const char *fname)
 	  typedef_decl ();
 	  break;
 
-	case DEFVEC_OP:
-	case DEFVEC_I:
-	  def_vec ();
-	  break;
-
-	case DEFVEC_ALLOC:
-	  def_vec_alloc ();
-	  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 a4aa725..a3b0c2b 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 +90,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 +171,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 +187,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 +220,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 +550,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 +603,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 +686,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 +698,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 +720,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 +920,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 +1062,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 +1111,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 +1121,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 +1254,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 +1270,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 +1300,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
@@ -1275,8 +1347,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",
@@ -1369,6 +1441,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;
@@ -1468,7 +1541,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",
@@ -2176,7 +2249,6 @@  close_output_files (void)
 
   for (of = output_files; of; of = of->next)
     {
-
       if (!is_file_equal (of))
 	{
 	  FILE *newfile = NULL;
@@ -2303,9 +2375,38 @@  struct walk_type_data
   bool fn_wants_lvalue;
   bool in_record_p;
   int loopcounter;
+  bool in_ptr_field;
   bool have_this_obj;
 };
 
+
+/* Given a string TYPE_NAME, representing a C++ typename, return a valid
+   pre-processor identifier to use in a #define directive.  This replaces
+   special characters used in C++ identifiers like '>', '<' and ':' with
+   '_'.
+
+   If no C++ special characters are found in TYPE_NAME, return
+   TYPE_NAME.  Otherwise, return a copy of TYPE_NAME with the special
+   characters replaced with '_'.  In this case, the caller is
+   responsible for freeing the allocated string.  */
+
+static const char *
+filter_type_name (const char *type_name)
+{
+  if (strchr (type_name, '<') || strchr (type_name, ':'))
+    {
+      size_t i;
+      char *s = xstrdup (type_name);
+      for (i = 0; i < strlen (s); i++)
+	if (s[i] == '<' || s[i] == '>' || s[i] == ':')
+	  s[i] = '_';
+      return s;
+    }
+  else
+    return type_name;
+}
+
+
 /* Print a mangled name representing T to OF.  */
 
 static void
@@ -2332,8 +2433,14 @@  output_mangled_typename (outf_p of, const_type_p t)
       case TYPE_STRUCT:
       case TYPE_UNION:
       case TYPE_LANG_STRUCT:
-	oprintf (of, "%lu%s", (unsigned long) strlen (t->u.s.tag),
-		 t->u.s.tag);
+      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),
+		   id_for_tag);
+	  if (id_for_tag != t->u.s.tag)
+	    free (CONST_CAST(char *, id_for_tag));
+	}
 	break;
       case TYPE_PARAM_STRUCT:
 	{
@@ -2390,6 +2497,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
@@ -2470,7 +2578,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);
@@ -2498,7 +2606,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",
@@ -2521,6 +2629,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);
@@ -2548,7 +2657,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,
@@ -2561,7 +2670,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 "
@@ -2638,6 +2747,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;
 
@@ -2921,6 +3031,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 ();
     }
@@ -2978,7 +3092,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);
@@ -2998,13 +3112,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:
@@ -3025,7 +3153,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);
@@ -3043,13 +3171,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
@@ -3057,13 +3185,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,
@@ -3113,22 +3413,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)
-    oprintf (d.of, "gt_%sx_%s", wtd->prefix, orig_s->u.s.tag);
-  else
-    {
-      oprintf (d.of, "gt_%s_", wtd->prefix);
-      output_mangled_typename (d.of, orig_s);
-    }
+  write_marker_function_name (d.of, orig_s, wtd->prefix);
   oprintf (d.of, " (void *x_p)\n");
-  oprintf (d.of, "{\n");
-  oprintf (d.of, "  %s %s * %sx = (%s %s *)x_p;\n",
-	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag,
-	   chain_next == NULL ? "const " : "",
-	   s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+  oprintf (d.of, "{\n  ");
+  write_type_decl (d.of, s);
+  oprintf (d.of, " * %sx = (", chain_next == NULL ? "const " : "");
+  write_type_decl (d.of, s);
+  oprintf (d.of, " *)x_p;\n");
   if (chain_next != NULL)
-    oprintf (d.of, "  %s %s * xlimit = x;\n",
-	     s->kind == TYPE_UNION ? "union" : "struct", s->u.s.tag);
+    {
+      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);
@@ -3211,9 +3508,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)
     {
@@ -3226,8 +3531,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
@@ -3238,23 +3547,27 @@  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)
       {
 	options_p opt;
+	const char *s_id_for_tag;
 
 	if (s->gc_used == GC_MAYBE_POINTED_TO && s->u.s.line.file == NULL)
 	  continue;
 
+	s_id_for_tag = filter_type_name (s->u.s.tag);
+
 	oprintf (output_header, "#define gt_%s_", wtd->prefix);
 	output_mangled_typename (output_header, s);
 	oprintf (output_header, "(X) do { \\\n");
 	oprintf (output_header,
 		 "  if (X != NULL) gt_%sx_%s (X);\\\n", wtd->prefix,
-		 s->u.s.tag);
+		 s_id_for_tag);
 	oprintf (output_header, "  } while (0)\n");
 
 	for (opt = s->u.s.opt; opt; opt = opt->next)
@@ -3264,9 +3577,14 @@  write_types (outf_p output_header, type_p structures, type_p param_structs,
 	      const_type_p const t = (const_type_p) opt->info.type;
 	      if (t->kind == TYPE_STRUCT
 		  || t->kind == TYPE_UNION || t->kind == TYPE_LANG_STRUCT)
-		oprintf (output_header,
-			 "#define gt_%sx_%s gt_%sx_%s\n",
-			 wtd->prefix, s->u.s.tag, wtd->prefix, t->u.s.tag);
+		{
+		  const char *t_id_for_tag = filter_type_name (t->u.s.tag);
+		  oprintf (output_header,
+			   "#define gt_%sx_%s gt_%sx_%s\n",
+			   wtd->prefix, s->u.s.tag, wtd->prefix, t_id_for_tag);
+		  if (t_id_for_tag != t->u.s.tag)
+		    free (CONST_CAST(char *, t_id_for_tag));
+		}
 	      else
 		error_at_line (&s->u.s.line,
 			       "structure alias is not a structure");
@@ -3278,7 +3596,10 @@  write_types (outf_p output_header, type_p structures, type_p param_structs,
 	/* Declare the marker procedure only once.  */
 	oprintf (output_header,
 		 "extern void gt_%sx_%s (void *);\n",
-		 wtd->prefix, s->u.s.tag);
+		 wtd->prefix, s_id_for_tag);
+
+	if (s_id_for_tag != s->u.s.tag)
+	  free (CONST_CAST(char *, s_id_for_tag));
 
 	if (s->u.s.line.file == NULL)
 	  {
@@ -3400,6 +3721,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
@@ -3419,6 +3824,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;
 
@@ -3427,6 +3842,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
@@ -3460,13 +3876,29 @@  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;
   d.have_this_obj = true;
-  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.  */
@@ -3478,6 +3910,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)
@@ -3557,15 +3990,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.  */
@@ -3587,7 +4020,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_");
@@ -3873,6 +4306,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;
@@ -3882,13 +4320,16 @@  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))
 	  {
-	    oprintf (f, "    &gt_ggc_mx_%s,\n", tp->u.s.tag);
+	    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)
-	      oprintf (f, "    &gt_pch_nx_%s", tp->u.s.tag);
+	      oprintf (f, "    &gt_pch_nx_%s", id_for_tag);
 	    else
 	      oprintf (f, "    NULL");
+	    if (id_for_tag != tp->u.s.tag)
+	      free (CONST_CAST(char *, id_for_tag));
 	  }
 	else if (!has_length && tp->kind == TYPE_PARAM_STRUCT)
 	  {
@@ -3903,7 +4344,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)
@@ -4146,7 +4587,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");
@@ -4249,96 +4691,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_", type_name, "_base", (char *) 0);
-
-  if (is_scalar)
-    {
-      t = create_scalar_type (type_name);
-      o = 0;
-    }
-  else
-    {
-      t = resolve_typedef (type_name, pos);
-      o = create_string_option (0, "length", "%h.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);
-}
-
-/* Record the definition of an allocation-specific VEC structure, as if
-   we had expanded the macros in vec.h:
-
-   typedef struct VEC_<type>_<astrat> {
-     VEC_<type>_base base;
-   } VEC_<type>_<astrat>;
-*/
-void
-note_def_vec_alloc (const char *type, const char *astrat, struct fileloc *pos)
-{
-  const char *astratname = concat ("VEC_", type, "_", astrat, (char *) 0);
-  const char *basename = concat ("VEC_", type, "_base", (char *) 0);
-
-  pair_p field = create_field_at (0, resolve_typedef (basename, pos),
-				  "base", 0, pos);
-
-  do_typedef (astratname, new_structure (astratname, 0, pos, field, 0), pos);
-}
-
-/* Returns the specifier keyword for a string or union type S, empty string
-   otherwise.  */
-
-static const char *
-get_type_specifier (const type_p s)
-{
-  if (s->kind == TYPE_STRUCT || s->kind == TYPE_LANG_STRUCT)
-    return "struct ";
-  if (s->kind == TYPE_UNION)
-    return "union ";
-  return "";
-}
 
 /* TRUE if type S has the GTY variable_size annotation.  */
 
@@ -4374,8 +4726,10 @@  write_typed_alloc_def (outf_p f,
   bool two_args = variable_size && (quantity == vector);
   bool third_arg = ((zone == specific_zone)
 		    && (variable_size || (quantity == vector)));
+  const char *type_name_as_id;
   gcc_assert (f != NULL);
-  oprintf (f, "#define ggc_alloc_%s%s", allocator_type, type_name);
+  type_name_as_id = filter_type_name (type_name);
+  oprintf (f, "#define ggc_alloc_%s%s", allocator_type, type_name_as_id);
   oprintf (f, "(%s%s%s%s%s) ",
 	   (variable_size ? "SIZE" : ""),
 	   (two_args ? ", " : ""),
@@ -4392,6 +4746,8 @@  write_typed_alloc_def (outf_p f,
   if (quantity == vector)
     oprintf (f, ", n");
   oprintf (f, " MEM_STAT_INFO)))\n");
+  if (type_name_as_id != type_name)
+    free (CONST_CAST(char *, type_name_as_id));
 }
 
 /* Writes a typed allocator definition into output F for a struct or
@@ -4403,7 +4759,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);
 }
@@ -4438,7 +4794,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 
@@ -4502,6 +4858,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);
@@ -4560,10 +4917,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.  */
@@ -4583,6 +4936,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;
@@ -4678,8 +5034,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, ' ');
@@ -4750,6 +5105,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)
@@ -4775,6 +5133,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:
@@ -4834,11 +5193,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 560f7f3..4a178ec 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,10 +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);
-extern void note_def_vec_alloc (const char *type, const char *astrat,
-				struct fileloc *pos);
 
 /* Lexer and parser routines.  */
 extern int yylex (const char **yylval);
@@ -453,12 +460,10 @@  enum
     STRUCT,
     ENUM,
     VEC_TOKEN,
-    DEFVEC_OP,
-    DEFVEC_I,
-    DEFVEC_ALLOC,
     ELLIPSIS,
     PTR_ALIAS,
     NESTED_PTR,
+    USER_GTY,
     PARAM_IS,
     NUM,
     SCALAR,
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index d3d186d..f43d0c2 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -1441,6 +1441,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 baf8076..3fe0dd2 100644
--- a/gcc/ggc-zone.c
+++ b/gcc/ggc-zone.c
@@ -1508,6 +1508,26 @@  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);
+}
+
+void
+gt_ggc_mx (unsigned char& x ATTRIBUTE_UNUSED)
+{
+}
+
 /* 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/ggc.h b/gcc/ggc.h
index 59a996b..5f25a58 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/stringpool.c b/gcc/stringpool.c
index 747db17..281e550 100644
--- a/gcc/stringpool.c
+++ b/gcc/stringpool.c
@@ -49,7 +49,7 @@  static const char digit_vector[] = {
 
 struct ht *ident_hash;
 
-static hashnode alloc_node (hash_table *);
+static hashnode alloc_node (cpp_hash_table *);
 static int mark_ident (struct cpp_reader *, hashnode, const void *);
 
 static void *
@@ -70,7 +70,7 @@  init_stringpool (void)
 
 /* Allocate a hash node.  */
 static hashnode
-alloc_node (hash_table *table ATTRIBUTE_UNUSED)
+alloc_node (cpp_hash_table *table ATTRIBUTE_UNUSED)
 {
   return GCC_IDENT_TO_HT_IDENT (make_node (IDENTIFIER_NODE));
 }
@@ -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/tree-cfg.c b/gcc/tree-cfg.c
index a91b433..c88a9f9 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -7863,3 +7863,54 @@  struct gimple_opt_pass pass_warn_unused_result =
     0,					/* todo_flags_finish */
   }
 };
+
+
+/* Garbage collection support for edge_def.  */
+
+extern void gt_ggc_mx (tree&);
+extern void gt_ggc_mx (gimple&);
+extern void gt_ggc_mx (rtx&);
+extern void gt_ggc_mx (basic_block&);
+
+void
+gt_ggc_mx (edge_def *e)
+{
+  gt_ggc_mx (e->src);
+  gt_ggc_mx (e->dest);
+  if (current_ir_type () == IR_GIMPLE)
+    gt_ggc_mx (e->insns.g);
+  else
+    gt_ggc_mx (e->insns.r);
+  gt_ggc_mx (e->goto_block);
+}
+
+/* PCH support for edge_def.  */
+
+extern void gt_pch_nx (tree&);
+extern void gt_pch_nx (gimple&);
+extern void gt_pch_nx (rtx&);
+extern void gt_pch_nx (basic_block&);
+
+void
+gt_pch_nx (edge_def *e)
+{
+  gt_pch_nx (e->src);
+  gt_pch_nx (e->dest);
+  if (current_ir_type () == IR_GIMPLE)
+    gt_pch_nx (e->insns.g);
+  else
+    gt_pch_nx (e->insns.r);
+  gt_pch_nx (e->goto_block);
+}
+
+void
+gt_pch_nx (edge_def *e, gt_pointer_operator op, void *cookie)
+{
+  op (&(e->src), cookie);
+  op (&(e->dest), cookie);
+  if (current_ir_type () == IR_GIMPLE)
+    op (&(e->insns.g), cookie);
+  else
+    op (&(e->insns.r), cookie);
+  op (&(e->goto_block), cookie);
+}