Patchwork VEC re-write [patch 02/25]

login
register
mail settings
Submitter Diego Novillo
Date Nov. 15, 2012, 9:53 p.m.
Message ID <20121115215322.B2C10C0916@torture.tor.corp.google.com>
Download mbox | patch
Permalink /patch/199426/
State New
Headers show

Comments

Diego Novillo - Nov. 15, 2012, 9:53 p.m.
This patch removes the special handling for VEC() that used to exist in gengtype.
Additionally, it allows gengtype to recognize templates of more than
one argument and introduces the concept of an undefined type (useful
for template arguments that may or may not be types).

When a TYPE_UNDEFINED is reached, gengtype will ignore it if it
happens inside a type marked with GTY((user)).  Otherwise, it will
emit an error.

Finally, gengtype rejects root types marked GTY((user)) that are not
first class pointers.


2012-11-15  Diego Novillo  <dnovillo@google.com>

	* gengtype-lex.l (VEC): Remove.
	Add characters in the set [\!\>\.-].
	* gengtype-parse.c (token_names): Remove "VEC".
	(require_template_declaration): Remove handling of VEC_TOKEN.
	(type): Likewise.
	Call create_user_defined_type when parsing GTY((user)).
	* gengtype-state.c (type_lineloc): handle TYPE_UNDEFINED.
	(write_state_undefined_type): New.
	(write_state_type): Call write_state_undefined_type for
	TYPE_UNDEFINED.
	(read_state_type): Call read_state_undefined_type for
	TYPE_UNDEFINED.
	* gengtype.c (dbgprint_count_type_at): Handle TYPE_UNDEFINED.
	(create_user_defined_type): Make extern.
	(type_for_name): Factor out of resolve_typedef.
	(create_undefined_type): New
	(resolve_typedef): Call it when we cannot find a previous
	typedef and the type is not a template.
	(find_structure): Accept TYPE_UNDEFINED.
	(set_gc_used_type): Add argument ALLOWED_UNDEFINED_TYPES,
	default to false.
	Emit an error for TYPE_UNDEFINED unless LEVEL is GC_UNUSED or
	ALLOWED_UNDEFINED_TYPES is set.
	Set ALLOWED_UNDEFINED_TYPES to true for TYPE_USER_STRUCT.
	(filter_type_name): Accept templates with more than one
	argument.
	(output_mangled_typename): Handle TYPE_UNDEFINED
	(walk_type): Likewise.
	(write_types_process_field): Likewise.
	(write_func_for_structure): If CHAIN_NEXT is set, ORIG_S
	should not be a user-defined type.
	(write_types_local_user_process_field): Handle TYPE_ARRAY,
	TYPE_NONE and TYPE_UNDEFINED.
	(write_types_local_process_field): Likewise.
	(contains_scalar_p): Return 0 for TYPE_USER_STRUCT.
	(write_root): Reject user-defined types that are not pointers.
	Handle TYPE_NONE, TYPE_UNDEFINED, TYPE_UNION, TYPE_LANG_STRUCT
	and TYPE_PARAM_STRUCT.
	(output_typename): Handle TYPE_NONE, TYPE_UNDEFINED, and
	TYPE_ARRAY.
	(dump_typekind): Handle TYPE_UNDEFINED.
	* gengtype.h (enum typekind): Add TYPE_UNDEFINED.
	(create_user_defined_type): Declare.
	(enum gty_token): Remove VEC_TOKEN.
