]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/gengtype-parse.c
PR fortran/95090 - ICE: identifier overflow
[thirdparty/gcc.git] / gcc / gengtype-parse.c
index 357981ad3cb392616603a3576694a9741b6f953c..920e451cf3d6db15a88ea55a6adb7d4ca1347618 100644 (file)
@@ -1,23 +1,28 @@
 /* Process source files and output type information.
-   Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2006-2020 Free Software Foundation, Inc.
 
-This file is part of GCC.
+   This file is part of GCC.
 
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
+   GCC is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 3, or (at your option) any later
+   version.
 
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
 
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3.  If not see
-<http://www.gnu.org/licenses/>.  */
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
+#ifdef HOST_GENERATOR_FILE
+#include "config.h"
+#define GENERATOR_FILE 1
+#else
 #include "bconfig.h"
+#endif
 #include "system.h"
 #include "gengtype.h"
 
@@ -72,10 +77,6 @@ static const char *const token_names[] = {
   "union",
   "struct",
   "enum",
-  "VEC",
-  "DEF_VEC_[OP]",
-  "DEF_VEC_I",
-  "DEF_VEC_ALLOC_[IOP]",
   "...",
   "ptr_alias",
   "nested_ptr",
@@ -86,6 +87,7 @@ static const char *const token_names[] = {
   "a string constant",
   "a character constant",
   "an array declarator",
+  "a C++ keyword to ignore"
 };
 
 /* This array is indexed by token code minus FIRST_TOKEN_WITH_VALUE.  */
@@ -97,6 +99,7 @@ static const char *const token_value_format[] = {
   "'\"%s\"'",
   "\"'%s'\"",
   "'[%s]'",
+  "'%s'",
 };
 
 /* Produce a printable representation for a token defined by CODE and
@@ -113,7 +116,7 @@ print_token (int code, const char *value)
   else if (code < FIRST_TOKEN_WITH_VALUE)
     return xasprintf ("'%s'", token_names[code - CHAR_TOKEN_OFFSET]);
   else if (!value)
-    return token_names[code - CHAR_TOKEN_OFFSET]; /* don't quote these */
+    return token_names[code - CHAR_TOKEN_OFFSET];      /* don't quote these */
   else
     return xasprintf (token_value_format[code - FIRST_TOKEN_WITH_VALUE],
                      value);
@@ -135,12 +138,15 @@ parse_error (const char *msg, ...)
 {
   va_list ap;
 
-  fprintf (stderr, "%s:%d: parse error: ", lexer_line.file, lexer_line.line);
+  fprintf (stderr, "%s:%d: parse error: ", 
+          get_input_file_name (lexer_line.file), lexer_line.line);
 
   va_start (ap, msg);
   vfprintf (stderr, msg, ap);
   va_end (ap);
 
+  fputc ('\n', stderr);
+
   hit_error = true;
 }
 
@@ -160,6 +166,21 @@ require (int t)
   return v;
 }
 
+/* As per require, but do not advance.  */
+static const char *
+require_without_advance (int t)
+{
+  int u = token ();
+  const char *v = T.value;
+  if (u != t)
+    {
+      parse_error ("expected %s, have %s",
+                  print_token (t, 0), print_token (u, v));
+      return 0;
+    }
+  return v;
+}
+
 /* If the next token does not have one of the codes T1 or T2, report a
    parse error; otherwise return the token's value.  */
 static const char *
@@ -177,6 +198,24 @@ require2 (int t1, int t2)
   return v;
 }
 
