Hi! In OpenMP 5.0, depend clause operands are location list items, which are either lvalue expressions, or array sections. In C++ it is easy to handle it with tentative parsing, in C I have to use similar hacks to what is used for declare simd.
Tested on x86_64-linux, committed to gomp-5_0-branch. 2017-05-09 Jakub Jelinek <ja...@redhat.com> c/ * c-parser.c (c_parser_omp_variable_list): For OMP_CLAUSE_DEPEND, parse clause operands as either an array section, or lvalue assignment expression. * c-typeck.c (c_finish_omp_clauses): Allow any lvalue as OMP_CLAUSE_DEPEND operand (besides array section), adjust diagnostics. cp/ * parser.c (cp_parser_omp_var_list_no_open): For OMP_CLAUSE_DEPEND, parse clause operands as either an array section, or lvalue assignment expression. * semantics.c (finish_omp_clauses): Allow any lvalue as OMP_CLAUSE_DEPEND operand (besides array section), adjust diagnostics. testsuite/ * c-c++-common/gomp/depend-5.c: New test. * c-c++-common/gomp/depend-6.c: New test. --- gcc/c/c-parser.c.jj 2017-05-04 15:27:33.306131900 +0200 +++ gcc/c/c-parser.c 2017-05-09 14:05:46.874354097 +0200 @@ -10737,13 +10737,87 @@ c_parser_omp_variable_list (c_parser *pa location_t clause_loc, enum omp_clause_code kind, tree list) { - if (c_parser_next_token_is_not (parser, CPP_NAME) - || c_parser_peek_token (parser)->id_kind != C_ID_ID) + auto_vec<c_token> tokens; + unsigned int tokens_avail = 0; + + if (kind != OMP_CLAUSE_DEPEND + && (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID)) c_parser_error (parser, "expected identifier"); - while (c_parser_next_token_is (parser, CPP_NAME) - && c_parser_peek_token (parser)->id_kind == C_ID_ID) + while (kind == OMP_CLAUSE_DEPEND + || (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID)) { + bool array_section_p = false; + if (kind == OMP_CLAUSE_DEPEND) + { + if (c_parser_next_token_is_not (parser, CPP_NAME) + || c_parser_peek_token (parser)->id_kind != C_ID_ID) + { + struct c_expr expr = c_parser_expr_no_commas (parser, NULL); + if (expr.value != error_mark_node) + { + tree u = build_omp_clause (clause_loc, kind); + OMP_CLAUSE_DECL (u) = expr.value; + OMP_CLAUSE_CHAIN (u) = list; + list = u; + } + + if (c_parser_next_token_is_not (parser, CPP_COMMA)) + break; + + c_parser_consume_token (parser); + continue; + } + + tokens.truncate (0); + unsigned int nesting_depth = 0; + while (1) + { + c_token *token = c_parser_peek_token (parser); + switch (token->type) + { + case CPP_EOF: + case CPP_PRAGMA_EOL: + break; + case CPP_OPEN_BRACE: + case CPP_OPEN_PAREN: + case CPP_OPEN_SQUARE: + ++nesting_depth; + goto add; + case CPP_CLOSE_BRACE: + case CPP_CLOSE_PAREN: + case CPP_CLOSE_SQUARE: + if (nesting_depth-- == 0) + break; + goto add; + case CPP_COMMA: + if (nesting_depth == 0) + break; + goto add; + default: + add: + tokens.safe_push (*token); + c_parser_consume_token (parser); + continue; + } + break; + } + + /* Make sure nothing tries to read past the end of the tokens. */ + c_token eof_token; + memset (&eof_token, 0, sizeof (eof_token)); + eof_token.type = CPP_EOF; + tokens.safe_push (eof_token); + tokens.safe_push (eof_token); + + tokens_avail = parser->tokens_avail; + gcc_assert (parser->tokens == &parser->tokens_buf[0]); + parser->tokens = tokens.address (); + parser->tokens_avail = tokens.length (); + } + tree t = lookup_name (c_parser_peek_token (parser)->value); if (t == NULL_TREE) @@ -10819,6 +10893,7 @@ c_parser_omp_variable_list (c_parser *pa t = error_mark_node; break; } + array_section_p = true; if (!c_parser_next_token_is (parser, CPP_CLOSE_SQUARE)) { location_t expr_loc @@ -10839,6 +10914,30 @@ c_parser_omp_variable_list (c_parser *pa t = tree_cons (low_bound, length, t); } + if (kind == OMP_CLAUSE_DEPEND + && t != error_mark_node + && parser->tokens_avail != 2) + { + if (array_section_p) + { + error_at (c_parser_peek_token (parser)->location, + "expected %<)%> or %<,%>"); + t = error_mark_node; + } + else + { + parser->tokens = tokens.address (); + parser->tokens_avail = tokens.length (); + + t = c_parser_expr_no_commas (parser, NULL).value; + if (t != error_mark_node && parser->tokens_avail != 2) + { + error_at (c_parser_peek_token (parser)->location, + "expected %<)%> or %<,%>"); + t = error_mark_node; + } + } + } break; default: break; @@ -10855,6 +10954,11 @@ c_parser_omp_variable_list (c_parser *pa else list = tree_cons (t, NULL_TREE, list); + if (kind == OMP_CLAUSE_DEPEND) + { + parser->tokens = &parser->tokens_buf[0]; + parser->tokens_avail = tokens_avail; + } if (c_parser_next_token_is_not (parser, CPP_COMMA)) break; --- gcc/c/c-typeck.c.jj 2017-05-04 15:05:06.000000000 +0200 +++ gcc/c/c-typeck.c 2017-05-09 13:54:44.092945431 +0200 @@ -13330,10 +13330,11 @@ c_finish_omp_clauses (tree clauses, enum } if (t == error_mark_node) remove = true; - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) + else if (!lvalue_p (t)) { error_at (OMP_CLAUSE_LOCATION (c), - "%qE is not a variable in %<depend%> clause", t); + "%qE is not lvalue expression nor array section in " + "%<depend%> clause", t); remove = true; } else if (!c_mark_addressable (t)) --- gcc/cp/parser.c.jj 2017-05-04 15:28:27.000000000 +0200 +++ gcc/cp/parser.c 2017-05-09 09:53:42.314990410 +0200 @@ -30888,6 +30888,8 @@ cp_parser_omp_var_list_no_open (cp_parse { tree name, decl; + if (kind == OMP_CLAUSE_DEPEND) + cp_parser_parse_tentatively (parser); token = cp_lexer_peek_token (parser->lexer); if (kind != 0 && current_class_ptr @@ -30907,7 +30909,12 @@ cp_parser_omp_var_list_no_open (cp_parse /*declarator_p=*/false, /*optional_p=*/false); if (name == error_mark_node) - goto skip_comma; + { + if (kind == OMP_CLAUSE_DEPEND + && cp_parser_simulate_error (parser)) + goto depend_lvalue; + goto skip_comma; + } decl = cp_parser_lookup_name_simple (parser, name, token->location); if (decl == error_mark_node) @@ -30965,7 +30972,14 @@ cp_parser_omp_var_list_no_open (cp_parse { /* Look for `:'. */ if (!cp_parser_require (parser, CPP_COLON, RT_COLON)) - goto skip_comma; + { + if (kind == OMP_CLAUSE_DEPEND + && cp_parser_simulate_error (parser)) + goto depend_lvalue; + goto skip_comma; + } + if (kind == OMP_CLAUSE_DEPEND) + cp_parser_commit_to_tentative_parse (parser); if (!cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_SQUARE)) length = cp_parser_expression (parser); @@ -30973,7 +30987,12 @@ cp_parser_omp_var_list_no_open (cp_parse /* Look for the closing `]'. */ if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, RT_CLOSE_SQUARE)) - goto skip_comma; + { + if (kind == OMP_CLAUSE_DEPEND + && cp_parser_simulate_error (parser)) + goto depend_lvalue; + goto skip_comma; + } decl = tree_cons (low_bound, length, decl); } @@ -30982,6 +31001,21 @@ cp_parser_omp_var_list_no_open (cp_parse break; } + if (kind == OMP_CLAUSE_DEPEND) + { + if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA) + && cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN) + && cp_parser_simulate_error (parser)) + { + depend_lvalue: + cp_parser_abort_tentative_parse (parser); + decl = cp_parser_assignment_expression (parser, NULL, + false, false); + } + else + cp_parser_parse_definitely (parser); + } + tree u = build_omp_clause (token->location, kind); OMP_CLAUSE_DECL (u) = decl; OMP_CLAUSE_CHAIN (u) = list; --- gcc/cp/semantics.c.jj 2017-05-04 15:05:49.000000000 +0200 +++ gcc/cp/semantics.c 2017-05-09 14:43:34.772324756 +0200 @@ -6626,24 +6626,25 @@ finish_omp_clauses (tree clauses, enum c } if (t == error_mark_node) remove = true; - else if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL) - { - if (processing_template_decl) - break; - if (DECL_P (t)) - error ("%qD is not a variable in %<depend%> clause", t); - else - error ("%qE is not a variable in %<depend%> clause", t); - remove = true; - } else if (t == current_class_ptr) { error ("%<this%> allowed in OpenMP only in %<declare simd%>" " clauses"); remove = true; } - else if (!processing_template_decl - && !cxx_mark_addressable (t)) + else if (processing_template_decl) + break; + else if (!lvalue_p (t)) + { + if (DECL_P (t)) + error ("%qD is not lvalue expression nor array section " + "in %<depend%> clause", t); + else + error ("%qE is not lvalue expression nor array section " + "in %<depend%> clause", t); + remove = true; + } + else if (!cxx_mark_addressable (t)) remove = true; break; --- gcc/testsuite/c-c++-common/gomp/depend-5.c.jj 2017-05-09 14:13:32.889516537 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-5.c 2017-05-09 14:13:50.058294285 +0200 @@ -0,0 +1,48 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct T { int c[3]; }; +struct S { int a; struct T *b; struct T g; }; +struct S d[10]; +struct S *e[10]; +struct S *f; +struct S h; + +void +foo (void) +{ + #pragma omp task depend(inout: d) + ; + #pragma omp task depend(out: d[2]) + ; + #pragma omp task depend(in: d[:]) + ; + #pragma omp task depend(in: d[2:2]) + ; + #pragma omp task depend(in: d[:2]) + ; + #pragma omp task depend(inout: d[1].b->c[2]) + ; + #pragma omp task depend(out: d[0].a) + ; + #pragma omp task depend(in: e[3]->a) + ; + #pragma omp task depend(inout: e[2]->b->c) + ; + #pragma omp task depend(in: e[1]->b->c[2]) + ; + #pragma omp task depend(out: (*f).a) + ; + #pragma omp task depend(inout: f->b->c[0]) + ; + #pragma omp task depend(in: f) + ; + #pragma omp task depend(out: *f) + ; + #pragma omp task depend(inout: f[0]) + ; + #pragma omp task depend(in: f[0].a) + ; + #pragma omp task depend(inout: h.g.c[2]) + ; +} --- gcc/testsuite/c-c++-common/gomp/depend-6.c.jj 2017-05-09 14:13:35.869477961 +0200 +++ gcc/testsuite/c-c++-common/gomp/depend-6.c 2017-05-09 14:13:58.002191451 +0200 @@ -0,0 +1,32 @@ +/* { dg-do compile } */ +/* { dg-options "-fopenmp" } */ + +struct T { int c[3]; }; +struct S { int a; struct T *b; struct T g; }; +struct S d[10]; +struct S *e[10]; +struct S *f; +struct S h; + +void +foo (void) +{ + #pragma omp task depend(in: d[:2].b->c[2]) /* { dg-error "expected" } */ + ; + #pragma omp task depend(inout: d[1:].b->c[2]) /* { dg-error "expected" } */ + ; + #pragma omp task depend(out: d[0:1].a) /* { dg-error "expected" } */ + ; + #pragma omp task depend(in: e[3:2]->a) /* { dg-error "expected" } */ + ; + #pragma omp task depend(inout: e[2:2]->b->c) /* { dg-error "expected" } */ + ; + #pragma omp task depend(in: e[1]->b->c[2:1]) /* { dg-error "expected" } */ + ; + #pragma omp task depend(out: f + 0) /* { dg-error "not lvalue expression" } */ + ; + #pragma omp task depend(inout: f[0:1].a) /* { dg-error "expected" } */ + ; + #pragma omp task depend(inout: h.g.c[2:1]) /* { dg-error "expected" } */ + ; +} Jakub