Hi!

In OpenMP 4.1, one can optionally use modifiers to say which construct
the if clause belongs to.

Implemented thusly:

2015-07-15  Jakub Jelinek  <ja...@redhat.com>

        * tree-core.h (struct tree_omp_clause): Add subcode.if_modifier
        field.
        * tree.h (OMP_CLAUSE_IF_MODIFIER): Define.
        * gimplify.c (gimplify_scan_omp_clauses): Add CODE argument.
        For OMP_CLAUSE_IF complain if OMP_CLAUSE_IF_MODIFIER is present
        and does not match code.  Handle OMP_CLAUSE_GANG separately.
        (gimplify_oacc_cache, gimplify_omp_parallel, gimplify_omp_task,
        gimplify_omp_for, gimplify_omp_workshare, gimplify_omp_target_update,
        gimplify_expr): Adjust gimplify_scan_omp_clauses callers.
        * tree-pretty-print.c (dump_omp_clause): Print OMP_CLAUSE_IF_MODIFIER.
c-family/
        * c-omp.c (c_omp_split_clauses): Use OMP_CLAUSE_IF_MODIFIER to
        decide where to put OMP_CLAUSE_IF, without modifier duplicate to
        both target and parallel if combined.
c/
        * c-parser.c (c_parser_omp_clause_if): Add IS_OMP argument.  Parse
        and diagnose directive-name-modifier.
        (c_parser_oacc_all_clauses, c_parser_omp_all_clauses): Adjust
        callers.
cp/
        * parser.c (cp_parser_omp_clause_if): Add IS_OMP argument.  Parse
        and diagnose directive-name-modifier.
        (cp_parser_oacc_all_clauses, cp_parser_omp_all_clauses): Adjust
        callers.
fortran/
        * trans-openmp.c (gfc_trans_omp_clauses): Set OMP_CLAUSE_IF_MODIFIER
        to ERROR_MARK.
testsuite/
        * c-c++-common/gomp/if-1.c: New test.
        * c-c++-common/gomp/if-2.c: New test.

--- gcc/tree-core.h.jj  2015-07-14 14:49:57.000000000 +0200
+++ gcc/tree-core.h     2015-07-15 09:06:43.660755515 +0200
@@ -1351,6 +1351,7 @@ struct GTY(()) tree_omp_clause {
     enum omp_clause_proc_bind_kind proc_bind_kind;
     enum tree_code                 reduction_code;
     enum omp_clause_linear_kind    linear_kind;
+    enum tree_code                 if_modifier;
   } GTY ((skip)) subcode;
 
   /* The gimplification of OMP_CLAUSE_REDUCTION_{INIT,MERGE} for omp-low's
--- gcc/tree.h.jj       2015-07-14 14:29:49.000000000 +0200
+++ gcc/tree.h  2015-07-15 09:09:56.450274941 +0200
@@ -1385,6 +1385,9 @@ extern void protected_set_expr_location
 #define OMP_CLAUSE_SHARED_FIRSTPRIVATE(NODE) \
   (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_SHARED)->base.public_flag)
 
+#define OMP_CLAUSE_IF_MODIFIER(NODE)   \
+  (OMP_CLAUSE_SUBCODE_CHECK (NODE, 
OMP_CLAUSE_IF)->omp_clause.subcode.if_modifier)
+
 #define OMP_CLAUSE_FINAL_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_FINAL), 0)
 #define OMP_CLAUSE_IF_EXPR(NODE) \
--- gcc/gimplify.c.jj   2015-07-14 16:17:52.000000000 +0200
+++ gcc/gimplify.c      2015-07-15 11:09:06.831010500 +0200
@@ -6133,7 +6133,8 @@ find_decl_expr (tree *tp, int *walk_subt
 
 static void
 gimplify_scan_omp_clauses (tree *list_p, gimple_seq *pre_p,
-                          enum omp_region_type region_type)
+                          enum omp_region_type region_type,
+                          enum tree_code code)
 {
   struct gimplify_omp_ctx *ctx, *outer_ctx;
   tree c;
@@ -6550,8 +6551,33 @@ gimplify_scan_omp_clauses (tree *list_p,
            }
          break;
 
-       case OMP_CLAUSE_FINAL:
        case OMP_CLAUSE_IF:
+         if (OMP_CLAUSE_IF_MODIFIER (c) != ERROR_MARK
+             && OMP_CLAUSE_IF_MODIFIER (c) != code)
+           {
+             const char *p[2];
+             for (int i = 0; i < 2; i++)
+               switch (i ? OMP_CLAUSE_IF_MODIFIER (c) : code)
+                 {
+                 case OMP_PARALLEL: p[i] = "parallel"; break;
+                 case OMP_TASK: p[i] = "task"; break;
+                 case OMP_TASKLOOP: p[i] = "taskloop"; break;
+                 case OMP_TARGET_DATA: p[i] = "target data"; break;
+                 case OMP_TARGET: p[i] = "target"; break;
+                 case OMP_TARGET_UPDATE: p[i] = "target update"; break;
+                 case OMP_TARGET_ENTER_DATA:
+                   p[i] = "target enter data"; break;
+                 case OMP_TARGET_EXIT_DATA: p[i] = "target exit data"; break;
+                 default: gcc_unreachable ();
+                 }
+             error_at (OMP_CLAUSE_LOCATION (c),
+                       "expected %qs %<if%> clause modifier rather than %qs",
+                       p[0], p[1]);
+             remove = true;
+           }
+         /* Fall through.  */
+
+       case OMP_CLAUSE_FINAL:
          OMP_CLAUSE_OPERAND (c, 0)
            = gimple_boolify (OMP_CLAUSE_OPERAND (c, 0));
          /* Fall through.  */
