diff gcc/gengtype-parse.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents f6334be47118
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/gengtype-parse.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/gengtype-parse.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,5 +1,5 @@
 /* Process source files and output type information.
-   Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2006-2017 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -17,7 +17,12 @@
    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 @@
   "union",
   "struct",
   "enum",
-  "VEC",
-  "DEF_VEC_[OP]",
-  "DEF_VEC_I",
-  "DEF_VEC_ALLOC_[IOP]",
   "...",
   "ptr_alias",
   "nested_ptr",
@@ -86,6 +87,7 @@
   "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 @@
   "'\"%s\"'",
   "\"'%s'\"",
   "'[%s]'",
+  "'%s'",
 };
 
 /* Produce a printable representation for a token defined by CODE and
@@ -163,6 +166,21 @@
   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 *
@@ -180,6 +198,24 @@
   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+
@@ -208,28 +244,89 @@
   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 *
+require_template_declaration (const char *tmpl_name)
+{
+  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)
+    {
+      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)
 {
-  if (token () == VEC_TOKEN)
-    {
-      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;
-    }
+  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 ()[]{}.  */
@@ -270,78 +367,77 @@
 }
 
 /* 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 '{':
+	consume_balanced ('{', '}');
+	return;
 
       case '(':
 	consume_balanced ('(', ')');
 	break;
+
       case '[':
 	consume_balanced ('[', ']');
 	break;
-      case '{':
-	consume_balanced ('{', '}');
-	break;
 
       case '}':
       case ']':
       case ')':
 	parse_error ("unmatched '%c' while scanning for ';'", token ());
-      return;
+	return;
 
       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 '{':
+	consume_balanced ('{', '}');
+	return false;
 
       case '(':
 	consume_balanced ('(', ')');
 	break;
+
       case '[':
 	consume_balanced ('[', ']');
 	break;
-      case '{':
-	consume_balanced ('{', '}');
-	break;
 
       case '}':
       case ']':
@@ -353,6 +449,10 @@
       case EOF_TOKEN:
 	parse_error ("unexpected end of file while scanning for ',' or ';'");
 	return false;
+
+      default:
+	advance ();
+	break;
       }
 }
 
@@ -434,7 +534,6 @@
 /* One GTY(()) option:
    ID str_optvalue_opt
    | PTR_ALIAS type_optvalue
-   | PARAM_IS type_optvalue
    | NESTED_PTR nestedptr_optvalue
 */
 static options_p
@@ -449,13 +548,14 @@
       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 ());
       advance ();
@@ -501,6 +601,8 @@
     return 0;
   return gtymarker ();
 }
+
+
 
 /* Declarators. The logic here is largely lifted from c-parser.c.
    Note that we do not have to process abstract declarators, which can
@@ -537,16 +639,21 @@
     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 ')'
+   '(' \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.  */
@@ -555,18 +662,45 @@
     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.  */
@@ -596,23 +730,26 @@
    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
@@ -620,10 +757,15 @@
    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;
@@ -632,7 +774,7 @@
       advance ();
       ty = create_pointer (ty);
     }
-  return direct_declarator (ty, namep, optsp);
+  return direct_declarator (ty, namep, optsp, in_struct);
 }
 
 /* Types and declarations.  */
@@ -641,7 +783,7 @@
    (
    type bitfield ';'
    | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
-   )+
+   )*
 
    Knows that such declarations must end with a close brace (or,
    erroneously, at EOF).
@@ -655,27 +797,36 @@
   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;
@@ -689,10 +840,21 @@
 	}
       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:
 
@@ -704,7 +866,12 @@
    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)
 {
@@ -717,13 +884,19 @@
       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;
 	/* GTY annotations follow attribute syntax
 	   GTY_BEFORE_ID is for union/struct declarations
@@ -734,14 +907,14 @@
 	  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(())
 	   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;
@@ -763,6 +936,37 @@
 	    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 (0 == strcmp (basename, "public")
+		    || 0 == strcmp (basename, "protected")
+		    || 0 == strcmp (basename, "private"))
+		  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 () == '{')
@@ -772,19 +976,47 @@
 		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 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)
@@ -796,6 +1028,23 @@
 
       if (token () == '{')
 	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:
@@ -833,7 +1082,7 @@
 
       /* 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);
     }
@@ -890,55 +1139,6 @@
     }
 }
 
-/* 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
@@ -963,15 +1163,6 @@
 	  typedef_decl ();
 	  break;
 
-	case DEFVEC_OP:
-	case DEFVEC_I:
-	  def_vec ();
-	  break;
-
-	case DEFVEC_ALLOC:
-	  def_vec_alloc ();
-	  break;
-
 	case EOF_TOKEN:
 	  goto eof;