From cd2a72c10f54135631f2c23865cc5d5f5360109a Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Thu, 20 Jul 2017 12:37:47 -0400
Subject: [PATCH 04/26] C frontend: capture BLT information

This patch extends the C frontend so that it optionally builds a BLT tree,
by using an auto_blt_node class within the recursive descent through the
parser, so that its ctor/dtors build the blt_node hierarchy; this is
rapidly (I hope) rejected in the no -fblt case, so that nothing is built
by default.

gcc/c/ChangeLog:
	* c-decl.c: Include "blt.h".
	(build_array_declarator): Initialize bltnode field of new
	declarator.
	(start_decl): Associate this decl with any bltnode of the
	declarator.
	(start_function): Likewise.
	(build_attrs_declarator): Initialize bltnode field of new
	declarator.
	(build_function_declarator): Add bltnode param, and use it to
	initialize the bltnode field of the new declarator.
	(build_id_declarator): Likewise.
	(make_pointer_declarator): Likewise.
	* c-parser.c: Include "blt.h".
	(struct c_parser): Add fields "last_token_location",
	"blt_root_node", "blt_current_node".
	(class auto_blt_node): New class.
	(AUTO_BLT_NODE): New macro.
	(CURRENT_BLT_NODE): New macro.
	(auto_blt_node::auto_blt_node): New ctor.
	(auto_blt_node::~auto_blt_node): New dtor.
	(auto_blt_node::set_tree): New method.
	(c_parser_consume_token): Update last_token_location.
	(c_parser_translation_unit): Add AUTO_BLT_NODE.
	(c_parser_external_declaration): Likewise.
	(c_parser_declspecs): Likewise, in multiple places.
	(c_parser_struct_or_union_specifier): Likewise.  Set the tree
	on the struct-contents and the struct-or-union-specifier.
	(c_parser_struct_declaration): Add AUTO_BLT_NODE.
	(c_parser_declarator): Likewise.
	(c_parser_direct_declarator): Likewise.  Set up the bltnode of
	the declarator.
	(c_parser_direct_declarator_inner): Pass the bltnode to the
	declarator.
	(c_parser_parms_declarator): Add AUTO_BLT_NODE.
	(c_parser_parameter_declaration): Likewise.
	(c_parser_expr_no_commas): Likewise.
	(c_parser_expression): Likewise.
	(c_parser_expr_list): Likewise.
	(c_parse_file): Handle -fdump-blt; set the_blt_root_node.
	* c-tree.h (class blt_node): Add forward decl.
	(struct c_declarator): Add "bltnode" field.
	(build_function_declarator): Add blt_node * param.
---
 gcc/c/c-decl.c   |  13 ++-
 gcc/c/c-parser.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++---------
 gcc/c/c-tree.h   |   6 +-
 3 files changed, 221 insertions(+), 39 deletions(-)

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 50da185..ff27e55 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -54,6 +54,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
 #include "asan.h"
+#include "blt.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -4503,6 +4504,7 @@ build_array_declarator (location_t loc,
 	}
       current_scope->had_vla_unspec = true;
     }
+  declarator->bltnode = NULL;
   return declarator;
 }
 
@@ -4627,6 +4629,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
 			 deprecated_state);
   if (!decl || decl == error_mark_node)
     return NULL_TREE;
+  if (declarator->bltnode)
+    declarator->bltnode->set_tree (decl);
 
   if (expr)
     add_stmt (fold_convert (void_type_node, expr));
@@ -8527,6 +8531,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
 
   decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
 			  &attributes, NULL, NULL, DEPRECATED_NORMAL);
+  if (declarator->bltnode)
+    declarator->bltnode->set_tree (decl1);
   invoke_plugin_callbacks (PLUGIN_START_PARSE_FUNCTION, decl1);
 
   /* If the declarator is not suitable for a function definition,
@@ -9645,6 +9651,7 @@ build_attrs_declarator (tree attrs, struct c_declarator *target)
   ret->kind = cdk_attrs;
   ret->declarator = target;
   ret->u.attrs = attrs;
+  ret->bltnode = NULL;
   return ret;
 }
 
@@ -9653,12 +9660,14 @@ build_attrs_declarator (tree attrs, struct c_declarator *target)
 
 struct c_declarator *
 build_function_declarator (struct c_arg_info *args,
-			   struct c_declarator *target)
+			   struct c_declarator *target,
+			   blt_node *bltnode)
 {
   struct c_declarator *ret = XOBNEW (&parser_obstack, struct c_declarator);
   ret->kind = cdk_function;
   ret->declarator = target;
   ret->u.arg_info = args;
+  ret->bltnode = bltnode;
   return ret;
 }
 
@@ -9674,6 +9683,7 @@ build_id_declarator (tree ident)
   ret->u.id = ident;
   /* Default value - may get reset to a more precise location. */
   ret->id_loc = input_location;
+  ret->bltnode = NULL;
   return ret;
 }
 
@@ -9700,6 +9710,7 @@ make_pointer_declarator (struct c_declspecs *type_quals_attrs,
   ret->kind = cdk_pointer;
   ret->declarator = itarget;
   ret->u.pointer_quals = quals;
+  ret->bltnode = NULL;
   return ret;
 }
 
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index f8fbc92..119ae23 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "read-rtl-function.h"
 #include "run-rtl-passes.h"
 #include "intl.h"
+#include "blt.h"
 
 /* We need to walk over decls with incomplete struct/union/enum types
    after parsing the whole translation unit.
@@ -206,8 +207,115 @@ struct GTY(()) c_parser {
   /* Buffer to hold all the tokens from parsing the vector attribute for the
      SIMD-enabled functions (formerly known as elemental functions).  */
   vec <c_token, va_gc> *cilk_simd_fn_tokens;
+
+  location_t last_token_location;
+  blt_node * GTY((skip)) blt_root_node;
+  blt_node * GTY((skip)) blt_current_node;
+};
+
+/* A RAII-style class for optionally building a concrete parse tree (or
+   at least, something close to it) as the recursive descent parser runs.
+
+   Close to a no-op if -fblt is not selected.  */
+
+class auto_blt_node
+{
+public:
+  auto_blt_node (c_parser* parser, enum blt_kind kind);
+  ~auto_blt_node ();
+
+  void set_tree (tree node);
+
+private:
+  c_parser *m_parser;
 };
 
+/* RAII-style construction of the blt_node tree: push a blt_node of KIND
+   onto the current stack of blt_nodes, popping it when it goes out
+   of scope.  */
+
+#define AUTO_BLT_NODE(PARSER, KIND) \
+  auto_blt_node tmp_blt_node ((PARSER), (KIND))
+
+/* The blt_node currently being constructed (the macro assumes that "parser"
+   exists in the current scope).  */
+
+#define CURRENT_BLT_NODE (parser->blt_current_node)
+
+/* auto_blt_node's constructor.
+
+   If -fblt was not enabled, return immediately.
+
+   Otherwise push a new blt_node of KIND as a child of the previous top
+   of the blt stack, effectively constructing a tree.
+
+   Set the new blt_node's start location to that of the next token
+   within PARSER.  */
+
+auto_blt_node::auto_blt_node (c_parser *parser, enum blt_kind kind)
+{
+  if (!flag_blt)
+    return;
+
+  /* Do this here rather than as an initializer
+     to avoid doing work when -fblt is not set.  */
+  m_parser = parser;
+
+  c_token *first_token = c_parser_peek_token (parser);
+  blt_node *parent = parser->blt_current_node;
+  blt_node *node = new blt_node (kind, first_token->location);
+  parser->blt_current_node = node;
+  if (parent)
+    parent->add_child (node);
+  else
+    parser->blt_root_node = node;
+}
+
+/* auto_blt_node's destructor.
+
+   If -fblt was not enabled, return immediately.
+
+   Otherwise, pop the current blt_node from the stack,
+   and set its finish location to that of the last
+   token that was consumed.  */
+
+auto_blt_node::~auto_blt_node ()
+{
+  if (!flag_blt)
+    return;
+
+  blt_node *node = m_parser->blt_current_node;
+  node->set_finish (m_parser->last_token_location);
+
+  if (0)
+    {
+      location_t start = node->get_start ();
+      location_t finish = node->get_finish ();
+      location_t range = make_location (start, start, finish);
+      inform (range, "%qs", node->get_name ());
+    }
+
+#if 0
+  if (m_expr_ptr)
+    node->set_tree (m_expr_ptr->get_value ());
+#endif
+
+  m_parser->blt_current_node = node->get_parent ();
+}
+
+/* Set the current blt_node's tree to be TREE_NODE.
+   Do nothing if -fblt is not set.  */
+
+void
+auto_blt_node::set_tree (tree tree_node)
+{
+  if (!flag_blt)
+    return;
+
+  blt_node *node = m_parser->blt_current_node;
+  node->set_tree (tree_node);
+}
+
 /* Return a pointer to the Nth token in PARSERs tokens_buf.  */
 
 c_token *