Laurynas Biveinis - Nov. 16, 2012, 3:09 p.m.
> 2012-11-15  Diego Novillo  <dnovillo@google.com>
>
>         * gengtype-lex.l (VEC): Remove.
>         Add characters in the set [\!\>\.-].
>         * gengtype-parse.c (token_names): Remove "VEC".
>         (require_template_declaration): Remove handling of VEC_TOKEN.
>         (type): Likewise.
>         Call create_user_defined_type when parsing GTY((user)).
>         * gengtype-state.c (type_lineloc): handle TYPE_UNDEFINED.
>         (write_state_undefined_type): New.
>         (write_state_type): Call write_state_undefined_type for
>         TYPE_UNDEFINED.
>         (read_state_type): Call read_state_undefined_type for
>         TYPE_UNDEFINED.
>         * gengtype.c (dbgprint_count_type_at): Handle TYPE_UNDEFINED.
>         (create_user_defined_type): Make extern.
>         (type_for_name): Factor out of resolve_typedef.
>         (create_undefined_type): New
>         (resolve_typedef): Call it when we cannot find a previous
>         typedef and the type is not a template.
>         (find_structure): Accept TYPE_UNDEFINED.
>         (set_gc_used_type): Add argument ALLOWED_UNDEFINED_TYPES,
>         default to false.
>         Emit an error for TYPE_UNDEFINED unless LEVEL is GC_UNUSED or
>         ALLOWED_UNDEFINED_TYPES is set.
>         Set ALLOWED_UNDEFINED_TYPES to true for TYPE_USER_STRUCT.
>         (filter_type_name): Accept templates with more than one
>         argument.
>         (output_mangled_typename): Handle TYPE_UNDEFINED
>         (walk_type): Likewise.
>         (write_types_process_field): Likewise.
>         (write_func_for_structure): If CHAIN_NEXT is set, ORIG_S
>         should not be a user-defined type.
>         (write_types_local_user_process_field): Handle TYPE_ARRAY,
>         TYPE_NONE and TYPE_UNDEFINED.
>         (write_types_local_process_field): Likewise.
>         (contains_scalar_p): Return 0 for TYPE_USER_STRUCT.
>         (write_root): Reject user-defined types that are not pointers.
>         Handle TYPE_NONE, TYPE_UNDEFINED, TYPE_UNION, TYPE_LANG_STRUCT
>         and TYPE_PARAM_STRUCT.
>         (output_typename): Handle TYPE_NONE, TYPE_UNDEFINED, and
>         TYPE_ARRAY.
>         (dump_typekind): Handle TYPE_UNDEFINED.
>         * gengtype.h (enum typekind): Add TYPE_UNDEFINED.
>         (create_user_defined_type): Declare.
>         (enum gty_token): Remove VEC_TOKEN.

OK.

Thanks,

Patch

diff --git a/gcc/gengtype-lex.l b/gcc/gengtype-lex.l
index fd80906..4c316a3 100644
--- a/gcc/gengtype-lex.l
+++ b/gcc/gengtype-lex.l
@@ -116,7 +116,6 @@  CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend
     return IGNORABLE_CXX_KEYWORD;
 }
 "GTY"/{EOID}			{ return GTY_TOKEN; }
-"VEC"/{EOID}			{ return VEC_TOKEN; }
 "union"/{EOID}			{ return UNION; }
 "struct"/{EOID}			{ return STRUCT; }
 "class"/{EOID}			{ return STRUCT; }
@@ -163,7 +162,7 @@  CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend
 }
 
 "..."				{ return ELLIPSIS; }
-[(){},*:<>;=%|+-]		{ return yytext[0]; }
+[(){},*:<>;=%|+\!\?\.-]		{ return yytext[0]; }
 
    /* ignore pp-directives */
 ^{HWS}"#"{HWS}[a-z_]+[^\n]*\n   {lexer_line.line++;}
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
index 5737a15..0b46661 100644
--- a/gcc/gengtype-parse.c
+++ b/gcc/gengtype-parse.c
@@ -76,7 +76,6 @@  static const char *const token_names[] = {
   "union",
   "struct",
   "enum",
-  "VEC",
   "...",
   "ptr_alias",
   "nested_ptr",
@@ -245,31 +244,12 @@  require_template_declaration (const char *tmpl_name)
 }
 
 
