diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index c5f72b231006a8c933998955a1a0d007a948d32f..a665bbe028f11c6690f513a81a1a4d1083da1b4e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,17 @@
+2006-01-23  Richard Sandiford  <richard@codesourcery.com>
+
+	* gengtype.c (new_structure): Return the structure.
+	(create_option): Add an extra "next" argument.
+	(create_field): New function.
+	(adjust_field_rtx_def): Use create_option and create_field.
+	Remove a now-unnecessary call to find_structure.
+	(adjust_field_tree_def): Likewise.
+	(note_yacc_type): Remove an unnecessary call to find_structure.
+	* gengtype.h (new_structure): Return the structure.
+	(create_option): Add an extra argument.
+	* gengtype-yacc.y (type): Remove unnecessary calls to find_structure.
+	(option): Adjust calls to create_option.
+
 2006-01-22  David Edelsohn  <edelsohn@gnu.org>
 
 	* config/rs6000/aix.h (STACK_BOUNDARY): Define.
diff --git a/gcc/gengtype-yacc.y b/gcc/gengtype-yacc.y
index b1331724bd48d4556ee86e8e712ca4f94f17f8c9..8bdf983e06b79055421b9e7fca6295f10de28a25 100644
--- a/gcc/gengtype-yacc.y
+++ b/gcc/gengtype-yacc.y
@@ -232,17 +232,11 @@ type: SCALAR
       | type '*'
          { $$ = create_pointer ($1); }
       | STRUCT ID '{' struct_fields '}'
-         {
-	   new_structure ($2, 0, &lexer_line, $4, NULL);
-           $$ = find_structure ($2, 0);
-	 }
+         { $$ = new_structure ($2, 0, &lexer_line, $4, NULL); }
       | STRUCT ID
          { $$ = find_structure ($2, 0); }
       | UNION ID '{' struct_fields '}'
-         {
-	   new_structure ($2, 1, &lexer_line, $4, NULL);
-           $$ = find_structure ($2, 1);
-	 }
+         { $$ = new_structure ($2, 1, &lexer_line, $4, NULL); }
       | UNION ID
          { $$ = find_structure ($2, 1); }
       | ENUM ID
@@ -275,11 +269,11 @@ type_option : ALIAS
 	      ;
 
 option:   ID
-	    { $$ = create_option ($1, (void *)""); }
+	    { $$ = create_option (NULL, $1, (void *)""); }
         | ID '(' stringseq ')'
-            { $$ = create_option ($1, (void *)$3); }
+            { $$ = create_option (NULL, $1, (void *)$3); }
 	| type_option '(' type ')'
-	    { $$ = create_option ($1, adjust_field_type ($3, NULL)); }
+	    { $$ = create_option (NULL, $1, adjust_field_type ($3, NULL)); }
 	| NESTED_PTR '(' type ',' stringseq ',' stringseq ')'
 	    {
 	      struct nested_ptr_data d;
@@ -287,7 +281,7 @@ option:   ID
 	      d.type = adjust_field_type ($3, NULL);
 	      d.convert_to = $5;
 	      d.convert_from = $7;
-	      $$ = create_option ("nested_ptr",
+	      $$ = create_option (NULL, "nested_ptr",
 				  xmemdup (&d, sizeof (d), sizeof (d)));
 	    }
 	;
diff --git a/gcc/gengtype.c b/gcc/gengtype.c
index 704f7739d9078ef6d9f0025b191724ac528729b5..0a915230e12d0f22f7f74f6bcf175649104222d9 100644
--- a/gcc/gengtype.c
+++ b/gcc/gengtype.c
@@ -143,10 +143,10 @@ resolve_typedef (const char *s, struct fileloc *pos)
   return create_scalar_type ("char", 4);
 }
 
-/* Create 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 (or a union iff
+   ISUNION is nonzero), at POS with fields FIELDS and options O.  */
 
-void
+type_p
 new_structure (const char *name, int isunion, struct fileloc *pos,
 	       pair_p fields, options_p o)
 {
@@ -214,6 +214,8 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
   s->u.s.bitmap = bitmap;
   if (s->u.s.lang_struct)
     s->u.s.lang_struct->u.s.bitmap |= bitmap;
+
+  return s;
 }
 
 /* Return the previously-defined structure with tag NAME (or a union
@@ -305,11 +307,14 @@ create_array (type_p t, const char *len)
   return v;
 }
 
-/* Return an options structure with name NAME and info INFO.  */
+/* Return an options structure with name NAME and info INFO.  NEXT is the
+   next option in the chain.  */
+
 options_p
-create_option (const char *name, void *info)
+create_option (options_p next, const char *name, const void *info)
 {
   options_p o = XNEW (struct options);
+  o->next = next;
   o->name = name;
   o->info = (const char*) info;
   return o;
@@ -331,6 +336,24 @@ note_variable (const char *s, type_p t, options_p o, struct fileloc *pos)
   variables = n;
 }
 