@@ -6572,15 +6598,19 @@ gimplify_scan_omp_clauses (tree *list_p,
        case OMP_CLAUSE_NUM_GANGS:
        case OMP_CLAUSE_NUM_WORKERS:
        case OMP_CLAUSE_VECTOR_LENGTH:
-       case OMP_CLAUSE_GANG:
        case OMP_CLAUSE_WORKER:
        case OMP_CLAUSE_VECTOR:
          if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
                             is_gimple_val, fb_rvalue) == GS_ERROR)
            remove = true;
-         if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_GANG
-             && gimplify_expr (&OMP_CLAUSE_OPERAND (c, 1), pre_p, NULL,
-                               is_gimple_val, fb_rvalue) == GS_ERROR)
+         break;
+
+       case OMP_CLAUSE_GANG:
+         if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 0), pre_p, NULL,
+                            is_gimple_val, fb_rvalue) == GS_ERROR)
+           remove = true;
+         if (gimplify_expr (&OMP_CLAUSE_OPERAND (c, 1), pre_p, NULL,
+                            is_gimple_val, fb_rvalue) == GS_ERROR)
            remove = true;
          break;
 
@@ -7009,7 +7039,8 @@ gimplify_oacc_cache (tree *expr_p, gimpl
 {
   tree expr = *expr_p;
 
-  gimplify_scan_omp_clauses (&OACC_CACHE_CLAUSES (expr), pre_p, ORT_WORKSHARE);
+  gimplify_scan_omp_clauses (&OACC_CACHE_CLAUSES (expr), pre_p, ORT_WORKSHARE,
+                            OACC_CACHE);
   gimplify_adjust_omp_clauses (pre_p, &OACC_CACHE_CLAUSES (expr));
 
   /* TODO: Do something sensible with this information.  */
@@ -7032,7 +7063,7 @@ gimplify_omp_parallel (tree *expr_p, gim
   gimplify_scan_omp_clauses (&OMP_PARALLEL_CLAUSES (expr), pre_p,
                             OMP_PARALLEL_COMBINED (expr)
                             ? ORT_COMBINED_PARALLEL
-                            : ORT_PARALLEL);
+                            : ORT_PARALLEL, OMP_PARALLEL);
 
   push_gimplify_context ();
 
@@ -7068,7 +7099,7 @@ gimplify_omp_task (tree *expr_p, gimple_
   gimplify_scan_omp_clauses (&OMP_TASK_CLAUSES (expr), pre_p,
                             find_omp_clause (OMP_TASK_CLAUSES (expr),
                                              OMP_CLAUSE_UNTIED)
-                            ? ORT_UNTIED_TASK : ORT_TASK);
+                            ? ORT_UNTIED_TASK : ORT_TASK, OMP_TASK);
 
   push_gimplify_context ();
 
@@ -7169,7 +7200,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
     }
 
   if (TREE_CODE (for_stmt) != OMP_TASKLOOP)
-    gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, ort);
+    gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p, ort,
+                              TREE_CODE (for_stmt));
   if (TREE_CODE (for_stmt) == OMP_DISTRIBUTE)
     gimplify_omp_ctxp->distribute = true;
 
@@ -7280,7 +7312,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
            }
        }
 
-      gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt), pre_p, ort);
+      gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (orig_for_stmt), pre_p, ort,
+                                OMP_TASKLOOP);
     }
 
   if (orig_for_stmt != for_stmt)
@@ -7853,7 +7886,8 @@ gimplify_omp_workshare (tree *expr_p, gi
     default:
       gcc_unreachable ();
     }
-  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort);
+  gimplify_scan_omp_clauses (&OMP_CLAUSES (expr), pre_p, ort,
+                            TREE_CODE (expr));
   if (ort == ORT_TARGET || ort == ORT_TARGET_DATA)
     {
       push_gimplify_context ();
@@ -7962,7 +7996,7 @@ gimplify_omp_target_update (tree *expr_p
       gcc_unreachable ();
     }
   gimplify_scan_omp_clauses (&OMP_STANDALONE_CLAUSES (expr), pre_p,
-                            ORT_WORKSHARE);
+                            ORT_WORKSHARE, TREE_CODE (expr));
   gimplify_adjust_omp_clauses (pre_p, &OMP_STANDALONE_CLAUSES (expr));
   stmt = gimple_build_omp_target (NULL, kind, OMP_STANDALONE_CLAUSES (expr));
 
@@ -8995,7 +9029,7 @@ gimplify_expr (tree *expr_p, gimple_seq
                break;
              case OMP_CRITICAL:
                gimplify_scan_omp_clauses (&OMP_CRITICAL_CLAUSES (*expr_p),
-                                          pre_p, ORT_WORKSHARE);
+                                          pre_p, ORT_WORKSHARE, OMP_CRITICAL);
                gimplify_adjust_omp_clauses (pre_p,
                                             &OMP_CRITICAL_CLAUSES (*expr_p));
                g = gimple_build_omp_critical (body,
--- gcc/tree-pretty-print.c.jj  2015-07-14 14:49:57.000000000 +0200
+++ gcc/tree-pretty-print.c     2015-07-15 11:17:43.463007390 +0200
@@ -367,6 +367,20 @@ dump_omp_clause (pretty_printer *pp, tre
 
     case OMP_CLAUSE_IF:
       pp_string (pp, "if(");
+      switch (OMP_CLAUSE_IF_MODIFIER (clause))
+       {
+       case ERROR_MARK: break;
+       case OMP_PARALLEL: pp_string (pp, "parallel:"); break;
+       case OMP_TASK: pp_string (pp, "task:"); break;
+       case OMP_TASKLOOP: pp_string (pp, "taskloop:"); break;
+       case OMP_TARGET_DATA: pp_string (pp, "target data:"); break;
+       case OMP_TARGET: pp_string (pp, "target:"); break;
+       case OMP_TARGET_UPDATE: pp_string (pp, "target update:"); break;
+       case OMP_TARGET_ENTER_DATA:
+         pp_string (pp, "target enter data:"); break;
+       case OMP_TARGET_EXIT_DATA: pp_string (pp, "target exit data:"); break;
+       default: gcc_unreachable ();
+       }
       dump_generic_node (pp, OMP_CLAUSE_IF_EXPR (clause),
                         spc, flags, false);
       pp_right_paren (pp);
--- gcc/c-family/c-omp.c.jj     2015-07-14 14:49:57.000000000 +0200
+++ gcc/c-family/c-omp.c        2015-07-15 11:09:06.831010500 +0200
@@ -1010,10 +1010,39 @@ c_omp_split_clauses (location_t loc, enu
          if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOGROUP))
              != 0)
            s = C_OMP_CLAUSE_SPLIT_TASKLOOP;