@@ -770,6 +878,7 @@ c_parser_consume_token (c_parser *parser)
   gcc_assert (parser->tokens[0].type != CPP_EOF);
   gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
   gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
+  parser->last_token_location = parser->tokens[0].location;
   if (parser->tokens != &parser->tokens_buf[0])
     parser->tokens++;
   else if (parser->tokens_avail == 2)
@@ -1336,6 +1445,8 @@ static void c_parser_parse_rtl_body (c_parser *parser, char *start_with_pass);
 static void
 c_parser_translation_unit (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_TRANSLATION_UNIT);
+
   if (c_parser_next_token_is (parser, CPP_EOF))
     {
       pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
@@ -1388,6 +1499,8 @@ c_parser_translation_unit (c_parser *parser)
 static void
 c_parser_external_declaration (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_EXTERNAL_DECLARATION);
+
   int ext;
   switch (c_parser_peek_token (parser)->type)
     {
@@ -2378,6 +2491,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 		    bool alignspec_ok, bool auto_type_ok,
 		    enum c_lookahead_kind la)
 {
+  AUTO_BLT_NODE (parser, BLT_DECLARATION_SPECIFIERS);
+
   bool attrs_ok = start_attr_ok;
   bool seen_type = specs->typespec_kind != ctsk_none;
 
@@ -2427,6 +2542,8 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  if (seen_type || !c_parser_next_tokens_start_typename (parser, la))
 	    break;
 
+	  AUTO_BLT_NODE (parser, BLT_TYPE_SPECIFIER);
+
 	  /* Now at an unknown typename (C_ID_ID), a C_ID_TYPENAME or
 	     a C_ID_CLASSNAME.  */
 	  c_parser_consume_token (parser);
@@ -2524,48 +2641,61 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	case RID_INT_N_1:
 	case RID_INT_N_2:
 	case RID_INT_N_3:
-	  if (!typespec_ok)
-	    goto out;
-	  attrs_ok = true;
-	  seen_type = true;
-	  if (c_dialect_objc ())
-	    parser->objc_need_raw_identifier = true;
-	  t.kind = ctsk_resword;
-	  t.spec = c_parser_peek_token (parser)->value;
-	  t.expr = NULL_TREE;
-	  t.expr_const_operands = true;
-	  declspecs_add_type (loc, specs, t);
-	  c_parser_consume_token (parser);
+	  {
+	    if (!typespec_ok)
+	      goto out;
+
+	    AUTO_BLT_NODE (the_parser, BLT_TYPE_SPECIFIER);
+	    attrs_ok = true;
+	    seen_type = true;
+	    if (c_dialect_objc ())
+	      parser->objc_need_raw_identifier = true;
+	    t.kind = ctsk_resword;
+	    t.spec = c_parser_peek_token (parser)->value;
+	    t.expr = NULL_TREE;
+	    t.expr_const_operands = true;
+	    declspecs_add_type (loc, specs, t);
+	    c_parser_consume_token (parser);
+	  }
 	  break;
 	case RID_ENUM:
-	  if (!typespec_ok)
-	    goto out;
-	  attrs_ok = true;
-	  seen_type = true;
-	  t = c_parser_enum_specifier (parser);
-          invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
-	  declspecs_add_type (loc, specs, t);
+	  {
+	    if (!typespec_ok)
+	      goto out;
+	    AUTO_BLT_NODE (the_parser, BLT_TYPE_SPECIFIER);
+	    attrs_ok = true;
+	    seen_type = true;
+	    t = c_parser_enum_specifier (parser);
+	    invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
+	    declspecs_add_type (loc, specs, t);
+	  }
 	  break;
 	case RID_STRUCT:
 	case RID_UNION:
-	  if (!typespec_ok)
-	    goto out;
-	  attrs_ok = true;
-	  seen_type = true;
-	  t = c_parser_struct_or_union_specifier (parser);
-          invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
-	  declspecs_add_type (loc, specs, t);
+	  {
+	    if (!typespec_ok)
+	      goto out;
+	    AUTO_BLT_NODE (the_parser, BLT_TYPE_SPECIFIER);
+	    attrs_ok = true;
+	    seen_type = true;
+	    t = c_parser_struct_or_union_specifier (parser);
+	    invoke_plugin_callbacks (PLUGIN_FINISH_TYPE, t.spec);
+	    declspecs_add_type (loc, specs, t);
+	  }
 	  break;
 	case RID_TYPEOF:
-	  /* ??? The old parser rejected typeof after other type
-	     specifiers, but is a syntax error the best way of
-	     handling this?  */
-	  if (!typespec_ok || seen_type)
-	    goto out;
-	  attrs_ok = true;
-	  seen_type = true;
-	  t = c_parser_typeof_specifier (parser);
-	  declspecs_add_type (loc, specs, t);
+	  {
+	    /* ??? The old parser rejected typeof after other type
+	       specifiers, but is a syntax error the best way of
+	       handling this?  */
+	    if (!typespec_ok || seen_type)
+	      goto out;
+	    AUTO_BLT_NODE (the_parser, BLT_TYPE_SPECIFIER);
+	    attrs_ok = true;
+	    seen_type = true;
+	    t = c_parser_typeof_specifier (parser);
+	    declspecs_add_type (loc, specs, t);
+	  }
 	  break;
 	case RID_ATOMIC:
 	  /* C parser handling of Objective-C constructs needs
@@ -2863,6 +2993,8 @@ c_parser_enum_specifier (c_parser *parser)
 static struct c_typespec
 c_parser_struct_or_union_specifier (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_STRUCT_OR_UNION_SPECIFIER);
+
   struct c_typespec ret;
   tree attrs;
   tree ident = NULL_TREE;
@@ -2898,6 +3030,8 @@ c_parser_struct_or_union_specifier (c_parser *parser)
     {
       /* Parse a struct or union definition.  Start the scope of the
 	 tag before parsing components.  */
+      AUTO_BLT_NODE (parser, BLT_STRUCT_CONTENTS);
+
       struct c_struct_parse_info *struct_info;
       tree type = start_struct (struct_loc, code, ident, &struct_info);
       tree postfix_attrs;
@@ -3006,6 +3140,10 @@ c_parser_struct_or_union_specifier (c_parser *parser)
       ret.expr = NULL_TREE;
       ret.expr_const_operands = true;
       timevar_pop (TV_PARSE_STRUCT);
+
+      if (CURRENT_BLT_NODE)
+	CURRENT_BLT_NODE->set_tree (ret.spec);
+
       return ret;
     }
   else if (!ident)
@@ -3017,7 +3155,12 @@ c_parser_struct_or_union_specifier (c_parser *parser)
       ret.expr_const_operands = true;
       return ret;
     }
