Commit e5e44252 by Andi Kleen Committed by Andi Kleen

Error out for Cilk_spawn or array expression in forbidden places

_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
parent 30055330
2014-11-10 Andi Kleen <ak@linux.intel.com> 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 * cilk.c (recognize_spawn): Use expression location
for error message. for error message.
......
...@@ -1414,4 +1414,6 @@ extern tree cilk_install_body_pedigree_operations (tree); ...@@ -1414,4 +1414,6 @@ extern tree cilk_install_body_pedigree_operations (tree);
extern void cilk_outline (tree, tree *, void *); extern void cilk_outline (tree, tree *, void *);
extern bool contains_cilk_spawn_stmt (tree); extern bool contains_cilk_spawn_stmt (tree);
extern tree cilk_for_number_of_iterations (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 */ #endif /* ! GCC_C_COMMON_H */
...@@ -1324,3 +1324,42 @@ contains_cilk_spawn_stmt (tree expr) ...@@ -1324,3 +1324,42 @@ contains_cilk_spawn_stmt (tree expr)
return walk_tree (&expr, contains_cilk_spawn_stmt_walker, NULL, NULL) return walk_tree (&expr, contains_cilk_spawn_stmt_walker, NULL, NULL)
!= NULL_TREE; != 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;
}
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> 2014-11-10 Paolo Carlini <paolo.carlini@oracle.com>
* c-typeck.c (build_binary_op): Use OPT_Wshift_count_negative and * c-typeck.c (build_binary_op): Use OPT_Wshift_count_negative and
......
...@@ -4965,6 +4965,11 @@ c_parser_statement_after_labels (c_parser *parser) ...@@ -4965,6 +4965,11 @@ c_parser_statement_after_labels (c_parser *parser)
c_parser_consume_token (parser); c_parser_consume_token (parser);
val = c_parser_expression (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); val = convert_lvalue_to_rvalue (loc, val, false, true);
stmt = c_finish_goto_ptr (loc, val.value); stmt = c_finish_goto_ptr (loc, val.value);
} }
...@@ -5018,8 +5023,15 @@ c_parser_statement_after_labels (c_parser *parser) ...@@ -5018,8 +5023,15 @@ c_parser_statement_after_labels (c_parser *parser)
{ {
struct c_expr expr = c_parser_expression (parser); struct c_expr expr = c_parser_expression (parser);
expr = convert_lvalue_to_rvalue (loc, expr, false, false); expr = convert_lvalue_to_rvalue (loc, expr, false, false);
expr.value = c_fully_fold (expr.value, false, NULL); if (check_no_cilk (expr.value,
stmt = objc_build_throw_stmt (loc, 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; goto expect_semicolon;
} }
break; break;
...@@ -5194,6 +5206,11 @@ c_parser_if_statement (c_parser *parser) ...@@ -5194,6 +5206,11 @@ c_parser_if_statement (c_parser *parser)
block = c_begin_compound_stmt (flag_isoc99); block = c_begin_compound_stmt (flag_isoc99);
loc = c_parser_peek_token (parser)->location; loc = c_parser_peek_token (parser)->location;
cond = c_parser_paren_condition (parser); 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; in_if_block = parser->in_if_block;
parser->in_if_block = true; parser->in_if_block = true;
first_body = c_parser_if_body (parser, &first_if); first_body = c_parser_if_body (parser, &first_if);
...@@ -5240,13 +5257,12 @@ c_parser_switch_statement (c_parser *parser) ...@@ -5240,13 +5257,12 @@ c_parser_switch_statement (c_parser *parser)
ce = c_parser_expression (parser); ce = c_parser_expression (parser);
ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false); ce = convert_lvalue_to_rvalue (switch_cond_loc, ce, true, false);
expr = ce.value; expr = ce.value;
if (flag_cilkplus && contains_array_notation_expr (expr)) /* ??? expr has no valid location? */
{ if (check_no_cilk (expr,
error_at (switch_cond_loc, "Cilk array notation cannot be used as a condition for switch statement",
"array notations cannot be used as a condition for switch " "%<_Cilk_spawn%> statement cannot be used as a condition for switch statement",
"statement"); switch_cond_loc))
expr = error_mark_node; expr = error_mark_node;
}
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>"); c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
} }
else else
...@@ -5286,13 +5302,10 @@ c_parser_while_statement (c_parser *parser, bool ivdep) ...@@ -5286,13 +5302,10 @@ c_parser_while_statement (c_parser *parser, bool ivdep)
block = c_begin_compound_stmt (flag_isoc99); block = c_begin_compound_stmt (flag_isoc99);
loc = c_parser_peek_token (parser)->location; loc = c_parser_peek_token (parser)->location;
cond = c_parser_paren_condition (parser); cond = c_parser_paren_condition (parser);
if (flag_cilkplus && contains_array_notation_expr (cond)) if (check_no_cilk (cond,
{ "Cilk array notation cannot be used as a condition for while statement",
error_at (loc, "array notations cannot be used as a condition for while " "%<_Cilk_spawn%> statement cannot be used as a condition for while statement"))
"statement"); cond = error_mark_node;
cond = error_mark_node;
}
if (ivdep && cond != error_mark_node) if (ivdep && cond != error_mark_node)
cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node, build_int_cst (integer_type_node,
...@@ -5338,12 +5351,10 @@ c_parser_do_statement (c_parser *parser, bool ivdep) ...@@ -5338,12 +5351,10 @@ c_parser_do_statement (c_parser *parser, bool ivdep)
new_cont = c_cont_label; new_cont = c_cont_label;
c_cont_label = save_cont; c_cont_label = save_cont;
cond = c_parser_paren_condition (parser); cond = c_parser_paren_condition (parser);
if (flag_cilkplus && contains_array_notation_expr (cond)) if (check_no_cilk (cond,
{ "Cilk array notation cannot be used as a condition for a do-while statement",
error_at (loc, "array notations cannot be used as a condition for a " "%<_Cilk_spawn%> statement cannot be used as a condition for a do-while statement"))
"do-while statement"); cond = error_mark_node;
cond = error_mark_node;
}
if (ivdep && cond != error_mark_node) if (ivdep && cond != error_mark_node)
cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond, cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
build_int_cst (integer_type_node, build_int_cst (integer_type_node,
...@@ -5495,6 +5506,8 @@ c_parser_for_statement (c_parser *parser, bool ivdep) ...@@ -5495,6 +5506,8 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
struct c_expr ce; struct c_expr ce;
tree init_expression; tree init_expression;
ce = c_parser_expression (parser); 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; init_expression = ce.value;
parser->objc_could_be_foreach_context = false; parser->objc_could_be_foreach_context = false;
if (c_parser_next_token_is_keyword (parser, RID_IN)) if (c_parser_next_token_is_keyword (parser, RID_IN))
...@@ -5536,12 +5549,10 @@ c_parser_for_statement (c_parser *parser, bool ivdep) ...@@ -5536,12 +5549,10 @@ c_parser_for_statement (c_parser *parser, bool ivdep)
else else
{ {
cond = c_parser_condition (parser); cond = c_parser_condition (parser);
if (flag_cilkplus && contains_array_notation_expr (cond)) if (check_no_cilk (cond,
{ "Cilk array notation cannot be used in a condition for a for-loop",
error_at (loc, "array notations cannot be used in a " "%<_Cilk_spawn%> statement cannot be used in a condition for a for-loop"))
"condition for a for-loop"); cond = error_mark_node;
cond = error_mark_node;
}
c_parser_skip_until_found (parser, CPP_SEMICOLON, c_parser_skip_until_found (parser, CPP_SEMICOLON,
"expected %<;%>"); "expected %<;%>");
} }
......
...@@ -9622,12 +9622,8 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body, ...@@ -9622,12 +9622,8 @@ c_finish_loop (location_t start_locus, tree cond, tree incr, tree body,
{ {
tree entry = NULL, exit = NULL, t; tree entry = NULL, exit = NULL, t;
if (flag_cilkplus && contains_array_notation_expr (cond)) /* In theory could forbid cilk spawn for loop increment expression,
{ but it should work just fine. */
error_at (start_locus, "array notation expression cannot be used in a "
"loop%'s condition");
return;
}
/* If the condition is zero don't generate a loop construct. */ /* If the condition is zero don't generate a loop construct. */
if (cond && integer_zerop (cond)) if (cond && integer_zerop (cond))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment