Error out for Cilk_spawn or array expression in forbidden places
authorAndi Kleen <ak@linux.intel.com>
Tue, 11 Nov 2014 05:10:58 +0000 (05:10 +0000)
committerAndi Kleen <ak@gcc.gnu.org>
Tue, 11 Nov 2014 05:10:58 +0000 (05:10 +0000)
_Cilk_spawn or Cilk array expressions are only allowed on their own,
but not in for(), if(), switch, do, while, goto, etc.
The C parser didn't always check for that, which lead to ICEs earlier
for invalid code.

Add a generic helper that checks this and call it where needed
in the C frontend.

I chose to allow spawn/array for for init and increment expressions.
While the Cilk spec could be interpreted to forbid it there too
there didn't seem any reason to not allow it.

One dark corner is spawn, array in statement expressions not at
the end. Right now that's forbidden too.

gcc/c-family/:

2014-11-10  Andi Kleen  <ak@linux.intel.com>

PR c/60804
* c-common.h (check_no_cilk): Declare.
* cilk.c (get_error_location): New function.
(check_no_cilk): Dito.

gcc/c/:

2014-11-10  Andi Kleen  <ak@linux.intel.com>

PR c/60804
* c-parser.c (c_parser_statement_after_labels): Call
check_no_cilk.
(c_parser_if_statement): Dito.
(c_parser_switch_statement): Dito.
(c_parser_while_statement): Dito.
(c_parser_do_statement): Dito.
(c_parser_for_statement): Dito.
* c-typeck.c (c_finish_loop): Dito.

From-SVN: r217336

gcc/c-family/ChangeLog
gcc/c-family/c-common.h
gcc/c-family/cilk.c
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/c/c-typeck.c

index a4d0b81a7f98628a700a9251f85425bceb7dcbd9..33c7d29b8a19ef64a8910a868d7cba4cf47bb27f 100644 (file)
@@ -1,3 +1,10 @@
+2014-11-10  Andi Kleen  <ak@linux.intel.com>
+
+       PR c/60804
+       * c-common.h (check_no_cilk): Declare.
+       * cilk.c (get_error_location): New function.
+       (check_no_cilk): Dito.
+
 2014-11-10  Andi Kleen  <ak@linux.intel.com>
 
        * cilk.c (recognize_spawn): Use expression location
index 17b26ce993a123e417d9bec82866056db084fe5e..ca6fc8beaf88323e335a3bae7fecd81b664ad2bb 100644 (file)
@@ -1414,4 +1414,6 @@ extern tree cilk_install_body_pedigree_operations (tree);
 extern void cilk_outline (tree, tree *, void *);
 extern bool contains_cilk_spawn_stmt (tree);
 extern tree cilk_for_number_of_iterations (tree);
+extern bool check_no_cilk (tree, const char *, const char *,
+                          location_t loc = UNKNOWN_LOCATION);
 #endif /* ! GCC_C_COMMON_H */
index 60f7a2a514239235631b6517fe1f11683daa6a5e..a0cef4f3ab3c30221d647a97d139dd3a37b79f62 100644 (file)
@@ -1324,3 +1324,42 @@ contains_cilk_spawn_stmt (tree expr)
   return walk_tree (&expr, contains_cilk_spawn_stmt_walker, NULL, NULL)
         != NULL_TREE;
 }
+
+/* Return a error location for EXPR if LOC is not set.  */
+
+static location_t
+get_error_location (tree expr, location_t loc)
+{
+  if (loc == UNKNOWN_LOCATION)
+    {
+      if (TREE_CODE (expr) == MODIFY_EXPR)
+        expr = TREE_OPERAND (expr, 0);
+      loc = EXPR_LOCATION (expr);
+    }
+  return loc;
+}
+
+/* Check that no array notation or spawn statement is in EXPR.
+   If not true generate an error at LOC for ARRAY_GMSGID or
+   SPAWN_MSGID.  */
+
+bool
+check_no_cilk (tree expr, const char *array_msgid, const char *spawn_msgid,
+             location_t loc)
+{
+  if (!flag_cilkplus)
+    return false;
+  if (contains_array_notation_expr (expr))
+    {
+      loc = get_error_location (expr, loc);
+      error_at (loc, array_msgid);
+      return true;
+    }
+  if (walk_tree (&expr, contains_cilk_spawn_stmt_walker, NULL, NULL))
+    {
+      loc = get_error_location (expr, loc);
+      error_at (loc, spawn_msgid);
+      return true;
+    }
+  return false;
+}
index a2b3c78fec009cde5db3801c1dc62ad46e7d8fe8..c4cf2bcd684edd0c733d703159a2be6bf8aa8b23 100644 (file)
@@ -1,3 +1,15 @@
+2014-11-10  Andi Kleen  <ak@linux.intel.com>
+
+       PR c/60804
+       * c-parser.c (c_parser_statement_after_labels): Call
+       check_no_cilk.
+       (c_parser_if_statement): Dito.
+       (c_parser_switch_statement): Dito.
+       (c_parser_while_statement): Dito.
+       (c_parser_do_statement): Dito.
+       (c_parser_for_statement): Dito.
+       * c-typeck.c (c_finish_loop): Dito.
+
 2014-11-10  Paolo Carlini  <paolo.carlini@oracle.com>
 
        * c-typeck.c (build_binary_op): Use OPT_Wshift_count_negative and
index d316216cbe1dd29ab430d554db98e43542c771de..f90f6af776e9cc26224c24ba2877b2662b0b0edd 100644 (file)
@@ -4965,6 +4965,11 @@ c_parser_statement_after_labels (c_parser *parser)
 
              c_parser_consume_token (parser);
              val = c_parser_expression (parser);