-/* 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.  */
+/* typedef_name: either an ID, or a template type
+   specification of the form ID<t1,t2,...,tn>.  */
 
 static const char *
 typedef_name (void)
 {
-  if (token () == VEC_TOKEN)
-    {
-      const char *c1, *r;
-      advance ();
-      require ('(');
-      c1 = require2 (ID, SCALAR);
-      require (',');
-      require (ID);
-      require (')');
-      r = concat ("vec_t<", c1, ">", (char *) 0);
-      free (CONST_CAST (char *, c1));
-      return r;
-    }
-
   const char *id = require (ID);
   if (token () == '<')
     return require_template_declaration (id);
@@ -826,7 +806,6 @@  type (options_p *optsp, bool nested)
       return create_scalar_type (s);
 
     case ID:
-    case VEC_TOKEN:
       s = typedef_name ();
       return resolve_typedef (s, &lexer_line);
 
@@ -907,6 +886,7 @@  type (options_p *optsp, bool nested)
 		    fields = NULL;
 		    kind = TYPE_USER_STRUCT;
 		    consume_balanced ('{', '}');
+		    return create_user_defined_type (s, &lexer_line);
 		  }
 
 		return new_structure (s, kind, &lexer_line, fields, opts);
diff --git a/gcc/gengtype-state.c b/gcc/gengtype-state.c
index e3317ec..8607ceb 100644
--- a/gcc/gengtype-state.c
+++ b/gcc/gengtype-state.c
@@ -52,6 +52,7 @@  type_lineloc (const_type_p ty)
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
     case TYPE_USER_STRUCT:
+    case TYPE_UNDEFINED:
       return CONST_CAST (struct fileloc*, &ty->u.s.line);
     case TYPE_PARAM_STRUCT:
       return CONST_CAST (struct fileloc*, &ty->u.param_struct.line);
@@ -770,6 +771,23 @@  write_state_string_type (type_p current)
     fatal ("Unexpected type in write_state_string_type");
 }
 
+/* Write an undefined type.  */
+static void
+write_state_undefined_type (type_p current)
+{
+  DBGPRINTF ("undefined type @ %p #%d '%s'", (void *) current,
+	     current->state_number, current->u.s.tag);
+  fprintf (state_file, "undefined ");
+  gcc_assert (current->gc_used == GC_UNUSED);
+  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));
+}
+
 
 /* Common code to write structure like types.  */
 static void
@@ -963,6 +981,9 @@  write_state_type (type_p current)
 	{
 	case TYPE_NONE:
 	  gcc_unreachable ();
+	case TYPE_UNDEFINED:
+	  write_state_undefined_type (current);
+	  break;
 	case TYPE_STRUCT:
 	  write_state_struct_type (current);
 	  break;
@@ -1345,6 +1366,40 @@  read_state_lang_bitmap (lang_bitmap *bitmap)
 }
 
 
+/* Read an undefined type.  */
+static void
+read_state_undefined_type (type_p type)
+{
+  struct state_token_st *t0;
+
+  type->kind = TYPE_UNDEFINED;
+  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 undefined type @%p #%d",
+		     (void *) type, type->state_number);
+	}
+      else
+	{
+	  type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+	  DBGPRINTF ("read undefined type @%p #%d '%s'",
+		     (void *) type, type->state_number, type->u.s.tag);
+	}
+
+      next_state_tokens (1);
+      read_state_fileloc (&(type->u.s.line));
+    }
+  else
+    {
+      fatal_reading_state (t0, "Bad tag in undefined type");
+    }
+}
+
+
 /* Read a GTY-ed struct type.  */
 static void
 read_state_struct_type (type_p type)
@@ -1673,6 +1728,12 @@  read_state_type (type_p *current)
 	      next_state_tokens (1);
 	      read_state_string_type (current);
 	    }