-         /* FIXME: This is currently being discussed.  */
          else if ((mask & (OMP_CLAUSE_MASK_1
                            << PRAGMA_OMP_CLAUSE_NUM_THREADS)) != 0)
-           s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+           {
+             if ((mask & (OMP_CLAUSE_MASK_1
+                          << PRAGMA_OMP_CLAUSE_MAP)) != 0)
+               {
+                 if (OMP_CLAUSE_IF_MODIFIER (clauses) == OMP_PARALLEL)
+                   s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+                 else if (OMP_CLAUSE_IF_MODIFIER (clauses) == OMP_TARGET)
+                   s = C_OMP_CLAUSE_SPLIT_TARGET;
+                 else if (OMP_CLAUSE_IF_MODIFIER (clauses) == ERROR_MARK)
+                   {
+                     c = build_omp_clause (OMP_CLAUSE_LOCATION (clauses),
+                                           OMP_CLAUSE_IF);
+                     OMP_CLAUSE_IF_MODIFIER (c)
+                       = OMP_CLAUSE_IF_MODIFIER (clauses);
+                     OMP_CLAUSE_IF_EXPR (c) = OMP_CLAUSE_IF_EXPR (clauses);
+                     OMP_CLAUSE_CHAIN (c)
+                       = cclauses[C_OMP_CLAUSE_SPLIT_TARGET];
+                     cclauses[C_OMP_CLAUSE_SPLIT_TARGET] = c;
+                     s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+                   }
+                 else
+                   {
+                     error_at (OMP_CLAUSE_LOCATION (clauses),
+                               "expected %<parallel%> or %<target%> %<if%> "
+                               "clause modifier");
+                     continue;
+                   }
+               }
+             else
+               s = C_OMP_CLAUSE_SPLIT_PARALLEL;
+           }
          else
            s = C_OMP_CLAUSE_SPLIT_TARGET;
          break;
--- gcc/c/c-parser.c.jj 2015-07-14 16:03:49.000000000 +0200
+++ gcc/c/c-parser.c    2015-07-15 12:53:35.626128964 +0200
@@ -10549,28 +10549,149 @@ c_parser_omp_clause_final (c_parser *par
 }
 
 /* OpenACC, OpenMP 2.5:
-   if ( expression ) */
+   if ( expression )
+
+   OpenMP 4.1:
+   if ( directive-name-modifier : expression )
+
+   directive-name-modifier:
+     parallel | task | taskloop | target data | target | target update
+     | target enter data | target exit data  */
 
 static tree
