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