+
   ret = parser_xref_tag (ident_loc, code, ident);
+
+  if (CURRENT_BLT_NODE)
+    CURRENT_BLT_NODE->set_tree (ret.spec);
+
   return ret;
 }
 
@@ -3056,6 +3199,8 @@ c_parser_struct_or_union_specifier (c_parser *parser)
 static tree
 c_parser_struct_declaration (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_STRUCT_DECLARATION);
+
   struct c_declspecs *specs;
   tree prefix_attrs;
   tree all_prefix_attrs;
@@ -3393,6 +3538,8 @@ struct c_declarator *
 c_parser_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 		     bool *seen_id)
 {
+  AUTO_BLT_NODE (parser, BLT_DECLARATOR);
+
   /* Parse any initial pointer part.  */
   if (c_parser_next_token_is (parser, CPP_MULT))
     {
@@ -3419,6 +3566,8 @@ static struct c_declarator *
 c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 			    bool *seen_id)
 {
+  AUTO_BLT_NODE (parser, BLT_DIRECT_DECLARATOR);
+
   /* The direct declarator must start with an identifier (possibly
      omitted) or a parenthesized declarator (possibly abstract).  In
      an ordinary declarator, initial parentheses must start a
@@ -3462,6 +3611,7 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
     {
       struct c_declarator *inner
 	= build_id_declarator (c_parser_peek_token (parser)->value);
+      inner->bltnode = CURRENT_BLT_NODE;
       *seen_id = true;
       inner->id_loc = c_parser_peek_token (parser)->location;
       c_parser_consume_token (parser);
@@ -3498,7 +3648,8 @@ c_parser_direct_declarator (c_parser *parser, bool type_seen_p, c_dtr_syn kind,
 	    {
 	      inner
 		= build_function_declarator (args,
-					     build_id_declarator (NULL_TREE));
+					     build_id_declarator (NULL_TREE),
+					     CURRENT_BLT_NODE);
 	      return c_parser_direct_declarator_inner (parser, *seen_id,
 						       inner);
 	    }
@@ -3646,7 +3797,7 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
 	return NULL;
       else
 	{
-	  inner = build_function_declarator (args, inner);
+	  inner = build_function_declarator (args, inner, CURRENT_BLT_NODE);
 	  return c_parser_direct_declarator_inner (parser, id_present, inner);
 	}
     }
@@ -3661,6 +3812,8 @@ c_parser_direct_declarator_inner (c_parser *parser, bool id_present,
 static struct c_arg_info *
 c_parser_parms_declarator (c_parser *parser, bool id_list_ok, tree attrs)
 {
+  AUTO_BLT_NODE (parser, BLT_PARAMETER_LIST);
+
   push_scope ();
   declare_parm_level ();
   /* If the list starts with an identifier, it is an identifier list.
@@ -3832,6 +3985,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
 static struct c_parm *
 c_parser_parameter_declaration (c_parser *parser, tree attrs)
 {
+  AUTO_BLT_NODE (parser, BLT_PARAMETER_DECLARATION);
+
   struct c_declspecs *specs;
   struct c_declarator *declarator;
   tree prefix_attrs;
@@ -6422,6 +6577,8 @@ static struct c_expr
 c_parser_expr_no_commas (c_parser *parser, struct c_expr *after,
 			 tree omp_atomic_lhs)
 {
+  AUTO_BLT_NODE (parser, BLT_ASSIGNMENT_EXPRESSION);
+
   struct c_expr lhs, rhs, ret;
   enum tree_code code;
   location_t op_location, exp_location;
@@ -8655,6 +8812,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
 static struct c_expr
 c_parser_expression (c_parser *parser)
 {
+  AUTO_BLT_NODE (parser, BLT_EXPRESSION);
+
   location_t tloc = c_parser_peek_token (parser)->location;
   struct c_expr expr;
   expr = c_parser_expr_no_commas (parser, NULL);
@@ -8742,6 +8901,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
 		    vec<location_t> *locations,
 		    unsigned int *literal_zero_mask)
 {
+  AUTO_BLT_NODE (parser, BLT_NONEMPTY_EXPR_LIST);
+
   vec<tree, va_gc> *ret;
   vec<tree, va_gc> *orig_types;
   struct c_expr expr;
@@ -18166,6 +18327,12 @@ c_parse_file (void)
     using_eh_for_cleanups ();
 
   c_parser_translation_unit (the_parser);
+
+  if (flag_blt && flag_dump_blt)
+    the_parser->blt_root_node->dump (stderr);
+
+  the_blt_root_node = the_parser->blt_root_node;
+
   the_parser = NULL;
 }
 
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index a8197eb..9455fcf 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-common.h"
 #include "diagnostic.h"
 
+class blt_node;
+
 /* struct lang_identifier is private to c-decl.c, but langhooks.c needs to
    know how big it is.  This is sanity-checked in c-decl.c.  */
 #define C_SIZEOF_STRUCT_LANG_IDENTIFIER \
@@ -451,6 +453,7 @@ struct c_declarator {
     /* For attributes.  */
     tree attrs;
   } u;
+  blt_node *bltnode;
 };
 
 /* A type name.  */
@@ -577,7 +580,8 @@ extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
 extern struct c_declarator *build_attrs_declarator (tree,
 						    struct c_declarator *);
 extern struct c_declarator *build_function_declarator (struct c_arg_info *,
-						       struct c_declarator *);
+						       struct c_declarator *,
+						       blt_node *);
 extern struct c_declarator *build_id_declarator (tree);
 extern struct c_declarator *make_pointer_declarator (struct c_declspecs *,
 						     struct c_declarator *);
-- 
1.8.5.3

