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

Reply via email to