From e5e442524724592b9f6e969354ba33c4f20f6ab2 Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Tue, 11 Nov 2014 05:10:58 +0000 Subject: [PATCH] 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 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 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 | 7 +++++ gcc/c-family/c-common.h | 2 ++ gcc/c-family/cilk.c | 39 ++++++++++++++++++++++++ gcc/c/ChangeLog | 12 ++++++++ gcc/c/c-parser.c | 67 ++++++++++++++++++++++++----------------- gcc/c/c-typeck.c | 8 ++--- 6 files changed, 101 insertions(+), 34 deletions(-) diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index a4d0b81a7f9..33c7d29b8a1 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,10 @@ +2014-11-10 Andi Kleen + + 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 * cilk.c (recognize_spawn): Use expression location diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 17b26ce993a..ca6fc8beaf8 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -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 */ diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c index 60f7a2a5142..a0cef4f3ab3 100644 --- a/gcc/c-family/cilk.c +++ b/gcc/c-family/cilk.c @@ -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; +} diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index a2b3c78fec0..c4cf2bcd684 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,15 @@ +2014-11-10 Andi Kleen + + 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 * c-typeck.c (build_binary_op): Use OPT_Wshift_count_negative and diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index d316216cbe1..f90f6af776e 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -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 %"); + 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 %<;%>"); } diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 77ce549ca15..338ef44eefb 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -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)) -- 2.30.2