+	  else if (state_token_is_name (t0, "undefined"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_undefined_type (*current);
+	    }
 	  else if (state_token_is_name (t0, "struct"))
 	    {
 	      *current = XCNEW (struct type);
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index b9fbd96..b3f73fe 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -171,13 +171,15 @@  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;
+  int nb_user_struct = 0, nb_undefined = 0;
   type_p p = NULL;
   for (p = t; p; p = p->next)
     {
       nb_types++;
       switch (p->kind)
 	{
+	case TYPE_UNDEFINED:
+	  nb_undefined++;
 	case TYPE_SCALAR:
 	  nb_scalar++;
 	  break;
@@ -205,7 +207,7 @@  dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
 	case TYPE_PARAM_STRUCT:
 	  nb_param_struct++;
 	  break;
-	default:
+	case TYPE_NONE:
 	  gcc_unreachable ();
 	}
     }
@@ -222,6 +224,8 @@  dbgprint_count_type_at (const char *fil, int lin, const char *msg, type_p t)
 	     nb_lang_struct, nb_param_struct);
   if (nb_user_struct > 0)
     fprintf (stderr, "@@%%@@ %d user_structs\n", nb_user_struct);
+  if (nb_undefined > 0)
+    fprintf (stderr, "@@%%@@ %d undefined types\n", nb_undefined);
   fprintf (stderr, "\n");
 }
 #endif /* ENABLE_CHECKING */
@@ -553,7 +557,7 @@  do_scalar_typedef (const char *s, struct fileloc *pos)
 
 /* Define TYPE_NAME to be a user defined type at location POS.  */
 
-static type_p
+type_p
 create_user_defined_type (const char *type_name, struct fileloc *pos)
 {
   type_p ty = find_structure (type_name, TYPE_USER_STRUCT);
@@ -595,20 +599,58 @@  create_user_defined_type (const char *type_name, struct fileloc *pos)
 }
 
 
-/* Return the type previously defined for S.  Use POS to report errors.  */
+/* Given a typedef name S, return its associated type.  Return NULL if
+   S is not a registered type name.  */
 
-type_p
-resolve_typedef (const char *s, struct fileloc *pos)
+static type_p
+type_for_name (const char *s)
 {
   pair_p p;
   for (p = typedefs; p != NULL; p = p->next)
     if (strcmp (p->name, s) == 0)
       return p->type;
+  return NULL;
+}
+
+
+/* Create an undefined type with name S and location POS.  Return the
+   newly created type.  */
+
+static type_p
+create_undefined_type (const char *s, struct fileloc *pos)
+{
+  type_p ty = find_structure (s, TYPE_UNDEFINED);
+  ty->u.s.line = *pos;
+  ty->u.s.bitmap = get_lang_bitmap (pos->file);
+  do_typedef (s, ty, pos);
+  return ty;
+}
+
+
+/* Return the type previously defined for S.  Use POS to report errors.  */
 
-  /* 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.  */
-  return create_user_defined_type (s, pos);
+type_p
+resolve_typedef (const char *s, struct fileloc *pos)
+{
+  bool is_template_instance = (strchr (s, '<') != NULL);
+  type_p p = type_for_name (s);
+
+  /* If we did not find a typedef registered, generate a TYPE_UNDEFINED
+     type for regular type identifiers.  If the type identifier S is a
+     template instantiation, however, we treat it as a user defined
+     type.
+
+     FIXME, this is actually a limitation in gengtype.  Supporting
+     template types and their instances would require keeping separate
+     track of the basic types definition and its instances.  This
+     essentially forces all template classes in GC to be marked
+     GTY((user)).  */
+  if (!p)
+    p = (is_template_instance)
+	? create_user_defined_type (s, pos)
+	: create_undefined_type (s, pos);
+
+  return p;
 }
 
 
@@ -707,7 +749,7 @@  find_structure (const char *name, enum typekind kind)
   type_p s;
   bool isunion = (kind == TYPE_UNION);
 
-  gcc_assert (union_or_struct_p (kind));
+  gcc_assert (kind == TYPE_UNDEFINED || 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)
@@ -1397,7 +1439,8 @@  adjust_field_type (type_p t, options_p opt)
 }
 
 
-static void set_gc_used_type (type_p, enum gc_used_enum, type_p *);
+static void set_gc_used_type (type_p, enum gc_used_enum, type_p *,
+			      bool = false);
 static void set_gc_used (pair_p);
 
 /* Handle OPT for set_gc_used_type.  */