+/* If the next token does not have one of the codes T1, T2, T3 or T4, report a
+   parse error; otherwise return the token's value.  */
+static const char *
+require4 (int t1, int t2, int t3, int t4)
+{
+  int u = token ();
+  const char *v = advance ();
+  if (u != t1 && u != t2 && u != t3 && u != t4)
+    {
+      parse_error ("expected %s, %s, %s or %s, have %s",
+                  print_token (t1, 0), print_token (t2, 0),
+                  print_token (t3, 0), print_token (t4, 0),
+                  print_token (u, v));
+      return 0;
+    }
+  return v;
+}
+
 /* Near-terminals.  */
 
 /* C-style string constant concatenation: STRING+
@@ -197,7 +236,7 @@ string_seq (void)
 
       l1 = strlen (s1);
       l2 = strlen (s2);
-      buf = XRESIZEVEC (char, CONST_CAST(char *, s1), l1 + l2 + 1);
+      buf = XRESIZEVEC (char, CONST_CAST (char *, s1), l1 + l2 + 1);
       memcpy (buf + l1, s2, l2 + 1);
       XDELETE (CONST_CAST (char *, s2));
       s1 = buf;
@@ -205,28 +244,89 @@ 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>,
+   potentially with a single level of indirection e.g.
+     ID<ID1 *, ID2, ID3 *, ..., IDn>.
+   It does not try to parse anything more sophisticated than that.
+
+   Returns the template declaration string "ID<ID1,ID2,...,IDn>".  */
+
 static const char *