+/* Create a fake field with the given type and name.  NEXT is the next
+   field in the chain.  */
+
+static pair_p
+create_field (pair_p next, type_p type, const char *name)
+{
+  pair_p field;
+
+  field = XNEW (struct pair);
+  field->next = next;
+  field->type = type;
+  field->name = name;
+  field->opt = NULL;
+  field->line.file = __FILE__;
+  field->line.line = __LINE__;
+  return field;
+}
+
 /* We don't care how long a CONST_DOUBLE is.  */
 #define CONST_DOUBLE_FORMAT "ww"
 /* We don't want to see codes that are only for generator files.  */
@@ -440,10 +463,7 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
       return &string_type;
     }
 
-  nodot = XNEW (struct options);
-  nodot->next = NULL;
-  nodot->name = "dot";
-  nodot->info = "";
+  nodot = create_option (NULL, "dot", "");
 
   rtx_tp = create_pointer (find_structure ("rtx_def", 0));
   rtvec_tp = create_pointer (find_structure ("rtvec_def", 0));
@@ -460,61 +480,46 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
 
     for (c = 0; c <= NOTE_INSN_MAX; c++)
       {
-	pair_p old_note_flds = note_flds;
-
-	note_flds = XNEW (struct pair);
-	note_flds->line.file = __FILE__;
-	note_flds->line.line = __LINE__;
-	note_flds->opt = XNEW (struct options);
-	note_flds->opt->next = nodot;
-	note_flds->opt->name = "tag";
-	note_flds->opt->info = note_insn_name[c];
-	note_flds->next = old_note_flds;
-
 	switch (c)
 	  {
-	    /* NOTE_INSN_MAX is used as the default field for line
-	       number notes.  */
 	  case NOTE_INSN_MAX:
-	    note_flds->opt->name = "default";
-	    note_flds->name = "rt_str";
-	    note_flds->type = &string_type;
+	    note_flds = create_field (note_flds, &string_type, "rt_str");
 	    break;
 
 	  case NOTE_INSN_BLOCK_BEG:
 	  case NOTE_INSN_BLOCK_END:
-	    note_flds->name = "rt_tree";
-	    note_flds->type = tree_tp;
+	    note_flds = create_field (note_flds, tree_tp, "rt_tree");
 	    break;
 
 	  case NOTE_INSN_EXPECTED_VALUE:
 	  case NOTE_INSN_VAR_LOCATION:
-	    note_flds->name = "rt_rtx";
-	    note_flds->type = rtx_tp;
+	    note_flds = create_field (note_flds, rtx_tp, "rt_rtx");
 	    break;
 
 	  default:
-	    note_flds->name = "rt_int";
-	    note_flds->type = scalar_tp;
+	    note_flds = create_field (note_flds, scalar_tp, "rt_int");
 	    break;
 	  }
+	/* NOTE_INSN_MAX is used as the default field for line
+	   number notes.  */
+	if (c == NOTE_INSN_MAX)
+	  note_flds->opt = create_option (nodot, "default", "");
+	else
+	  note_flds->opt = create_option (nodot, "tag", note_insn_name[c]);
       }
-    new_structure ("rtx_def_note_subunion", 1, &lexer_line, note_flds, NULL);
+    note_union_tp = new_structure ("rtx_def_note_subunion", 1,
+				   &lexer_line, note_flds, NULL);
   }
-
-  note_union_tp = find_structure ("rtx_def_note_subunion", 1);
-
   for (i = 0; i < NUM_RTX_CODE; i++)
     {
-      pair_p old_flds = flds;
       pair_p subfields = NULL;
       size_t aindex, nmindex;
       const char *sname;
+      type_p substruct;
       char *ftag;
 
       for (aindex = 0; aindex < strlen (rtx_format[i]); aindex++)
 	{
-	  pair_p old_subf = subfields;
 	  type_p t;
 	  const char *subname;
 
@@ -614,43 +619,28 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt))
 	      break;
 	    }
 
-	  subfields = XNEW (struct pair);
-	  subfields->next = old_subf;
-	  subfields->type = t;
-	  subfields->name = xasprintf (".fld[%lu].%s", (unsigned long)aindex,
-				       subname);
-	  subfields->line.file = __FILE__;
-	  subfields->line.line = __LINE__;
+	  subfields = create_field (subfields, t,
+				    xasprintf (".fld[%lu].%s",
+					       (unsigned long) aindex,
+					       subname));
+	  subfields->opt = nodot;
 	  if (t == note_union_tp)
