The following handles __GIMPLE as declspec which better follows other
similar handling.  It also reverts the C FE parts back to rely
on finish_function (that adjusts things like visibility - sth we'll
need in the end).  And it makes the __GIMPLE specs (currently only
startswith) optional.

Tested on x86_64-unknown-linux-gnu.

Given the similarity to attributes I'm not sure if we want to try
re-using the attribute list parsing as well as the storage during
declspec processing (I'd have to experiment with that).  At least
once we add more specs to __GIMPLE this might make things simpler.

Richard.

2016-10-28  Richard Biener  <rguent...@suse.de>

        c/
        * c-parser.c (c_parser_declaration_or_fndef): Move __GIMPLE
        parsing to declspecs parsing.  Rely on finish_function.
        (c_parser_declspecs): Handle RID_GIMPLE.
        * c-tree.h (enum c_declspec_word): Add cdw_gimple.
        (struct c_declspecs): Add gimple_pass member and gimple_p flag.
        * gimple-parser.c (c_parser_gimple_pass_list): Adjust interface,
        make specs optional and consume closing paren.
        * gimple-parser.h (c_parser_gimple_pass_list): Adjust.

        testsuite/
        * gcc.dg/gimplefe-1.c: Drop optional specs for __GIMPLE.

diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 413d8a7..2997c83 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -436,7 +436,7 @@ const struct c_common_resword c_common_reswords[] =
   { "__volatile",      RID_VOLATILE,   0 },
   { "__volatile__",    RID_VOLATILE,   0 },
   { "__GIMPLE",                RID_GIMPLE,     D_CONLY },
-  { "__PHI",           RID_PHI,        D_CONLY},
+  { "__PHI",           RID_PHI,        D_CONLY },
   { "alignas",         RID_ALIGNAS,    D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "alignof",         RID_ALIGNOF,    D_CXXONLY | D_CXX11 | D_CXXWARN },
   { "asm",             RID_ASM,        D_ASM },
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 63385fc..d21b8e9 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -159,7 +159,7 @@ struct GTY(()) c_parser {
   /* The look-ahead tokens.  */
   c_token * GTY((skip)) tokens;
   /* Buffer for look-ahead tokens.  */
-  c_token GTY(()) tokens_buf[4];
+  c_token tokens_buf[4];
   /* How many look-ahead tokens are available (0 - 4, or
      more if parsing from pre-lexed tokens).  */
   unsigned int tokens_avail;
@@ -1563,8 +1563,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
fndef_ok,
   tree all_prefix_attrs;
   bool diagnosed_no_specs = false;
   location_t here = c_parser_peek_token (parser)->location;
-  bool gimple_body_p = false;
-  char *pass = NULL;
 
   if (static_assert_ok
       && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
@@ -1650,19 +1648,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
fndef_ok,
       return;
     }
 
-  if (c_parser_next_token_is (parser, CPP_KEYWORD))
-    {
-      c_token *kw_token = c_parser_peek_token (parser);
-      if (kw_token->keyword == RID_GIMPLE)
-       {
-         gimple_body_p = true;
-         c_parser_consume_token (parser);
-         c_parser_gimple_pass_list (parser, &pass);
-         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
-                                    "expected %<)%>");
-       }
-    }
-
   finish_declspecs (specs);
   bool auto_type_p = specs->typespec_word == cts_auto_type;
   if (c_parser_next_token_is (parser, CPP_SEMICOLON))
@@ -1793,7 +1778,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
fndef_ok,
       struct c_declarator *declarator;
       bool dummy = false;
       timevar_id_t tv;
-      tree fnbody;
+      tree fnbody = NULL_TREE;
       /* Declaring either one or more declarators (in which case we
         should diagnose if there were no declaration specifiers) or a
         function definition (in which case the diagnostic for
@@ -2076,7 +2061,6 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
fndef_ok,
        c_parser_declaration_or_fndef (parser, false, false, false,
                                       true, false, NULL, vNULL);
       store_parm_decls ();
-
       if (omp_declare_simd_clauses.exists ()
          || !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
        c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
@@ -2086,23 +2070,23 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
fndef_ok,
       DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
        = c_parser_peek_token (parser)->location;
 
-      if (gimple_body_p && flag_gimple)
+      /* If the definition was marked with __GIMPLE then parse the
+         function body as GIMPLE.  */
+      if (specs->gimple_p)
        {
-         cfun->pass_startwith = pass;
+         cfun->pass_startwith = specs->gimple_pass;
          bool saved = in_late_binary_op;
          in_late_binary_op = true;
          c_parser_parse_gimple_body (parser);
          in_late_binary_op = saved;
-         cgraph_node::finalize_function (current_function_decl, false);
-         set_cfun (NULL);
-         current_function_decl = NULL;
-         timevar_pop (tv);
-         return;
        }
-
-      fnbody = c_parser_compound_statement (parser);
-      if (flag_cilkplus && contains_array_notation_expr (fnbody))
-       fnbody = expand_array_notation_exprs (fnbody);
+      else
+       {
+         fnbody = c_parser_compound_statement (parser);
+         if (flag_cilkplus && contains_array_notation_expr (fnbody))
+           fnbody = expand_array_notation_exprs (fnbody);
+       }
+      tree fndecl = current_function_decl;
       if (nested)
        {
          tree decl = current_function_decl;
@@ -2118,9 +2102,13 @@ c_parser_declaration_or_fndef (c_parser *parser, bool 
fndef_ok,
        }
       else
        {
-         add_stmt (fnbody);
+         if (fnbody)
+           add_stmt (fnbody);
          finish_function ();
        }
+      /* Get rid of the empty stmt list for GIMPLE.  */
+      if (specs->gimple_p)
+       DECL_SAVED_TREE (fndecl) = NULL_TREE;
 
       timevar_pop (tv);
       break;
@@ -2608,6 +2596,14 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs 
*specs,
          align = c_parser_alignas_specifier (parser);
          declspecs_add_alignas (loc, specs, align);
          break;
+       case RID_GIMPLE:
+         if (! flag_gimple)
+           error_at (loc, "%<__GIMPLE%> only valid with -fgimple");
+         c_parser_consume_token (parser);
+         specs->gimple_p = true;
+         specs->locations[cdw_gimple] = loc;
+         specs->gimple_pass = c_parser_gimple_pass_list (parser);
+         break;
        default:
          goto out;
        }
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index e8060f8..a8cf353 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -267,6 +267,7 @@ enum c_declspec_word {
   cdw_saturating,
   cdw_alignas,
   cdw_address_space,
+  cdw_gimple,
   cdw_number_of_elements /* This one must always be the last
                            enumerator.  */
 };
@@ -290,6 +291,8 @@ struct c_declspecs {
      NULL; attributes (possibly from multiple lists) will be passed
      separately.  */
   tree attrs;
+  /* The pass to start compiling a __GIMPLE function with.  */
+  char *gimple_pass;
   /* The base-2 log of the greatest alignment required by an _Alignas
      specifier, in bytes, or -1 if no such specifiers with nonzero
      alignment.  */
@@ -362,6 +365,8 @@ struct c_declspecs {
   /* Whether any alignment specifier (even with zero alignment) was
      specified.  */
   BOOL_BITFIELD alignas_p : 1;
+  /* Whether any __GIMPLE specifier was specified.  */
+  BOOL_BITFIELD gimple_p : 1;
   /* The address space that the declaration belongs to.  */
   addr_space_t address_space;
 };
diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
index 7040071..392f6b0 100644
--- a/gcc/c/gimple-parser.c
+++ b/gcc/c/gimple-parser.c
@@ -1046,14 +1046,15 @@ c_parser_gimple_label (c_parser *parser, gimple_seq 
*seq)
      startwith("pass-name")
  */
 
-void
-c_parser_gimple_pass_list (c_parser *parser, char **pass)
+char *
+c_parser_gimple_pass_list (c_parser *parser)
 {
-  if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-    return;
+  char *pass = NULL;
 
-  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
-    return;
+  /* Accept __GIMPLE.  */
+  if (c_parser_next_token_is_not (parser, CPP_OPEN_PAREN))
+    return NULL;
+  c_parser_consume_token (parser);
 
   if (c_parser_next_token_is (parser, CPP_NAME))
     {
@@ -1062,33 +1063,31 @@ c_parser_gimple_pass_list (c_parser *parser, char 
**pass)
       if (! strcmp (op, "startwith"))
        {
          if (! c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-           return;
+           return NULL;
          if (c_parser_next_token_is_not (parser, CPP_STRING))
            {
              error_at (c_parser_peek_token (parser)->location,
                        "expected pass name");
-             return;
+             return NULL;
            }
-         *pass = xstrdup (TREE_STRING_POINTER
+         pass = xstrdup (TREE_STRING_POINTER
                                (c_parser_peek_token (parser)->value));
          c_parser_consume_token (parser);
          if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
-           return;
+           return NULL;
        }
       else
        {
          error_at (c_parser_peek_token (parser)->location,
                    "invalid operation");
-         return;
+         return NULL;
        }
     }
-  else if (c_parser_next_token_is (parser, CPP_EOF))
-    {
-      c_parser_error (parser, "expected parameters");
-      return;
-    }
 
-  return;
+  if (! c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    return NULL;
+
+  return pass;
 }
 
 /* Parse gimple local declaration.
diff --git a/gcc/c/gimple-parser.h b/gcc/c/gimple-parser.h
index 860695b..f72b626 100644
--- a/gcc/c/gimple-parser.h
+++ b/gcc/c/gimple-parser.h
@@ -22,6 +22,6 @@ along with GCC; see the file COPYING3.  If not see
 
 /* Gimple parsing functions.  */
 extern void c_parser_parse_gimple_body (c_parser *);
-extern void c_parser_gimple_pass_list (c_parser *, char **);
+extern char *c_parser_gimple_pass_list (c_parser *);
 
 #endif
diff --git a/gcc/testsuite/gcc.dg/gimplefe-1.c 
b/gcc/testsuite/gcc.dg/gimplefe-1.c
index 0786d47..a81ed1f 100644
--- a/gcc/testsuite/gcc.dg/gimplefe-1.c
+++ b/gcc/testsuite/gcc.dg/gimplefe-1.c
@@ -2,7 +2,7 @@
 /* { dg-options "-fgimple" } */
 
 int i;
-void __GIMPLE () foo()
+void __GIMPLE foo()
 {
   i = 1;
 }

Reply via email to