-c_parser_omp_clause_if (c_parser *parser, tree list)
+c_parser_omp_clause_if (c_parser *parser, tree list, bool is_omp)
 {
-  location_t loc = c_parser_peek_token (parser)->location;
-  if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
-    {
-      tree t = c_parser_paren_condition (parser);
-      tree c;
+  location_t location = c_parser_peek_token (parser)->location;
+  enum tree_code if_modifier = ERROR_MARK;
 
-      check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if");
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return list;
 
-      c = build_omp_clause (loc, OMP_CLAUSE_IF);
-      OMP_CLAUSE_IF_EXPR (c) = t;
-      OMP_CLAUSE_CHAIN (c) = list;
-      list = c;
+  if (is_omp && c_parser_next_token_is (parser, CPP_NAME))
+    {
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      int n = 2;
+      if (strcmp (p, "parallel") == 0)
+       if_modifier = OMP_PARALLEL;
+      else if (strcmp (p, "task") == 0)
+       if_modifier = OMP_TASK;
+      else if (strcmp (p, "taskloop") == 0)
+       if_modifier = OMP_TASKLOOP;
+      else if (strcmp (p, "target") == 0)
+       {
+         if_modifier = OMP_TARGET;
+         if (c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+           {
+             p = IDENTIFIER_POINTER (c_parser_peek_2nd_token (parser)->value);
+             if (strcmp ("data", p) == 0)
+               if_modifier = OMP_TARGET_DATA;
+             else if (strcmp ("update", p) == 0)
+               if_modifier = OMP_TARGET_UPDATE;
+             else if (strcmp ("enter", p) == 0)
+               if_modifier = OMP_TARGET_ENTER_DATA;
+             else if (strcmp ("exit", p) == 0)
+               if_modifier = OMP_TARGET_EXIT_DATA;
+             if (if_modifier != OMP_TARGET)
+               {
+                 n = 3;
+                 c_parser_consume_token (parser);
+               }
+             else
+               {
+                 location_t loc = c_parser_peek_2nd_token (parser)->location;
+                 error_at (loc, "expected %<data%>, %<update%>, %<enter%> "
+                                "or %<exit%>");
+                 if_modifier = ERROR_MARK;
+               }
+             if (if_modifier == OMP_TARGET_ENTER_DATA
+                 || if_modifier == OMP_TARGET_EXIT_DATA)
+               {
+                 if (c_parser_peek_2nd_token (parser)->type == CPP_NAME)
+                   {
+                     p = IDENTIFIER_POINTER
+                               (c_parser_peek_2nd_token (parser)->value);
+                     if (strcmp ("data", p) == 0)
+                       n = 4;
+                   }
+                 if (n == 4)
+                   c_parser_consume_token (parser);
+                 else
+                   {
+                     location_t loc
+                       = c_parser_peek_2nd_token (parser)->location;
+                     error_at (loc, "expected %<data%>");
+                     if_modifier = ERROR_MARK;
+                   }
+               }
+           }
+       }
+      if (if_modifier != ERROR_MARK)
+       {
+         if (c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+           {
+             c_parser_consume_token (parser);
+             c_parser_consume_token (parser);
+           }
+         else
+           {
+             if (n > 2)
+               {
+                 location_t loc = c_parser_peek_2nd_token (parser)->location;
+                 error_at (loc, "expected %<:%>");
+               }
+             if_modifier = ERROR_MARK;
+           }
+       }
     }
-  else
-    c_parser_error (parser, "expected %<(%>");
 
-  return list;
+  tree t = c_parser_condition (parser), c;
+  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+  for (c = list; c ; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF)
+      {
+       if (if_modifier != ERROR_MARK
+           && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier)
+         {
+           const char *p = NULL;
+           switch (if_modifier)
+             {
+             case OMP_PARALLEL: p = "parallel"; break;
+             case OMP_TASK: p = "task"; break;
+             case OMP_TASKLOOP: p = "taskloop"; break;
+             case OMP_TARGET_DATA: p = "target data"; break;
+             case OMP_TARGET: p = "target"; break;
+             case OMP_TARGET_UPDATE: p = "target update"; break;
+             case OMP_TARGET_ENTER_DATA: p = "enter data"; break;
+             case OMP_TARGET_EXIT_DATA: p = "exit data"; break;
+             default: gcc_unreachable ();
+             }
+           error_at (location, "too many %<if%> clauses with %qs modifier",
+                     p);
+           return list;
+         }
+       else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier)
+         {
+           if (!is_omp)
+             error_at (location, "too many %<if%> clauses");
+           else
+             error_at (location, "too many %<if%> clauses without modifier");
+           return list;
+         }
+       else if (if_modifier == ERROR_MARK
+                || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK)
+         {
+           error_at (location, "if any %<if%> clause has modifier, then all "
+                               "%<if%> clauses have to use modifier");
+           return list;
+         }
+      }
+
+  c = build_omp_clause (location, OMP_CLAUSE_IF);
+  OMP_CLAUSE_IF_MODIFIER (c) = if_modifier;
+  OMP_CLAUSE_IF_EXPR (c) = t;
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
 }
 
 /* OpenMP 2.5:
@@ -12150,7 +12271,7 @@ c_parser_oacc_all_clauses (c_parser *par
          c_name = "host";
          break;
        case PRAGMA_OACC_CLAUSE_IF:
-         clauses = c_parser_omp_clause_if (parser, clauses);
+         clauses = c_parser_omp_clause_if (parser, clauses, false);
          c_name = "if";
          break;
        case PRAGMA_OACC_CLAUSE_NUM_GANGS:
@@ -12288,7 +12409,7 @@ c_parser_omp_all_clauses (c_parser *pars
          c_name = "defaultmap";
          break;
        case PRAGMA_OMP_CLAUSE_IF:
-         clauses = c_parser_omp_clause_if (parser, clauses);
+         clauses = c_parser_omp_clause_if (parser, clauses, true);
          c_name = "if";
          break;
        case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
--- gcc/cp/parser.c.jj  2015-07-14 17:39:06.000000000 +0200
+++ gcc/cp/parser.c     2015-07-15 12:13:04.950069705 +0200
@@ -28402,16 +28402,102 @@ cp_parser_omp_clause_final (cp_parser *p
 }
 
 /* OpenMP 2.5:
-   if ( expression ) */
+   if ( expression )
+
+   OpenMP 4.1:
+   if ( directive-name-modifier : expression )
+
+   directive-name-modifier:
+     parallel | task | taskloop | target data | target | target update
+     | target enter data | target exit data  */
 
 static tree
-cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location)
+cp_parser_omp_clause_if (cp_parser *parser, tree list, location_t location,
+                        bool is_omp)
 {
   tree t, c;
+  enum tree_code if_modifier = ERROR_MARK;
 
   if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
     return list;
 
+  if (is_omp && cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+    {
+      tree id = cp_lexer_peek_token (parser->lexer)->u.value;
+      const char *p = IDENTIFIER_POINTER (id);
+      int n = 2;
+
+      if (strcmp ("parallel", p) == 0)
+       if_modifier = OMP_PARALLEL;
+      else if (strcmp ("task", p) == 0)
+       if_modifier = OMP_TASK;
+      else if (strcmp ("taskloop", p) == 0)
+       if_modifier = OMP_TASKLOOP;
+      else if (strcmp ("target", p) == 0)
+       {
+         if_modifier = OMP_TARGET;
+         if (cp_lexer_nth_token_is (parser->lexer, 2, CPP_NAME))
+           {
+             id = cp_lexer_peek_nth_token (parser->lexer, 2)->u.value;
+             p = IDENTIFIER_POINTER (id);
+             if (strcmp ("data", p) == 0)
+               if_modifier = OMP_TARGET_DATA;
+             else if (strcmp ("update", p) == 0)
+               if_modifier = OMP_TARGET_UPDATE;
+             else if (strcmp ("enter", p) == 0)
+               if_modifier = OMP_TARGET_ENTER_DATA;
+             else if (strcmp ("exit", p) == 0)
+               if_modifier = OMP_TARGET_EXIT_DATA;
+             if (if_modifier != OMP_TARGET)
+               n = 3;
+             else
+               {
+                 location_t loc
+                   = cp_lexer_peek_nth_token (parser->lexer, 2)->location;
+                 error_at (loc, "expected %<data%>, %<update%>, %<enter%> "
+                                "or %<exit%>");
+                 if_modifier = ERROR_MARK;
+               }
+             if (if_modifier == OMP_TARGET_ENTER_DATA
+                 || if_modifier == OMP_TARGET_EXIT_DATA)
+               {
+                 if (cp_lexer_nth_token_is (parser->lexer, 3, CPP_NAME))
+                   {
+                     id = cp_lexer_peek_nth_token (parser->lexer, 3)->u.value;
+                     p = IDENTIFIER_POINTER (id);
+                     if (strcmp ("data", p) == 0)
+                       n = 4;
+                   }
+                 if (n != 4)
+                   {
+                     location_t loc
+                       = cp_lexer_peek_nth_token (parser->lexer, 3)->location;
+                     error_at (loc, "expected %<data%>");
+                     if_modifier = ERROR_MARK;
+                   }
+               }
+           }
+       }
+      if (if_modifier != ERROR_MARK)
+       {
+         if (cp_lexer_nth_token_is (parser->lexer, n, CPP_COLON))
+           {
+             while (n-- > 0)
+               cp_lexer_consume_token (parser->lexer);
+           }
+         else
+           {
+             if (n > 2)
+               {
+                 location_t loc
+                   = cp_lexer_peek_nth_token (parser->lexer, n)->location;
+                 error_at (loc, "expected %<:%>");
+               }
+             if_modifier = ERROR_MARK;
+           }
+       }
+    }
+
   t = cp_parser_condition (parser);
 
   if (t == error_mark_node
@@ -28420,9 +28506,48 @@ cp_parser_omp_clause_if (cp_parser *pars
                                           /*or_comma=*/false,
                                           /*consume_paren=*/true);
 
-  check_no_duplicate_clause (list, OMP_CLAUSE_IF, "if", location);
+  for (c = list; c ; c = OMP_CLAUSE_CHAIN (c))
+    if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IF)
+      {
+       if (if_modifier != ERROR_MARK
+           && OMP_CLAUSE_IF_MODIFIER (c) == if_modifier)
+         {
+           const char *p = NULL;
+           switch (if_modifier)
+             {
+             case OMP_PARALLEL: p = "parallel"; break;
+             case OMP_TASK: p = "task"; break;
+             case OMP_TASKLOOP: p = "taskloop"; break;
+             case OMP_TARGET_DATA: p = "target data"; break;
+             case OMP_TARGET: p = "target"; break;
+             case OMP_TARGET_UPDATE: p = "target update"; break;
+             case OMP_TARGET_ENTER_DATA: p = "enter data"; break;
+             case OMP_TARGET_EXIT_DATA: p = "exit data"; break;
+             default: gcc_unreachable ();
+             }
+           error_at (location, "too many %<if%> clauses with %qs modifier",
+                     p);
+           return list;
+         }
+       else if (OMP_CLAUSE_IF_MODIFIER (c) == if_modifier)
+         {
+           if (!is_omp)
+             error_at (location, "too many %<if%> clauses");
+           else
+             error_at (location, "too many %<if%> clauses without modifier");
+           return list;
+         }
+       else if (if_modifier == ERROR_MARK
+                || OMP_CLAUSE_IF_MODIFIER (c) == ERROR_MARK)
+         {
+           error_at (location, "if any %<if%> clause has modifier, then all "
+                               "%<if%> clauses have to use modifier");
+           return list;
+         }
+      }
 
   c = build_omp_clause (location, OMP_CLAUSE_IF);
+  OMP_CLAUSE_IF_MODIFIER (c) = if_modifier;
   OMP_CLAUSE_IF_EXPR (c) = t;
   OMP_CLAUSE_CHAIN (c) = list;
 
@@ -29713,7 +29838,7 @@ cp_parser_oacc_all_clauses (cp_parser *p
          c_name = "host";
          break;
        case PRAGMA_OACC_CLAUSE_IF:
-         clauses = cp_parser_omp_clause_if (parser, clauses, here);
+         clauses = cp_parser_omp_clause_if (parser, clauses, here, false);
          c_name = "if";
          break;
        case PRAGMA_OACC_CLAUSE_NUM_GANGS:
@@ -29867,7 +29992,8 @@ cp_parser_omp_all_clauses (cp_parser *pa
          c_name = "is_device_ptr";
          break;
        case PRAGMA_OMP_CLAUSE_IF:
-         clauses = cp_parser_omp_clause_if (parser, clauses, token->location);
+         clauses = cp_parser_omp_clause_if (parser, clauses, token->location,
+                                            true);
          c_name = "if";
          break;
        case PRAGMA_OMP_CLAUSE_LASTPRIVATE:
--- gcc/fortran/trans-openmp.c.jj       2015-07-09 09:44:47.000000000 +0200
+++ gcc/fortran/trans-openmp.c  2015-07-15 11:09:06.831010500 +0200
@@ -2245,6 +2245,7 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
       gfc_add_block_to_block (block, &se.post);
 
       c = build_omp_clause (where.lb->location, OMP_CLAUSE_IF);
+      OMP_CLAUSE_IF_MODIFIER (c) = ERROR_MARK;
       OMP_CLAUSE_IF_EXPR (c) = if_var;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
--- gcc/testsuite/c-c++-common/gomp/if-1.c.jj   2015-07-15 11:47:36.807682266 
+0200
+++ gcc/testsuite/c-c++-common/gomp/if-1.c      2015-07-15 11:47:52.548053177 
+0200
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void
+foo (int a, int b, int *p, int *q)
+{
+  int i;
+  #pragma omp parallel if (a)
+    ;
+  #pragma omp parallel if (parallel:a)
+    ;
+  #pragma omp parallel for simd if (a)
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp parallel for simd if (parallel : a)
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp task if (a)
+    ;
+  #pragma omp task if (task: a)
+    ;
+  #pragma omp taskloop if (a)
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp taskloop if (taskloop : a)
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp target if (a)
+    ;
+  #pragma omp target if (target: a)
+    ;
+  #pragma omp target teams distribute parallel for simd if (a)
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp target teams distribute parallel for simd if (parallel : a) if 
(target: b)
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp target data if (a) map (p[0:2])
+    ;
+  #pragma omp target data if (target data: a) map (p[0:2])
+    ;
+  #pragma omp target enter data if (a) map (to: p[0:2])
+  #pragma omp target enter data if (target enter data: a) map (to: p[0:2])
+  #pragma omp target exit data if (a) map (from: p[0:2])
+  #pragma omp target exit data if (target exit data: a) map (from: p[0:2])
+  #pragma omp target update if (a) to (q[0:3])
+  #pragma omp target update if (target update:a) to (q[0:3])
+}
--- gcc/testsuite/c-c++-common/gomp/if-2.c.jj   2015-07-15 11:47:39.644568886 
+0200
+++ gcc/testsuite/c-c++-common/gomp/if-2.c      2015-07-15 12:07:10.829683856 
+0200
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+void
+foo (int a, int b, int *p, int *q, int task)
+{
+  int i;
+  #pragma omp parallel if (a) if (b) /* { dg-error "too many .if. clauses 
without modifier" } */
+    ;
+  #pragma omp parallel if (a) if (parallel: b) /* { dg-error "if any .if. 
clause has modifier, then all .if. clauses have to use modifier" } */
+    ;
+  #pragma omp parallel if (parallel: a) if (b) /* { dg-error "if any .if. 
clause has modifier, then all .if. clauses have to use modifier" } */
+    ;
+  #pragma omp parallel if (parallel:a) if (parallel:a) /* { dg-error "too many 
.if. clauses with .parallel. modifier" } */
+    ;
+  #pragma omp parallel if (task:a) /* { dg-error "expected .parallel. .if. 
clause modifier rather than .task." } */ \
+    if (taskloop: b) /* { dg-error "expected .parallel. .if. clause modifier 
rather than .taskloop." } */
+    ;
+  #pragma omp parallel if (target update:a) /* { dg-error "expected .parallel. 
.if. clause modifier rather than .target update." } */
+    ;
+  #pragma omp parallel for simd if (target update: a) /* { dg-error "expected 
.parallel. .if. clause modifier rather than .target update." } */
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp task if (task)
+    ;
+  #pragma omp task if (task: task)
+    ;
+  #pragma omp task if (parallel: a) /* { dg-error "expected .task. .if. clause 
modifier rather than .parallel." } */
+    ;
+  #pragma omp taskloop if (task : a) /* { dg-error "expected .taskloop. .if. 
clause modifier rather than .task." } */
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp target if (taskloop: a) /* { dg-error "expected .target. .if. 
clause modifier rather than .taskloop." } */
+    ;
+  #pragma omp target teams distribute parallel for simd if (target exit data : 
a) /* { dg-error "expected .parallel. or .target. .if. clause modifier" } */
+  for (i = 0; i < 16; i++)
+    ;
+  #pragma omp target data if (target: a) map (p[0:2]) /* { dg-error "expected 
.target data. .if. clause modifier rather than .target." } */
+    ;
+  #pragma omp target enter data if (target data: a) map (to: p[0:2]) /* { 
dg-error "expected .target enter data. .if. clause modifier rather than .target 
data." } */
+  #pragma omp target exit data if (target enter data: a) map (from: p[0:2]) /* 
{ dg-error "expected .target exit data. .if. clause modifier rather than 
.target enter data." } */
+  #pragma omp target update if (target exit data:a) to (q[0:3]) /* { dg-error 
"expected .target update. .if. clause modifier rather than .target exit data." 
} */
+}

        Jakub

Reply via email to