-	    {
-	      subfields->opt = XNEW (struct options);
-	      subfields->opt->next = nodot;
-	      subfields->opt->name = "desc";
-	      subfields->opt->info = "NOTE_LINE_NUMBER (&%0)";
-	    }
-	  else
-	    subfields->opt = nodot;
+	    subfields->opt = create_option (subfields->opt, "desc",
+					    "NOTE_LINE_NUMBER (&%0)");
 	}
 
-      flds = XNEW (struct pair);
-      flds->next = old_flds;
-      flds->name = "";
       sname = xasprintf ("rtx_def_%s", rtx_name[i]);
-      new_structure (sname, 0, &lexer_line, subfields, NULL);
-      flds->type = find_structure (sname, 0);
-      flds->line.file = __FILE__;
-      flds->line.line = __LINE__;
-      flds->opt = XNEW (struct options);
-      flds->opt->next = nodot;
-      flds->opt->name = "tag";
+      substruct = new_structure (sname, 0, &lexer_line, subfields, NULL);
+
       ftag = xstrdup (rtx_name[i]);
       for (nmindex = 0; nmindex < strlen (ftag); nmindex++)
 	ftag[nmindex] = TOUPPER (ftag[nmindex]);
-      flds->opt->info = ftag;
+
+      flds = create_field (flds, substruct, "");
+      flds->opt = create_option (nodot, "tag", ftag);
     }
 
-  new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
-  return find_structure ("rtx_def_subunion", 1);
+  return new_structure ("rtx_def_subunion", 1, &lexer_line, flds, nodot);
 }
 
 /* Handle `special("tree_exp")'.  This is a special case for
@@ -672,31 +662,14 @@ adjust_field_tree_exp (type_p t, options_p opt ATTRIBUTE_UNUSED)
       return &string_type;
     }
 
-  nodot = XNEW (struct options);
-  nodot->next = NULL;
-  nodot->name = "dot";
-  nodot->info = "";
-
-  flds = XNEW (struct pair);
-  flds->next = NULL;
-  flds->name = "";
-  flds->type = t;
-  flds->line.file = __FILE__;
-  flds->line.line = __LINE__;
-  flds->opt = XNEW (struct options);
-  flds->opt->next = nodot;
-  flds->opt->name = "length";
-  flds->opt->info = "TREE_CODE_LENGTH (TREE_CODE ((tree) &%0))";
-  {
-    options_p oldopt = flds->opt;
-    flds->opt = XNEW (struct options);
-    flds->opt->next = oldopt;
-    flds->opt->name = "default";
-    flds->opt->info = "";
-  }
+  nodot = create_option (NULL, "dot", "");
+
+  flds = create_field (NULL, t, "");
+  flds->opt = create_option (nodot, "length",
+			     "TREE_CODE_LENGTH (TREE_CODE ((tree) &%0))");
+  flds->opt = create_option (flds->opt, "default", "");
 
-  new_structure ("tree_exp_subunion", 1, &lexer_line, flds, nodot);
-  return find_structure ("tree_exp_subunion", 1);
+  return new_structure ("tree_exp_subunion", 1, &lexer_line, flds, nodot);
 }
 
 /* Perform any special processing on a type T, about to become the type
@@ -841,8 +814,7 @@ note_yacc_type (options_p o, pair_p fields, pair_p typeinfo,
 	p_p = &p->next;
     }
 
-  new_structure ("yy_union", 1, pos, typeinfo, o);
-  do_typedef ("YYSTYPE", find_structure ("yy_union", 1), pos);
+  do_typedef ("YYSTYPE", new_structure ("yy_union", 1, pos, typeinfo, o), pos);
 }
 
 static void process_gc_options (options_p, enum gc_used_enum,
diff --git a/gcc/gengtype.h b/gcc/gengtype.h
index 0e527c2706debefd1b5278fa5c69dcf479dc72e9..cb44b97fcc814994c5f2d35c063574da46b38b8e 100644
--- a/gcc/gengtype.h
+++ b/gcc/gengtype.h
@@ -133,14 +133,14 @@ extern char * xasprintf (const char *, ...)
 /* Constructor routines for types.  */
 extern void do_typedef (const char *s, type_p t, struct fileloc *pos);
 extern type_p resolve_typedef (const char *s, struct fileloc *pos);
-extern void new_structure (const char *name, int isunion, 
-			   struct fileloc *pos, pair_p fields, 
-			   options_p o);
+extern type_p new_structure (const char *name, int isunion,
+			     struct fileloc *pos, pair_p fields,
+			     options_p o);
 extern type_p find_structure (const char *s, int isunion);
 extern type_p create_scalar_type (const char *name, size_t name_len);
 extern type_p create_pointer (type_p t);
 extern type_p create_array (type_p t, const char *len);
-extern options_p create_option (const char *name, void *info);
+extern options_p create_option (options_p, const char *name, const void *info);
 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);