+             if (check_no_cilk (val.value,
+                                "Cilk array notation cannot be used as a computed goto expression",
+                                "%<_Cilk_spawn%> statement cannot be used as a computed goto expression",
+                                loc))
+               val.value = error_mark_node;
              val = convert_lvalue_to_rvalue (loc, val, false, true);
              stmt = c_finish_goto_ptr (loc, val.value);
            }
@@ -5018,8 +5023,15 @@ c_parser_statement_after_labels (c_parser *parser)
            {
              struct c_expr expr = c_parser_expression (parser);
              expr = convert_lvalue_to_rvalue (loc, expr, false, false);
-             expr.value = c_fully_fold (expr.value, false, NULL);
-             stmt = objc_build_throw_stmt (loc, expr.value);
+             if (check_no_cilk (expr.value,
+                "Cilk array notation cannot be used for a throw expression",
+                "%<_Cilk_spawn%> statement cannot be used for a throw expression"))
+               expr.value = error_mark_node;
+             else
+               {
+                 expr.value = c_fully_fold (expr.value, false, NULL);
+                 stmt = objc_build_throw_stmt (loc, expr.value);
+               }
              goto expect_semicolon;
            }
          break;
@@ -5194,6 +5206,11 @@ c_parser_if_statement (c_parser *parser)
   block = c_begin_compound_stmt (flag_isoc99);
   loc = c_parser_peek_token (parser)->location;
   cond = c_parser_paren_condition (parser);
+  if (flag_cilkplus && contains_cilk_spawn_stmt (cond))
+    {
+      error_at (loc, "if statement cannot contain %<Cilk_spawn%>");
+      cond = error_mark_node;
+    }
   in_if_block = parser->in_if_block;
   parser->in_if_block = true;
   first_body = c_parser_if_body (parser, &first_if);
@@ -5240,13 +5257,12 @@ c_parser_switch_statement (c_parser *parser)
       ce = c_parser_expression (parser);
       ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
       expr = ce.value;
-      if (flag_cilkplus && contains_array_notation_expr (expr))
-       {
-         error_at (switch_cond_loc,
-                   "array notations cannot be used as a condition for switch "
-                   "statement");
-         expr = error_mark_node;
-       }
+      /* ??? expr has no valid location?  */
+      if (check_no_cilk (expr,
+        "Cilk array notation cannot be used as a condition for switch statement",
+        "%<_Cilk_spawn%> statement cannot be used as a condition for switch statement",
+                        switch_cond_loc))
+        expr = error_mark_node;
       c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
     }
   else
@@ -5286,13 +5302,10 @@ c_parser_while_statement (c_parser *parser, bool ivdep)
   block = c_begin_compound_stmt (flag_isoc99);
   loc = c_parser_peek_token (parser)->location;
   cond = c_parser_paren_condition (parser);
-  if (flag_cilkplus && contains_array_notation_expr (cond))
-    {
-      error_at (loc, "array notations cannot be used as a condition for while "
-               "statement");
-      cond = error_mark_node;
-    }
-
+  if (check_no_cilk (cond,
+         "Cilk array notation cannot be used as a condition for while statement",
+        "%<_Cilk_spawn%> statement cannot be used as a condition for while statement"))
+    cond = error_mark_node;
   if (ivdep && cond != error_mark_node)
     cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
                   build_int_cst (integer_type_node,
@@ -5338,12 +5351,10 @@ c_parser_do_statement (c_parser *parser, bool ivdep)
   new_cont = c_cont_label;
   c_cont_label = save_cont;
   cond = c_parser_paren_condition (parser);
-  if (flag_cilkplus && contains_array_notation_expr (cond))
-    {
-      error_at (loc, "array notations cannot be used as a condition for a "
-               "do-while statement");
-      cond = error_mark_node;
-    }
+  if (check_no_cilk (cond,
+        "Cilk array notation cannot be used as a condition for a do-while statement",
+        "%<_Cilk_spawn%> statement cannot be used as a condition for a do-while statement"))
+    cond = error_mark_node;
   if (ivdep && cond != error_mark_node)
     cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
                   build_int_cst (integer_type_node,
@@ -5495,6 +5506,8 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
            struct c_expr ce;
            tree init_expression;
            ce = c_parser_expression (parser);
+           /* In theory we could forbid _Cilk_spawn here, as the spec says "only in top
+              level statement", but it works just fine, so allow it.  */
            init_expression = ce.value;
            parser->objc_could_be_foreach_context = false;
            if (c_parser_next_token_is_keyword (parser, RID_IN))
@@ -5536,12 +5549,10 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
          else
            {
              cond = c_parser_condition (parser);
-             if (flag_cilkplus && contains_array_notation_expr (cond))
-               {
-                 error_at (loc, "array notations cannot be used in a "
-                           "condition for a for-loop");
-                 cond = error_mark_node;
-               }
+             if (check_no_cilk (cond,
+                "Cilk array notation cannot be used in a condition for a for-loop",
+                "%<_Cilk_spawn%> statement cannot be used in a condition for a for-loop"))
+               cond = error_mark_node;
              c_parser_skip_until_found (parser, CPP_SEMICOLON,
                                         "expected %<;%>");
            }
index 77ce549ca150a69795e6d7f9115136d096c2eef3..338ef44eefba190736ed1bba0f394e9e98d0c59c 100644 (file)
@@ -9622,12 +9622,8 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
 {
   tree entry = NULL, exit = NULL, t;
 
-  if (flag_cilkplus && contains_array_notation_expr (cond))
-    {
-      error_at (start_locus, "array notation expression cannot be used in a "
-               "loop%'s condition");
-      return;
-    }
+  /* In theory could forbid cilk spawn for loop increment expression,
+     but it should work just fine.  */
   
   /* If the condition is zero don't generate a loop construct.  */
   if (cond && integer_zerop (cond))