@@ -1427,9 +1470,31 @@  process_gc_options (options_p opt, enum gc_used_enum level, int *maybe_undef,
 }
 
 
-/* Set the gc_used field of T to LEVEL, and handle the types it references.  */
+/* Set the gc_used field of T to LEVEL, and handle the types it references.
+
+   If ALLOWED_UNDEFINED_TYPES is true, types of kind TYPE_UNDEFINED
+   are set to GC_UNUSED.  Otherwise, an error is emitted for
+   TYPE_UNDEFINED types.  This is used to support user-defined
+   template types with non-type arguments.
+
+   For instance, when we parse a template type with enum arguments
+   (e.g. MyType<AnotherType, EnumValue>), the parser created two
+   artificial fields for 'MyType', one for 'AnotherType', the other
+   one for 'EnumValue'.
+
+   At the time that we parse this type we don't know that 'EnumValue'
+   is really an enum value, so the parser creates a TYPE_UNDEFINED
+   type for it.  Since 'EnumValue' is never resolved to a known
+   structure, it will stay with TYPE_UNDEFINED.
+
+   Since 'MyType' is a TYPE_USER_STRUCT, we can simply ignore
+   'EnumValue'.  Generating marking code for it would cause
+   compilation failures since the marking routines assumes that
+   'EnumValue' is a type.  */
+
 static void
-set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
+set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM],
+		  bool allow_undefined_types)
 {
   if (t->gc_used >= level)
     return;
@@ -1445,6 +1510,7 @@  set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
 	pair_p f;
 	int dummy;
 	type_p dummy2;
+	bool allow_undefined_field_types = (t->kind == TYPE_USER_STRUCT);
 
 	process_gc_options (t->u.s.opt, level, &dummy, &dummy, &dummy, &dummy,
 			    &dummy2);
@@ -1472,11 +1538,21 @@  set_gc_used_type (type_p t, enum gc_used_enum level, type_p param[NUM_PARAM])
 	    else if (skip)
 	      ;			/* target type is not used through this field */
 	    else
-	      set_gc_used_type (f->type, GC_USED, pass_param ? param : NULL);
+	      set_gc_used_type (f->type, GC_USED, pass_param ? param : NULL,
+				allow_undefined_field_types);
 	  }
 	break;
       }
 
+    case TYPE_UNDEFINED:
+      if (level > GC_UNUSED)
+	{
+	  if (!allow_undefined_types)
+	    error_at_line (&t->u.s.line, "undefined type `%s'", t->u.s.tag);
+	  t->gc_used = GC_UNUSED;
+	}
+      break;
+
     case TYPE_POINTER:
       set_gc_used_type (t->u.p, GC_POINTED_TO, NULL);
       break;
@@ -2397,7 +2473,7 @@  filter_type_name (const char *type_name)
       size_t i;
       char *s = xstrdup (type_name);
       for (i = 0; i < strlen (s); i++)
-	if (s[i] == '<' || s[i] == '>' || s[i] == ':')
+	if (s[i] == '<' || s[i] == '>' || s[i] == ':' || s[i] == ',')
 	  s[i] = '_';
       return s;
     }
@@ -2417,6 +2493,7 @@  output_mangled_typename (outf_p of, const_type_p t)
     switch (t->kind)
       {
       case TYPE_NONE:
+      case TYPE_UNDEFINED:
 	gcc_unreachable ();
 	break;
       case TYPE_POINTER:
@@ -3042,7 +3119,8 @@  walk_type (type_p t, struct walk_type_data *d)
       d->process_field (t, d);
       break;
 
-    default:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
       gcc_unreachable ();
     }
 }