-typedef_name (void)
+require_template_declaration (const char *tmpl_name)
 {
-  if (token () == VEC_TOKEN)
+  char *str;
+  int num_indirections = 0;
+
+  /* Recognize the opening '<'.  */
+  require ('<');
+  str = concat (tmpl_name, "<", (char *) 0);
+
+  /* Read the comma-separated list of identifiers.  */
+  int depth = 1;
+  while (depth > 0)
     {
-      const char *c1, *c2, *r;
-      advance ();
-      require ('(');
-      c1 = require2 (ID, SCALAR);
-      require (',');
-      c2 = require (ID);
-      require (')');
-      r = concat ("VEC_", c1, "_", c2, (char *)0);
-      free (CONST_CAST (char *, c1));
-      free (CONST_CAST (char *, c2));
-      return r;
+      if (token () == ENUM)
+       {
+         advance ();
+         str = concat (str, "enum ", (char *) 0);
+         continue;
+       }
+      if (token () == NUM
+         || token () == ':'
+         || token () == '+')
+       {
+         str = concat (str, advance (), (char *) 0);
+         continue;
+       }
+      if (token () == '<')
+       {
+         advance ();
+         str = concat (str, "<", (char *) 0);
+         depth += 1;
+         continue;
+       }
+      if (token () == '>')
+       {
+         advance ();
+         str = concat (str, ">", (char *) 0);
+         depth -= 1;
+         continue;
+       }
+      const char *id = require4 (SCALAR, ID, '*', ',');
+      if (id == NULL)
+       {
+         if (T.code == '*')
+           {
+             id = "*";
+             if (num_indirections++)
+               parse_error ("only one level of indirection is supported"
+                            " in template arguments");
+           }
+         else
+           id = ",";
+       }
+      else
+       num_indirections = 0;
+      str = concat (str, id, (char *) 0);
     }
+  return str;
+}
+
+
+/* typedef_name: either an ID, or a template type
+   specification of the form ID<t1,t2,...,tn>.  */
+
+static const char *
+typedef_name (void)
+{
+  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 ()[]{}.  */
@@ -237,10 +337,18 @@ consume_balanced (int opener, int closer)
   for (;;)
     switch (token ())
       {
-      default: advance (); break;
-      case '(': consume_balanced ('(',')'); break;
-      case '[': consume_balanced ('[',']'); break;
-      case '{': consume_balanced ('{','}'); break;
+      default:
+       advance ();
+       break;
+      case '(':
+       consume_balanced ('(', ')');
+       break;
+      case '[':
+       consume_balanced ('[', ']');
+       break;
+      case '{':
+       consume_balanced ('{', '}');
+       break;
 
       case '}':
       case ']':
@@ -248,8 +356,8 @@ consume_balanced (int opener, int closer)
        if (token () != closer)
          parse_error ("unbalanced delimiters - expected '%c', have '%c'",
                       closer, token ());
-       advance ();
-       return;
+      advance ();
+      return;
 
       case EOF_TOKEN:
        parse_error ("unexpected end of file within %c%c-delimited construct",
@@ -259,23 +367,30 @@ consume_balanced (int opener, int closer)
 }
 
 /* Absorb a sequence of tokens, possibly including ()[]{}-delimited
-   expressions, until we encounter a semicolon outside any such
-   delimiters; absorb that too.  If IMMEDIATE is true, it is an error
-   if the semicolon is not the first token encountered.  */
+   expressions, until we encounter an end-of-statement marker (a ';' or
+   a '}') outside any such delimiters; absorb that too.  */
+
 static void
-consume_until_semi (bool immediate)
+consume_until_eos (void)
 {
-  if (immediate && token () != ';')
-    require (';');
   for (;;)
     switch (token ())
       {
-      case ';':        advance (); return;
-      default: advance (); break;
+      case ';':
+       advance ();
+       return;
 
-      case '(':        consume_balanced ('(',')'); break;
-      case '[': consume_balanced ('[',']'); break;
-      case '{':        consume_balanced ('{','}'); break;
+      case '{':
+       consume_balanced ('{', '}');
+       return;
+
+      case '(':
+       consume_balanced ('(', ')');
+       break;
+
+      case '[':
+       consume_balanced ('[', ']');
+       break;
 
       case '}':
       case ']':
@@ -286,44 +401,62 @@ consume_until_semi (bool immediate)
       case EOF_TOKEN:
        parse_error ("unexpected end of file while scanning for ';'");
        return;
+
+      default:
+       advance ();
+       break;
       }
 }
 
 /* Absorb a sequence of tokens, possibly including ()[]{}-delimited
    expressions, until we encounter a comma or semicolon outside any
-   such delimiters; absorb that too.  If IMMEDIATE is true, it is an
-   error if the comma or semicolon is not the first token encountered.
-   Returns true if the loop ended with a comma.  */
+   such delimiters; absorb that too.  Returns true if the loop ended
+   with a comma.  */
+
 static bool
-consume_until_comma_or_semi (bool immediate)
+consume_until_comma_or_eos ()
 {
-  if (immediate && token () != ',' && token () != ';')
-    require2 (',', ';');
   for (;;)
     switch (token ())
       {
-      case ',':        advance (); return true;
-      case ';':        advance (); return false;
-      default: advance (); break;
+      case ',':
+       advance ();
+       return true;
+
+      case ';':
+       advance ();
+       return false;
 
-      case '(':        consume_balanced ('(',')'); break;
-      case '[': consume_balanced ('[',']'); break;
-      case '{':        consume_balanced ('{','}'); break;
+      case '{':
+       consume_balanced ('{', '}');
+       return false;
+
+      case '(':
+       consume_balanced ('(', ')');
+       break;
+
+      case '[':
+       consume_balanced ('[', ']');
+       break;
 
       case '}':
       case ']':
       case ')':
        parse_error ("unmatched '%s' while scanning for ',' or ';'",
                     print_cur_token ());
-       return false;
+      return false;
 
       case EOF_TOKEN:
        parse_error ("unexpected end of file while scanning for ',' or ';'");
        return false;
+
+      default:
+       advance ();
+       break;
       }
 }
-
 \f
+
 /* GTY(()) option handling.  */
 static type_p type (options_p *optsp, bool nested);
 
@@ -339,7 +472,7 @@ str_optvalue_opt (options_p prev)
       value = string_seq ();
       require (')');
     }
-  return create_option (prev, name, value);
+  return create_string_option (prev, name, value);
 }
 
 /* absdecl: type '*'*
@@ -377,7 +510,7 @@ type_optvalue (options_p prev, const char *name)
   require ('(');
   ty = absdecl ();
   require (')');
-  return create_option (prev, name, ty);
+  return create_type_option (prev, name, ty);
 }
 
 /* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
@@ -399,11 +532,10 @@ nestedptr_optvalue (options_p prev)
 }
 
 /* One GTY(()) option:
-         ID str_optvalue_opt
-       | PTR_ALIAS type_optvalue
-       | PARAM_IS type_optvalue
-       | NESTED_PTR nestedptr_optvalue
- */
+   ID str_optvalue_opt
+   | PTR_ALIAS type_optvalue
+   | NESTED_PTR nestedptr_optvalue
+*/
 static options_p
 option (options_p prev)
 {
@@ -416,18 +548,18 @@ option (options_p prev)
       advance ();
       return type_optvalue (prev, "ptr_alias");
 
-    case PARAM_IS:
-      return type_optvalue (prev, advance ());
-
     case NESTED_PTR:
       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 ());
