diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index bf18bae..23cec6b 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/gengtype-lex.l b/gcc/gengtype-lex.l
index 537acf6..5788a6a 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -108,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 b213585..03ee781 100644
--- a/gcc/gengtype-parse.c
+++ b/gcc/gengtype-parse.c
@@ -499,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 ();
@@ -733,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:

@@ -805,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;
@@ -812,9 +829,20 @@ 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 ('}');
+		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);
  	      }
  	  }
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index 2ca0e4e..4a178ec 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -463,6 +463,7 @@ enum
      ELLIPSIS,
      PTR_ALIAS,
      NESTED_PTR,
+    USER_GTY,
      PARAM_IS,
      NUM,
      SCALAR,
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index e4cf076..b734781 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -7836,3 +7836,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);
+}