@@ -3059,6 +3137,7 @@  write_types_process_field (type_p f, const struct walk_type_data *d)
   switch (f->kind)
     {
     case TYPE_NONE:
+    case TYPE_UNDEFINED:
       gcc_unreachable ();
     case TYPE_POINTER:
       oprintf (d->of, "%*s%s (%s%s", d->indent, "",
@@ -3265,7 +3344,6 @@  write_marker_function_name (outf_p of, type_p s, const char *prefix)
     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.  */
@@ -3429,6 +3507,10 @@  write_func_for_structure (type_p orig_s, type_p s, type_p *param,
   oprintf (d.of, " *)x_p;\n");
   if (chain_next != NULL)
     {
+      /* TYPE_USER_STRUCTs should not occur here.  These structures
+	 are completely handled by user code.  */
+      gcc_assert (orig_s->kind != TYPE_USER_STRUCT);
+
       oprintf (d.of, "  ");
       write_type_decl (d.of, s);
       oprintf (d.of, " * xlimit = x;\n");
@@ -3760,7 +3842,9 @@  write_types_local_user_process_field (type_p f, const struct walk_type_data *d)
     case TYPE_SCALAR:
       break;
 
-    default:
+    case TYPE_ARRAY:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
       gcc_unreachable ();
     }
 }
@@ -3843,7 +3927,9 @@  write_types_local_process_field (type_p f, const struct walk_type_data *d)
     case TYPE_SCALAR:
       break;
 
-    default:
+    case TYPE_ARRAY:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
       gcc_unreachable ();
     }
 }
@@ -4063,6 +4149,9 @@  contains_scalar_p (type_p t)
       return 0;
     case TYPE_ARRAY:
       return contains_scalar_p (t->u.a.p);
+    case TYPE_USER_STRUCT:
+      /* User-marked structures will typically contain pointers.  */
+      return 0;
     default:
       /* Could also check for structures that have no non-pointer
          fields, but there aren't enough of those to worry about.  */
@@ -4313,8 +4402,9 @@  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);
+      error_at_line (line, "`%s' must be a pointer type, because it is "
+	             "a GC root and its type is marked with GTY((user))",
+		     v->name);
       break;
 
     case TYPE_POINTER:
@@ -4384,7 +4474,11 @@  write_root (outf_p f, pair_p v, type_p type, const char *name, int has_length,
     case TYPE_SCALAR:
       break;
 
-    default:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
+    case TYPE_UNION:
+    case TYPE_LANG_STRUCT:
+    case TYPE_PARAM_STRUCT:
       error_at_line (line, "global `%s' is unimplemented type", name);
     }
 }
@@ -4880,7 +4974,9 @@  output_typename (outf_p of, const_type_p t)
 	output_typename (of, t->u.param_struct.stru);
 	break;
       }
-    default:
+    case TYPE_NONE:
+    case TYPE_UNDEFINED:
+    case TYPE_ARRAY:
       gcc_unreachable ();
     }
 }
@@ -4941,6 +5037,9 @@  dump_typekind (int indent, enum typekind kind)
     case TYPE_STRUCT:
       printf ("TYPE_STRUCT");
       break;
+    case TYPE_UNDEFINED:
+      printf ("TYPE_UNDEFINED");
+      break;
     case TYPE_USER_STRUCT:
       printf ("TYPE_USER_STRUCT");
       break;
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index e687e48..57a67fb 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -134,6 +134,9 @@  extern pair_p variables;
 
 enum typekind {
   TYPE_NONE=0,          /* Never used, so zeroed memory is invalid.  */
+  TYPE_UNDEFINED,	/* We have not yet seen a definition for this type.
+			   If a type is still undefined when generating code,
+			   an error will be generated.  */
   TYPE_SCALAR,          /* Scalar types like char.  */
   TYPE_STRING,          /* The string type.  */
   TYPE_STRUCT,          /* Type for GTY-ed structs.  */
@@ -423,6 +426,7 @@  extern type_p resolve_typedef (const char *s, struct fileloc *pos);
 extern type_p new_structure (const char *name, enum typekind kind,
 			     struct fileloc *pos, pair_p fields,
 			     options_p o);
+type_p create_user_defined_type (const char *, struct fileloc *);
 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);
@@ -457,7 +461,6 @@  enum gty_token
   UNION,
   STRUCT,
   ENUM,
-  VEC_TOKEN,
   ELLIPSIS,
   PTR_ALIAS,
   NESTED_PTR,