+      parse_error ("expected an option keyword, have %s", print_cur_token ());
       advance ();
-      return create_option (prev, "", "");
+      return create_string_option (prev, "", "");
     }
 }
 
@@ -469,6 +601,8 @@ gtymarker_opt (void)
     return 0;
   return gtymarker ();
 }
+
+
 \f
 /* Declarators. The logic here is largely lifted from c-parser.c.
    Note that we do not have to process abstract declarators, which can
@@ -477,9 +611,9 @@ gtymarker_opt (void)
    we don't have to do it.  */
 
 /* array_and_function_declarators_opt:
-      \epsilon
-      array_and_function_declarators_opt ARRAY
-      array_and_function_declarators_opt '(' ... ')'
+   \epsilon
+   array_and_function_declarators_opt ARRAY
+   array_and_function_declarators_opt '(' ... ')'
 
    where '...' indicates stuff we ignore except insofar as grouping
    symbols ()[]{} must balance.
@@ -505,16 +639,21 @@ array_and_function_declarators_opt (type_p ty)
     return ty;
 }
 
-static type_p inner_declarator (type_p, const char **, options_p *);
+static type_p inner_declarator (type_p, const char **, options_p *, bool);
 
 /* direct_declarator:
-      '(' inner_declarator ')'
-      gtymarker_opt ID array_and_function_declarators_opt
+   '(' inner_declarator ')'
+   '(' \epsilon ')'    <-- C++ ctors/dtors
+   gtymarker_opt ID array_and_function_declarators_opt
 
    Subroutine of declarator, mutually recursive with inner_declarator;
-   do not use elsewhere.  */
+   do not use elsewhere.
+
+   IN_STRUCT is true if we are called while parsing structures or classes.  */
+
 static type_p
-direct_declarator (type_p ty, const char **namep, options_p *optsp)
+direct_declarator (type_p ty, const char **namep, options_p *optsp,
+                  bool in_struct)
 {
   /* The first token in a direct-declarator must be an ID, a
      GTY marker, or an open parenthesis.  */
@@ -523,18 +662,45 @@ direct_declarator (type_p ty, const char **namep, options_p *optsp)
     case GTY_TOKEN:
       *optsp = gtymarker ();
       /* fall through */
+
     case ID:
       *namep = require (ID);
+      /* If the next token is '(', we are parsing a function declaration.
+        Functions are ignored by gengtype, so we return NULL.  */
+      if (token () == '(')
+       return NULL;
       break;
 
     case '(':
+      /* If the declarator starts with a '(', we have three options.  We
+        are either parsing 'TYPE (*ID)' (i.e., a function pointer)
+        or 'TYPE(...)'.
+
+        The latter will be a constructor iff we are inside a
+        structure or class.  Otherwise, it could be a typedef, but
+        since we explicitly reject typedefs inside structures, we can
+        assume that we found a ctor and return NULL.  */
       advance ();
-      ty = inner_declarator (ty, namep, optsp);
+      if (in_struct && token () != '*')
+       {
+         /* Found a constructor.  Find and consume the closing ')'.  */
+         while (token () != ')')
+           advance ();
+         advance ();
+         /* Tell the caller to ignore this.  */
+         return NULL;
+       }
+      ty = inner_declarator (ty, namep, optsp, in_struct);
       require (')');
       break;
 
+    case IGNORABLE_CXX_KEYWORD:
+      /* Any C++ keyword like 'operator' means that we are not looking
+        at a regular data declarator.  */
+      return NULL;
+
     default:
-      parse_error ("expected '(', 'GTY', or an identifier, have %s",
+      parse_error ("expected '(', ')', 'GTY', or an identifier, have %s",
                   print_cur_token ());
       /* Do _not_ advance if what we have is a close squiggle brace, as
         we will get much better error recovery that way.  */
@@ -548,7 +714,7 @@ direct_declarator (type_p ty, const char **namep, options_p *optsp)
 /* The difference between inner_declarator and declarator is in the
    handling of stars.  Consider this declaration:
 
-      char * (*pfc) (void)
+   char * (*pfc) (void)
 
    It declares a pointer to a function that takes no arguments and
    returns a char*.  To construct the correct type for this
@@ -560,27 +726,30 @@ direct_declarator (type_p ty, const char **namep, options_p *optsp)
    creating pointers.  */
 
 /* inner_declarator:
-     '*' inner_declarator
-     direct_declarator
+   '*' inner_declarator
+   direct_declarator
 
    Mutually recursive subroutine of direct_declarator; do not use
-   elsewhere.  */
+   elsewhere.
+
+   IN_STRUCT is true if we are called while parsing structures or classes.  */
 
 static type_p
-inner_declarator (type_p ty, const char **namep, options_p *optsp)
+inner_declarator (type_p ty, const char **namep, options_p *optsp,
+                 bool in_struct)
 {
   if (token () == '*')
     {
       type_p inner;
       advance ();
-      inner = inner_declarator (ty, namep, optsp);
+      inner = inner_declarator (ty, namep, optsp, in_struct);
       if (inner == 0)
        return 0;
       else
        return create_pointer (ty);
     }
   else
-    return direct_declarator (ty, namep, optsp);
+    return direct_declarator (ty, namep, optsp, in_struct);
 }
 
 /* declarator: '*'+ direct_declarator
@@ -588,10 +757,15 @@ inner_declarator (type_p ty, const char **namep, options_p *optsp)
    This is the sole public interface to this part of the grammar.
    Arguments are the type known so far, a pointer to where the name
    may be stored, and a pointer to where GTY options may be stored.
-   Returns the final type. */
+
+   IN_STRUCT is true when we are called to parse declarators inside
+   a structure or class.
+
+   Returns the final type.  */
 
 static type_p
-declarator (type_p ty, const char **namep, options_p *optsp)
+declarator (type_p ty, const char **namep, options_p *optsp,
+           bool in_struct = false)
 {
   *namep = 0;
   *optsp = 0;
@@ -600,20 +774,20 @@ declarator (type_p ty, const char **namep, options_p *optsp)
       advance ();
       ty = create_pointer (ty);
     }
-  return direct_declarator (ty, namep, optsp);
+  return direct_declarator (ty, namep, optsp, in_struct);
 }
 \f
 /* Types and declarations.  */
 
 /* Structure field(s) declaration:
    (
-       type bitfield ';'
-     | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
-   )+
+   type bitfield ';'
+   | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
+   )*
 
    Knows that such declarations must end with a close brace (or,
    erroneously, at EOF).
- */
+*/
 static pair_p
 struct_field_seq (void)
 {
@@ -623,27 +797,36 @@ struct_field_seq (void)
   const char *name;
   bool another;
 
-  do
+  while (token () != '}' && token () != EOF_TOKEN)
     {
       ty = type (&opts, true);
-      /* Another piece of the IFCVT_EXTRA_FIELDS special case, see type().  */
-      if (!ty && token () == '}')
-       break;
+
+      /* Ignore access-control keywords ("public:" etc).  */
+      while (!ty && token () == IGNORABLE_CXX_KEYWORD)
+       {
+         const char *keyword = advance ();
+         if (strcmp (keyword, "public:") != 0
+             && strcmp (keyword, "private:") != 0
+             && strcmp (keyword, "protected:") != 0)
+           break;
+         ty = type (&opts, true);
+       }
 
       if (!ty || token () == ':')
        {
-         consume_until_semi (false);
+         consume_until_eos ();
          continue;
        }
 
       do
        {
-         dty = declarator (ty, &name, &dopts);
+         dty = declarator (ty, &name, &dopts, true);
+
          /* There could be any number of weird things after the declarator,
             notably bitfield declarations and __attribute__s.  If this
             function returns true, the last thing was a comma, so we have
             more than one declarator paired with the current type.  */
-         another = consume_until_comma_or_semi (false);
+         another = consume_until_comma_or_eos ();
 
          if (!dty)
            continue;
@@ -657,14 +840,25 @@ struct_field_seq (void)
        }
       while (another);
     }
-  while (token () != '}' && token () != EOF_TOKEN);
   return nreverse_pairs (f);
 }
 
+/* Return true if OPTS contain the option named STR.  */
+
+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:
 
-     SCALAR
+   SCALAR
    | ID     // typedef
    | (STRUCT|UNION) ID? gtymarker? ( '{' gtymarker? struct_field_seq '}' )?
    | ENUM ID ( '{' ... '}' )?
@@ -672,12 +866,16 @@ struct_field_seq (void)
    Returns a partial type; under some conditions (notably
    "struct foo GTY((...)) thing;") it may write an options
    structure to *OPTSP.
- */
+
+   NESTED is true when parsing a declaration already known to have a
+   GTY marker. In these cases, typedef and enum declarations are not
+   allowed because gengtype only understands types at the global
+   scope.  */
+
 static type_p
 type (options_p *optsp, bool nested)
 {
   const char *s;
-  bool is_union;
   *optsp = 0;
   switch (token ())
     {
@@ -686,56 +884,167 @@ 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);
 
+    case IGNORABLE_CXX_KEYWORD:
+      /* By returning NULL here, we indicate to the caller that they
+        should ignore everything following this keyword up to the
+        next ';' or '}'.  */
+      return NULL;
+
     case STRUCT:
     case UNION:
       {
+       type_p base_class = NULL;
        options_p opts = 0;
-
-       is_union = (token() == UNION);
+       /* GTY annotations follow attribute syntax
+          GTY_BEFORE_ID is for union/struct declarations
+          GTY_AFTER_ID is for variable declarations.  */
+       enum
+       {
+         NO_GTY,
+         GTY_BEFORE_ID,
+         GTY_AFTER_ID
+       } is_gty = NO_GTY;
+       enum typekind kind = (token () == UNION) ? TYPE_UNION : TYPE_STRUCT;
        advance ();
 
-       if (token () == ID)
-         s = advance ();
-       else
-         s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
-
        /* Top-level structures that are not explicitly tagged GTY(())
           are treated as mere forward declarations.  This is because
           there are a lot of structures that we don't need to know
-          about, and some of those have weird macro stuff in them
-          that we can't handle.  */
+          about, and some of those have C++ and macro constructs that
+          we cannot handle.  */
        if (nested || token () == GTY_TOKEN)
          {
+           is_gty = GTY_BEFORE_ID;
+           opts = gtymarker_opt ();
+         }
+
+       if (token () == ID)
+         s = advance ();
+       else
+         s = xasprintf ("anonymous:%s:%d",
+                        get_input_file_name (lexer_line.file),
+                        lexer_line.line);
+
+       /* Unfortunately above GTY_TOKEN check does not capture the
+          typedef struct_type GTY case.  */
+       if (token () == GTY_TOKEN)
+         {
+           is_gty = GTY_AFTER_ID;
            opts = gtymarker_opt ();
+         }
+
+       bool is_user_gty = opts_have (opts, "user");
+
+       if (token () == ':')
+         {
+           if (is_gty && !is_user_gty)
+             {
+               /* For GTY-marked types that are not "user", parse some C++
+                  inheritance specifications.
+                  We require single-inheritance from a non-template type.  */
+               advance ();
+               const char *basename = require (ID);
+               /* This may be either an access specifier, or the base name.  */
+               if (strcmp (basename, "public") == 0
+                   || strcmp (basename, "protected") == 0
+                   || strcmp (basename, "private") == 0)
+                 basename = require (ID);
+               base_class = find_structure (basename, TYPE_STRUCT);
+               if (!base_class)
+                 parse_error ("unrecognized base class: %s", basename);
+               require_without_advance ('{');
+             }
+           else
+             {
+               /* For types lacking GTY-markings, skip over C++ inheritance
+                  specification (and thus avoid having to parse e.g. template
+                  types).  */
+               while (token () != '{')
+                 advance ();
+             }
+         }
+
+       if (is_gty)
+         {
            if (token () == '{')
              {
                pair_p fields;
-               advance ();
-               fields = struct_field_seq ();
-               require ('}');
-               return new_structure (s, is_union, &lexer_line, fields, opts);
+
+               if (is_gty == GTY_AFTER_ID)
+                 parse_error ("GTY must be specified before identifier");
+
+               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 create_user_defined_type (s, &lexer_line);
+                 }
+
+               return new_structure (s, kind, &lexer_line, fields, opts,
+                                     base_class);
              }
          }
        else if (token () == '{')
          consume_balanced ('{', '}');
        if (opts)
          *optsp = opts;
-       return find_structure (s, is_union);
+       return find_structure (s, kind);
       }
 
+    case TYPEDEF:
+      /* In C++, a typedef inside a struct/class/union defines a new
+        type for that inner scope.  We cannot support this in
+        gengtype because we have no concept of scoping.
+
+        We handle typedefs in the global scope separately (see
+        parse_file), so if we find a 'typedef', we must be inside
+        a struct.  */
+      gcc_assert (nested);
+      parse_error ("typedefs not supported in structures marked with "
+                  "automatic GTY markers.  Use GTY((user)) to mark "
+                  "this structure.");
+      advance ();
+      return NULL;
+
     case ENUM:
       advance ();
-       if (token () == ID)
-         s = advance ();
-       else
-         s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
+      if (token () == ID)
+       s = advance ();
+      else
+       s = xasprintf ("anonymous:%s:%d",
+                      get_input_file_name (lexer_line.file),
+                      lexer_line.line);
 
       if (token () == '{')
-       consume_balanced ('{','}');
+       consume_balanced ('{', '}');
+
+      /* If after parsing the enum we are at the end of the statement,
+        and we are currently inside a structure, then this was an
+        enum declaration inside this scope.
+
+        We cannot support this for the same reason we cannot support
+        'typedef' inside structures (see the TYPEDEF handler above).
+        If this happens, emit an error and return NULL.  */
+      if (nested && token () == ';')
+       {
+         parse_error ("enum definitions not supported in structures marked "
+                      "with automatic GTY markers.  Use GTY((user)) to mark "
+                      "this structure.");
+         advance ();
+         return NULL;
+       }
+
       return create_scalar_type (s);
 
     default:
@@ -773,7 +1082,7 @@ typedef_decl (void)
 
       /* Yet another place where we could have junk (notably attributes)
         after the declarator.  */
-      another = consume_until_comma_or_semi (false);
+      another = consume_until_comma_or_eos ();
       if (dty)
        do_typedef (name, dty, &lexer_line);
     }
@@ -796,7 +1105,7 @@ struct_or_union (void)
 }
 
 /* GC root declaration:
-     (extern|static) gtymarker? type ID array_declarators_opt (';'|'=')
+   (extern|static) gtymarker? type ID array_declarators_opt (';'|'=')
    If the gtymarker is not present, we ignore the rest of the declaration.  */
 static void
 extern_or_static (void)
@@ -813,8 +1122,8 @@ extern_or_static (void)
     }
 
   opts = gtymarker ();
-  ty   = type (&opts2, true);  /* if we get here, it's got a GTY(()) */
-  dty  = declarator (ty, &name, &dopts);
+  ty = type (&opts2, true);    /* if we get here, it's got a GTY(()) */
+  dty = declarator (ty, &name, &dopts);
 
   if ((opts && dopts) || (opts && opts2) || (opts2 && dopts))
     parse_error ("GTY((...)) specified more than once for %s", name);
@@ -830,55 +1139,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
@@ -903,15 +1163,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;