Hi!

OpenMP 5.0 adds support for non-rectangular loop collapses, e.g.
triangular and more complex.

This patch deals just with the diagnostics so that they aren't rejected
immediately as before.  As the spec generally requires as before that the
iteration variable initializer and bound in the comparison as invariant
vs. the outermost loop, and just add some exceptional forms that can violate
that, we need to avoid folding the expressions until we can detect them and
in order to avoid folding it later on, I chose to use a TREE_VEC in those
expressions to hold the var_outer * expr1 + expr2 triplet, the patch adds
pretty-printing of that, gimplification etc. and just sorry_at during
omp expansion for now.

The next step will be to implement the different cases of that one by one.

Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk.

2020-06-16  Jakub Jelinek  <ja...@redhat.com>

gcc/
        * tree.h (OMP_FOR_NON_RECTANGULAR): Define.
        * gimplify.c (gimplify_omp_for): Diagnose schedule, ordered
        or dist_schedule clause on non-rectangular loops.  Handle
        gimplification of non-rectangular lb/b expressions.  When changing
        iteration variable, adjust also non-rectangular lb/b expressions
        referencing that.
        * omp-general.h (struct omp_for_data_loop): Add m1, m2 and outer
        members.
        (struct omp_for_data): Add non_rect member.
        * omp-general.c (omp_extract_for_data): Handle non-rectangular
        loops.  Fill in non_rect, m1, m2 and outer.
        * omp-low.c (lower_omp_for): Handle non-rectangular lb/b expressions.
        * omp-expand.c (expand_omp_for): Emit sorry_at for unsupported
        non-rectangular loop cases and assert for cases that can't be
        non-rectangular.
        * tree-pretty-print.c (dump_mem_ref): Formatting fix.
        (dump_omp_loop_non_rect_expr): New function.
        (dump_generic_node): Handle non-rectangular OpenMP loops.
        * tree-pretty-print.h (dump_omp_loop_non_rect_expr): Declare.
        * gimple-pretty-print.c (dump_gimple_omp_for): Handle non-rectangular
        OpenMP loops.
gcc/c-family/
        * c-common.h (c_omp_check_loop_iv_exprs): Add an int argument.
        * c-omp.c (struct c_omp_check_loop_iv_data): Add maybe_nonrect and
        idx members.
        (c_omp_is_loop_iterator): New function.
        (c_omp_check_loop_iv_r): Use it.  Add support for silent scanning
        if outer loop iterator is present.  Perform duplicate checking through
        hash_set in the function rather than expecting caller to do that.
        Pass NULL instead of d->ppset to walk_tree_1.
        (c_omp_check_nonrect_loop_iv): New function.
        (c_omp_check_loop_iv): Use it.  Fill in new members, allow
        non-rectangular loop forms, diagnose multiple associated loops with
        the same iterator.  Pass NULL instead of &pset to walk_tree_1.
        (c_omp_check_loop_iv_exprs): Likewise.
gcc/c/
        * c-parser.c (c_parser_expr_no_commas): Save, clear and restore
        c_in_omp_for.
        (c_parser_omp_for_loop): Set c_in_omp_for around some calls to avoid
        premature c_fully_fold.  Defer explicit c_fully_fold calls to after
        c_finish_omp_for.
        * c-tree.h (c_in_omp_for): Declare.
        * c-typeck.c (c_in_omp_for): Define.
        (build_modify_expr): Avoid c_fully_fold if c_in_omp_for.
        (digest_init): Likewise.
        (build_binary_op): Likewise.
gcc/cp/
        * semantics.c (handle_omp_for_class_iterator): Adjust
        c_omp_check_loop_iv_exprs caller.
        (finish_omp_for): Likewise.  Don't call fold_build_cleanup_point_expr
        before calling c_finish_omp_for and c_omp_check_loop_iv, move it
        after those calls.
        * pt.c (tsubst_omp_for_iterator): Handle non-rectangular loops.
gcc/testsuite/
        * c-c++-common/gomp/loop-6.c: New test.
        * gcc.dg/gomp/loop-1.c: Don't expect diagnostics on valid
        non-rectangular loops.
        * gcc.dg/gomp/loop-2.c: New test.
        * g++.dg/gomp/loop-1.C: Don't expect diagnostics on valid
        non-rectangular loops.
        * g++.dg/gomp/loop-2.C: Likewise.
        * g++.dg/gomp/loop-5.C: New test.
        * g++.dg/gomp/loop-6.C: New test.

--- gcc/tree.h.jj       2020-06-16 12:10:03.628010921 +0200
+++ gcc/tree.h  2020-06-16 12:35:02.440298110 +0200
@@ -1465,6 +1465,11 @@ class auto_suppress_location_wrappers
   != UNKNOWN_LOCATION)
 #define OMP_CLAUSE_LOCATION(NODE)  (OMP_CLAUSE_CHECK (NODE))->omp_clause.locus
 
+/* True on OMP_FOR and other OpenMP/OpenACC looping constructs if the loop nest
+   is non-rectangular.  */
+#define OMP_FOR_NON_RECTANGULAR(NODE) \
+  (OMP_LOOPING_CHECK (NODE)->base.private_flag)
+
 /* True on an OMP_SECTION statement that was the last lexical member.
    This status is meaningful in the implementation of lastprivate.  */
 #define OMP_SECTION_LAST(NODE) \
--- gcc/gimplify.c.jj   2020-06-16 12:10:03.622011008 +0200
+++ gcc/gimplify.c      2020-06-16 12:35:02.446298022 +0200
@@ -11182,7 +11182,26 @@ gimplify_omp_for (tree *expr_p, gimple_s
   switch (TREE_CODE (for_stmt))
     {
     case OMP_FOR:
+      if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_stmt))
+       {
+         if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
+                              OMP_CLAUSE_SCHEDULE))
+           error_at (EXPR_LOCATION (for_stmt),
+                     "%qs clause may not appear on non-rectangular %qs",
+                     "schedule", "for");
+         if (omp_find_clause (OMP_FOR_CLAUSES (for_stmt), OMP_CLAUSE_ORDERED))
+           error_at (EXPR_LOCATION (for_stmt),
+                     "%qs clause may not appear on non-rectangular %qs",
+                     "ordered", "for");
+       }
+      break;
     case OMP_DISTRIBUTE:
+      if (OMP_FOR_NON_RECTANGULAR (inner_for_stmt ? inner_for_stmt : for_stmt)
+         && omp_find_clause (OMP_FOR_CLAUSES (for_stmt),
+                             OMP_CLAUSE_DIST_SCHEDULE))
+       error_at (EXPR_LOCATION (for_stmt),
+                 "%qs clause may not appear on non-rectangular %qs",
+                 "dist_schedule", "distribute");
       break;
     case OACC_LOOP:
       ort = ORT_ACC;
@@ -11757,8 +11776,18 @@ gimplify_omp_for (tree *expr_p, gimple_s
       else
        var = decl;
 
-      tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
-                           is_gimple_val, fb_rvalue, false);
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC)
+       {
+         tree lb = TREE_OPERAND (t, 1);
+         tret = gimplify_expr (&TREE_VEC_ELT (lb, 1), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+         ret = MIN (ret, tret);
+         tret = gimplify_expr (&TREE_VEC_ELT (lb, 2), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+       }
+      else
+       tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
+                             is_gimple_val, fb_rvalue, false);
       ret = MIN (ret, tret);
       if (ret == GS_ERROR)
        return ret;
@@ -11768,8 +11797,18 @@ gimplify_omp_for (tree *expr_p, gimple_s
       gcc_assert (COMPARISON_CLASS_P (t));
       gcc_assert (TREE_OPERAND (t, 0) == decl);
 
-      tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
-                           is_gimple_val, fb_rvalue, false);
+      if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC)
+       {
+         tree ub = TREE_OPERAND (t, 1);
+         tret = gimplify_expr (&TREE_VEC_ELT (ub, 1), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+         ret = MIN (ret, tret);
+         tret = gimplify_expr (&TREE_VEC_ELT (ub, 2), &for_pre_body, NULL,
+                               is_gimple_val, fb_rvalue, false);
+       }
+      else
+       tret = gimplify_expr (&TREE_OPERAND (t, 1), &for_pre_body, NULL,
+                             is_gimple_val, fb_rvalue, false);
       ret = MIN (ret, tret);
 
       /* Handle OMP_FOR_INCR.  */
@@ -11911,6 +11950,20 @@ gimplify_omp_for (tree *expr_p, gimple_s
                pop_gimplify_context (bind);
              }
        }
+      if (OMP_FOR_NON_RECTANGULAR (for_stmt) && var != decl)
+       for (int j = i + 1; j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++)
+         {
+           t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j);
+           gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
+           if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+               && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+             TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+           t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), j);
+           gcc_assert (COMPARISON_CLASS_P (t));
+           if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+               && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+             TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+         }
     }
 
   BITMAP_FREE (has_decl_expr);
@@ -11955,6 +12008,27 @@ gimplify_omp_for (tree *expr_p, gimple_s
        t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
        TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
        TREE_OPERAND (TREE_OPERAND (t, 1), 0) = var;
+       if (OMP_FOR_NON_RECTANGULAR (for_stmt))
+         for (int j = i + 1;
+              j < TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)); j++)
+           {
+             t = TREE_VEC_ELT (OMP_FOR_INIT (for_stmt), j);
+             gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
+             if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+                 && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+               {
+                 TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
+                 TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+               }
+             t = TREE_VEC_ELT (OMP_FOR_COND (for_stmt), j);
+             gcc_assert (COMPARISON_CLASS_P (t));
+             if (TREE_CODE (TREE_OPERAND (t, 1)) == TREE_VEC
+                 && TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) == decl)
+               {
+                 TREE_OPERAND (t, 1) = copy_node (TREE_OPERAND (t, 1));
+                 TREE_VEC_ELT (TREE_OPERAND (t, 1), 0) = var;
+               }
+         }
       }
 
   gimplify_adjust_omp_clauses (pre_p, for_body,
--- gcc/omp-general.c.jj        2020-06-16 12:10:03.624010979 +0200
+++ gcc/omp-general.c   2020-06-16 12:35:02.447298008 +0200
@@ -201,6 +201,7 @@ omp_extract_for_data (gomp_for *for_stmt
   fd->have_pointer_condtemp = false;
   fd->have_scantemp = false;
   fd->have_nonctrl_scantemp = false;
+  fd->non_rect = false;
   fd->lastprivate_conditional = 0;
   fd->tiling = NULL_TREE;
   fd->collapse = 1;
@@ -330,12 +331,45 @@ omp_extract_for_data (gomp_for *for_stmt
                  || TREE_CODE (TREE_TYPE (loop->v)) == POINTER_TYPE);
       var = TREE_CODE (loop->v) == SSA_NAME ? SSA_NAME_VAR (loop->v) : loop->v;
       loop->n1 = gimple_omp_for_initial (for_stmt, i);
+      loop->m1 = NULL_TREE;
+      loop->m2 = NULL_TREE;
+      loop->outer = 0;
+      if (TREE_CODE (loop->n1) == TREE_VEC)
+       {
+         for (int j = i - 1; j >= 0; j--)
+           if (TREE_VEC_ELT (loop->n1, 0) == gimple_omp_for_index (for_stmt, 
j))
+             {
+               loop->outer = i - j;
+               break;
+             }
+         gcc_assert (loop->outer);
+         loop->m1 = TREE_VEC_ELT (loop->n1, 1);
+         loop->n1 = TREE_VEC_ELT (loop->n1, 2);
+         fd->non_rect = true;
+       }
 
       loop->cond_code = gimple_omp_for_cond (for_stmt, i);
       loop->n2 = gimple_omp_for_final (for_stmt, i);
       gcc_assert (loop->cond_code != NE_EXPR
                  || (gimple_omp_for_kind (for_stmt)
                      != GF_OMP_FOR_KIND_OACC_LOOP));
+      if (TREE_CODE (loop->n2) == TREE_VEC)
+       {
+         if (loop->outer)
+           gcc_assert (TREE_VEC_ELT (loop->n2, 0)
+                       == gimple_omp_for_index (for_stmt, i - loop->outer));
+         else
+           for (int j = i - 1; j >= 0; j--)
+             if (TREE_VEC_ELT (loop->n2, 0) == gimple_omp_for_index (for_stmt, 
j))
+               {
+                 loop->outer = i - j;
+                 break;
+               }
+         gcc_assert (loop->outer);
+         loop->m2 = TREE_VEC_ELT (loop->n2, 1);
+         loop->n2 = TREE_VEC_ELT (loop->n2, 2);
+         fd->non_rect = true;
+       }
 
       t = gimple_omp_for_incr (for_stmt, i);
       gcc_assert (TREE_OPERAND (t, 0) == var);
@@ -357,6 +391,10 @@ omp_extract_for_data (gomp_for *for_stmt
              = build_nonstandard_integer_type
                  (TYPE_PRECISION (TREE_TYPE (loop->v)), 1);
        }
+      else if (loop->m1 || loop->m2)
+       /* Non-rectangular loops should use static schedule and no
+          ordered clause.  */
+       gcc_unreachable ();
       else if (iter_type != long_long_unsigned_type_node)
        {
          if (POINTER_TYPE_P (TREE_TYPE (loop->v)))
@@ -406,13 +444,18 @@ omp_extract_for_data (gomp_for *for_stmt
 
       if (collapse_count && *collapse_count == NULL)
        {
-         t = fold_binary (loop->cond_code, boolean_type_node,
-                          fold_convert (TREE_TYPE (loop->v), loop->n1),
-                          fold_convert (TREE_TYPE (loop->v), loop->n2));
+         if (loop->m1 || loop->m2)
+           t = NULL_TREE;
+         else
+           t = fold_binary (loop->cond_code, boolean_type_node,
+                            fold_convert (TREE_TYPE (loop->v), loop->n1),
+                            fold_convert (TREE_TYPE (loop->v), loop->n2));
          if (t && integer_zerop (t))
            count = build_zero_cst (long_long_unsigned_type_node);
          else if ((i == 0 || count != NULL_TREE)
                   && TREE_CODE (TREE_TYPE (loop->v)) == INTEGER_TYPE
+                  && loop->m1 == NULL_TREE
+                  && loop->m2 == NULL_TREE
                   && TREE_CONSTANT (loop->n1)
                   && TREE_CONSTANT (loop->n2)
                   && TREE_CODE (loop->step) == INTEGER_CST)
@@ -486,6 +529,9 @@ omp_extract_for_data (gomp_for *for_stmt
       fd->loop.n1 = build_int_cst (TREE_TYPE (fd->loop.v), 0);
       fd->loop.n2 = *collapse_count;
       fd->loop.step = build_int_cst (TREE_TYPE (fd->loop.v), 1);
+      fd->loop.m1 = NULL_TREE;
+      fd->loop.m2 = NULL_TREE;
+      fd->loop.outer = 0;
       fd->loop.cond_code = LT_EXPR;
     }
   else if (loops)
--- gcc/omp-general.h.jj        2020-06-16 12:10:03.624010979 +0200
+++ gcc/omp-general.h   2020-06-16 12:35:02.440298110 +0200
@@ -43,11 +43,16 @@ enum oacc_loop_flags {
 };
 
 /* A structure holding the elements of:
-   for (V = N1; V cond N2; V += STEP) [...] */
+   for (V = N1; V cond N2; V += STEP) [...]
+   or for non-rectangular loops:
+   for (V = M1 * W + N1; V cond M2 * W + N2; V += STEP;
+   where W is V of the OUTER-th loop (e.g. for OUTER 1 it is the
+   the index of the immediately surrounding loop).  */
 
 struct omp_for_data_loop
 {
-  tree v, n1, n2, step;
+  tree v, n1, n2, step, m1, m2;
+  int outer;
   enum tree_code cond_code;
 };
 
@@ -64,6 +69,7 @@ struct omp_for_data
   int ordered;
   bool have_nowait, have_ordered, simd_schedule, have_reductemp;
   bool have_pointer_condtemp, have_scantemp, have_nonctrl_scantemp;
+  bool non_rect;
   int lastprivate_conditional;
   unsigned char sched_modifiers;
   enum omp_clause_schedule_kind sched_kind;
--- gcc/omp-low.c.jj    2020-06-16 12:10:03.626010950 +0200
+++ gcc/omp-low.c       2020-06-16 12:35:02.445298037 +0200
@@ -10573,13 +10573,31 @@ lower_omp_for (gimple_stmt_iterator *gsi
   for (i = 0; i < gimple_omp_for_collapse (stmt); i++)
     {
       rhs_p = gimple_omp_for_initial_ptr (stmt, i);
-      if (!is_gimple_min_invariant (*rhs_p))
+      if (TREE_CODE (*rhs_p) == TREE_VEC)
+       {
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 1)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 1), &cnt_list);
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 2)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 2), &cnt_list);
+       }
+      else if (!is_gimple_min_invariant (*rhs_p))
        *rhs_p = get_formal_tmp_var (*rhs_p, &cnt_list);
       else if (TREE_CODE (*rhs_p) == ADDR_EXPR)
        recompute_tree_invariant_for_addr_expr (*rhs_p);
 
       rhs_p = gimple_omp_for_final_ptr (stmt, i);
-      if (!is_gimple_min_invariant (*rhs_p))
+      if (TREE_CODE (*rhs_p) == TREE_VEC)
+       {
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 1)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 1), &cnt_list);
+         if (!is_gimple_min_invariant (TREE_VEC_ELT (*rhs_p, 2)))
+           TREE_VEC_ELT (*rhs_p, 1)
+             = get_formal_tmp_var (TREE_VEC_ELT (*rhs_p, 2), &cnt_list);
+       }
+      else if (!is_gimple_min_invariant (*rhs_p))
        *rhs_p = get_formal_tmp_var (*rhs_p, &cnt_list);
       else if (TREE_CODE (*rhs_p) == ADDR_EXPR)
        recompute_tree_invariant_for_addr_expr (*rhs_p);
--- gcc/omp-expand.c.jj 2020-06-16 12:10:03.623010993 +0200
+++ gcc/omp-expand.c    2020-06-16 12:35:02.447298008 +0200
@@ -6532,14 +6532,22 @@ expand_omp_for (struct omp_region *regio
     loops_state_set (LOOPS_NEED_FIXUP);
 
   if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_SIMD)
-    expand_omp_simd (region, &fd);
+    {
+      if (fd.non_rect)
+       sorry_at (gimple_location (fd.for_stmt),
+                 "non-rectangular %<simd%> not supported yet");
+      expand_omp_simd (region, &fd);
+    }
   else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_OACC_LOOP)
     {
-      gcc_assert (!inner_stmt);
+      gcc_assert (!inner_stmt && !fd.non_rect);
       expand_oacc_for (region, &fd);
     }
   else if (gimple_omp_for_kind (fd.for_stmt) == GF_OMP_FOR_KIND_TASKLOOP)
     {
+      if (fd.non_rect)
+       sorry_at (gimple_location (fd.for_stmt),
+                 "non-rectangular %<taskloop%> not supported yet");
       if (gimple_omp_for_combined_into_p (fd.for_stmt))
        expand_omp_taskloop_for_inner (region, &fd, inner_stmt);
       else
@@ -6548,6 +6556,9 @@ expand_omp_for (struct omp_region *regio
   else if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
           && !fd.have_ordered)
     {
+      if (fd.non_rect)
+       sorry_at (gimple_location (fd.for_stmt),
+                 "non-rectangular OpenMP loops not supported yet");
       if (fd.chunk_size == NULL)
        expand_omp_for_static_nochunk (region, &fd, inner_stmt);
       else
@@ -6560,7 +6571,7 @@ expand_omp_for (struct omp_region *regio
       tree sched_arg = NULL_TREE;
 
       gcc_assert (gimple_omp_for_kind (fd.for_stmt)
-                 == GF_OMP_FOR_KIND_FOR);
+                 == GF_OMP_FOR_KIND_FOR && !fd.non_rect);
       if (fd.chunk_size == NULL
          && fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC)
        fd.chunk_size = integer_zero_node;
--- gcc/tree-pretty-print.c.jj  2020-06-16 12:10:03.627010935 +0200
+++ gcc/tree-pretty-print.c     2020-06-16 12:35:02.440298110 +0200
@@ -1568,7 +1568,36 @@ dump_mem_ref (pretty_printer *pp, tree n
        }
       pp_right_bracket (pp);
     }
- }
+}
+
+/* Helper function for dump_generic_node.  Dump INIT or COND expression for
+   OpenMP loop non-rectangular iterators.  */
+
+void
+dump_omp_loop_non_rect_expr (pretty_printer *pp, tree node, int spc,
+                            dump_flags_t flags)
+{
+  gcc_assert (TREE_CODE (node) == TREE_VEC);
+  dump_generic_node (pp, TREE_VEC_ELT (node, 0), spc, flags, false);
+  pp_string (pp, " * ");
+  if (op_prio (TREE_VEC_ELT (node, 1)) <= op_code_prio (MULT_EXPR))
+    {
+      pp_left_paren (pp);
+      dump_generic_node (pp, TREE_VEC_ELT (node, 1), spc, flags, false);
+      pp_right_paren (pp);
+    }
+  else
+    dump_generic_node (pp, TREE_VEC_ELT (node, 1), spc, flags, false);
+  pp_string (pp, " + ");
+  if (op_prio (TREE_VEC_ELT (node, 1)) <= op_code_prio (PLUS_EXPR))
+    {
+      pp_left_paren (pp);
+      dump_generic_node (pp, TREE_VEC_ELT (node, 2), spc, flags, false);
+      pp_right_paren (pp);
+    }
+  else
+    dump_generic_node (pp, TREE_VEC_ELT (node, 2), spc, flags, false);
+}
 
 /* Dump the node NODE on the pretty_printer PP, SPC spaces of
    indent.  FLAGS specifies details to show in the dump (see TDF_* in
@@ -3418,13 +3447,34 @@ dump_generic_node (pretty_printer *pp, t
                  spc += 2;
                  newline_and_indent (pp, spc);
                  pp_string (pp, "for (");
-                 dump_generic_node (pp,
-                                    TREE_VEC_ELT (OMP_FOR_INIT (node), i),
-                                    spc, flags, false);
+                 tree init = TREE_VEC_ELT (OMP_FOR_INIT (node), i);
+                 if (TREE_CODE (init) != MODIFY_EXPR
+                     || TREE_CODE (TREE_OPERAND (init, 1)) != TREE_VEC)
+                   dump_generic_node (pp, init, spc, flags, false);
+                 else
+                   {
+                     dump_generic_node (pp, TREE_OPERAND (init, 0),
+                                        spc, flags, false);
+                     pp_string (pp, " = ");
+                     dump_omp_loop_non_rect_expr (pp, TREE_OPERAND (init, 1),
+                                                  spc, flags);
+                   }
                  pp_string (pp, "; ");
-                 dump_generic_node (pp,
-                                    TREE_VEC_ELT (OMP_FOR_COND (node), i),
-                                    spc, flags, false);
+                 tree cond = TREE_VEC_ELT (OMP_FOR_COND (node), i);
+                 if (!COMPARISON_CLASS_P (cond)
+                     || TREE_CODE (TREE_OPERAND (cond, 1)) != TREE_VEC)
+                   dump_generic_node (pp, cond, spc, flags, false);
+                 else
+                   {
+                     dump_generic_node (pp, TREE_OPERAND (cond, 0),
+                                        spc, flags, false);
+                     const char *op = op_symbol (cond);
+                     pp_space (pp);
+                     pp_string (pp, op);
+                     pp_space (pp);
+                     dump_omp_loop_non_rect_expr (pp, TREE_OPERAND (cond, 1),
+                                                  spc, flags);
+                   }
                  pp_string (pp, "; ");
                  dump_generic_node (pp,
                                     TREE_VEC_ELT (OMP_FOR_INCR (node), i),
--- gcc/tree-pretty-print.h.jj  2020-06-16 12:10:03.627010935 +0200
+++ gcc/tree-pretty-print.h     2020-06-16 12:35:02.445298037 +0200
@@ -42,6 +42,8 @@ extern char *print_generic_expr_to_str (
 extern void dump_omp_clauses (pretty_printer *, tree, int, dump_flags_t);
 extern void dump_omp_atomic_memory_order (pretty_printer *,
                                          enum omp_memory_order);
+extern void dump_omp_loop_non_rect_expr (pretty_printer *, tree, int,
+                                        dump_flags_t);
 extern int dump_generic_node (pretty_printer *, tree, int, dump_flags_t, bool);
 extern void print_declaration (pretty_printer *, tree, int, dump_flags_t);
 extern int op_code_prio (enum tree_code);
--- gcc/gimple-pretty-print.c.jj        2020-06-16 12:10:03.621011022 +0200
+++ gcc/gimple-pretty-print.c   2020-06-16 12:35:02.439298124 +0200
@@ -1512,8 +1512,11 @@ dump_gimple_omp_for (pretty_printer *buf
          dump_generic_node (buffer, gimple_omp_for_index (gs, i), spc,
                             flags, false);
          pp_string (buffer, " = ");
-         dump_generic_node (buffer, gimple_omp_for_initial (gs, i), spc,
-                            flags, false);
+         tree init = gimple_omp_for_initial (gs, i);
+         if (TREE_CODE (init) != TREE_VEC)
+           dump_generic_node (buffer, init, spc, flags, false);
+         else
+           dump_omp_loop_non_rect_expr (buffer, init, spc, flags);
          pp_string (buffer, "; ");
 
          dump_generic_node (buffer, gimple_omp_for_index (gs, i), spc,
@@ -1540,8 +1543,11 @@ dump_gimple_omp_for (pretty_printer *buf
              gcc_unreachable ();
            }
          pp_space (buffer);
-         dump_generic_node (buffer, gimple_omp_for_final (gs, i), spc,
-                            flags, false);
+         tree cond = gimple_omp_for_final (gs, i);
+         if (TREE_CODE (cond) != TREE_VEC)
+           dump_generic_node (buffer, cond, spc, flags, false);
+         else
+           dump_omp_loop_non_rect_expr (buffer, cond, spc, flags);
          pp_string (buffer, "; ");
 
          dump_generic_node (buffer, gimple_omp_for_index (gs, i), spc,
--- gcc/c-family/c-common.h.jj  2020-06-04 09:06:35.612022094 +0200
+++ gcc/c-family/c-common.h     2020-06-16 13:02:43.064335185 +0200
@@ -1196,7 +1196,7 @@ extern void c_finish_omp_taskyield (loca
 extern tree c_finish_omp_for (location_t, enum tree_code, tree, tree, tree,
                              tree, tree, tree, tree, bool);
 extern bool c_omp_check_loop_iv (tree, tree, walk_tree_lh);
-extern bool c_omp_check_loop_iv_exprs (location_t, tree, tree, tree, tree,
+extern bool c_omp_check_loop_iv_exprs (location_t, tree, int, tree, tree, tree,
                                       walk_tree_lh);
 extern tree c_finish_oacc_wait (location_t, tree, tree);
 extern tree c_oacc_split_loop_clauses (tree, tree *, bool);
--- gcc/c-family/c-omp.c.jj     2020-06-16 12:10:03.611011166 +0200
+++ gcc/c-family/c-omp.c        2020-06-16 13:04:32.353744975 +0200
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.
 #include "memmodel.h"
 #include "attribs.h"
 #include "gimplify.h"
+#include "langhooks.h"
 
 
 /* Complete a #pragma oacc wait construct.  LOC is the location of
@@ -1041,13 +1042,37 @@ struct c_omp_check_loop_iv_data
 {
   tree declv;
   bool fail;
+  bool maybe_nonrect;
   location_t stmt_loc;
   location_t expr_loc;
   int kind;
+  int idx;
   walk_tree_lh lh;
   hash_set<tree> *ppset;
 };
 
+/* Return -1 if DECL is not a loop iterator in loop nest D, otherwise
+   return the index of the loop in which it is an iterator.
+   Return TREE_VEC_LENGTH (d->declv) if it is a C++ range for iterator.  */
+
+static int
+c_omp_is_loop_iterator (tree decl, struct c_omp_check_loop_iv_data *d)
+{
+  for (int i = 0; i < TREE_VEC_LENGTH (d->declv); i++)
+    if (decl == TREE_VEC_ELT (d->declv, i)
+       || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
+           && decl == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i))))
+      return i;
+    else if (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
+            && TREE_CHAIN (TREE_VEC_ELT (d->declv, i))
+            && (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i)))
+                == TREE_VEC)
+            && decl == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv,
+                                                 i)), 2))
+      return TREE_VEC_LENGTH (d->declv);
+  return -1;
+}
+
 /* Helper function called via walk_tree, to diagnose uses
    of associated loop IVs inside of lb, b and incr expressions
    of OpenMP loops.  */
@@ -1059,51 +1084,234 @@ c_omp_check_loop_iv_r (tree *tp, int *wa
     = (struct c_omp_check_loop_iv_data *) data;
   if (DECL_P (*tp))
     {
-      int i;
-      for (i = 0; i < TREE_VEC_LENGTH (d->declv); i++)
-       if (*tp == TREE_VEC_ELT (d->declv, i)
-           || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
-               && *tp == TREE_PURPOSE (TREE_VEC_ELT (d->declv, i)))
-           || (TREE_CODE (TREE_VEC_ELT (d->declv, i)) == TREE_LIST
-               && TREE_CHAIN (TREE_VEC_ELT (d->declv, i))
-               && (TREE_CODE (TREE_CHAIN (TREE_VEC_ELT (d->declv, i)))
-                   == TREE_VEC)
-               && *tp == TREE_VEC_ELT (TREE_CHAIN (TREE_VEC_ELT (d->declv,
-                                                                 i)), 2)))
-         {
-           location_t loc = d->expr_loc;
-           if (loc == UNKNOWN_LOCATION)
-             loc = d->stmt_loc;
-           switch (d->kind)
-             {
-             case 0:
-               error_at (loc, "initializer expression refers to "
-                              "iteration variable %qD", *tp);
-               break;
-             case 1:
-               error_at (loc, "condition expression refers to "
-                              "iteration variable %qD", *tp);
-               break;
-             case 2:
-               error_at (loc, "increment expression refers to "
-                              "iteration variable %qD", *tp);
-               break;
-             }
-           d->fail = true;
-         }
+      int idx = c_omp_is_loop_iterator (*tp, d);
+      if (idx == -1)
+       return NULL_TREE;
+
+      if ((d->kind & 4) && idx < d->idx)
+       {
+         d->maybe_nonrect = true;
+         return NULL_TREE;
+       }
+
+      if (d->ppset->add (*tp))
+       return NULL_TREE;
+
+      location_t loc = d->expr_loc;
+      if (loc == UNKNOWN_LOCATION)
+       loc = d->stmt_loc;
+
+      switch (d->kind & 3)
+       {
+       case 0:
+         error_at (loc, "initializer expression refers to "
+                        "iteration variable %qD", *tp);
+         break;
+       case 1:
+         error_at (loc, "condition expression refers to "
+                        "iteration variable %qD", *tp);
+         break;
+       case 2:
+         error_at (loc, "increment expression refers to "
+                        "iteration variable %qD", *tp);
+         break;
+       }
+      d->fail = true;
     }
+  else if (d->ppset->add (*tp))
+    *walk_subtrees = 0;
   /* Don't walk dtors added by C++ wrap_cleanups_r.  */
   else if (TREE_CODE (*tp) == TRY_CATCH_EXPR
           && TRY_CATCH_IS_CLEANUP (*tp))
     {
       *walk_subtrees = 0;
       return walk_tree_1 (&TREE_OPERAND (*tp, 0), c_omp_check_loop_iv_r, data,
-                         d->ppset, d->lh);
+                         NULL, d->lh);
     }
 
   return NULL_TREE;
 }
 
+/* Check the allowed expressions for non-rectangular loop nest lb and b
+   expressions.  Return the outer var decl referenced in the expression.  */
+
+static tree
+c_omp_check_nonrect_loop_iv (tree *tp, struct c_omp_check_loop_iv_data *d,
+                            walk_tree_lh lh)
+{
+  d->maybe_nonrect = false;
+  if (d->fail)
+    return NULL_TREE;
+
+  hash_set<tree> pset;
+  hash_set<tree> *ppset = d->ppset;
+  d->ppset = &pset;
+
+  tree t = *tp;
+  if (TREE_CODE (t) == TREE_VEC
+      && TREE_VEC_LENGTH (t) == 3
+      && DECL_P (TREE_VEC_ELT (t, 0))
+      && c_omp_is_loop_iterator (TREE_VEC_ELT (t, 0), d) >= 0)
+    {
+      d->kind &= 3;
+      walk_tree_1 (&TREE_VEC_ELT (t, 1), c_omp_check_loop_iv_r, d, NULL, lh);
+      walk_tree_1 (&TREE_VEC_ELT (t, 1), c_omp_check_loop_iv_r, d, NULL, lh);
+      d->ppset = ppset;
+      return d->fail ? NULL_TREE : TREE_VEC_ELT (t, 0);
+    }
+
+  while (CONVERT_EXPR_P (t))
+    t = TREE_OPERAND (t, 0);
+
+  tree a1 = t, a2 = integer_zero_node;
+  bool neg_a1 = false, neg_a2 = false;
+  switch (TREE_CODE (t))
+    {
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+      a1 = TREE_OPERAND (t, 0);
+      a2 = TREE_OPERAND (t, 1);
+      while (CONVERT_EXPR_P (a1))
+       a1 = TREE_OPERAND (a1, 0);
+      while (CONVERT_EXPR_P (a2))
+       a2 = TREE_OPERAND (a2, 0);
+      if (DECL_P (a1) && c_omp_is_loop_iterator (a1, d) >= 0)
+       {
+         a2 = TREE_OPERAND (t, 1);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a2 = true;
+         t = a1;
+         break;
+       }
+      if (DECL_P (a2) && c_omp_is_loop_iterator (a2, d) >= 0)
+       {
+         a1 = TREE_OPERAND (t, 0);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a1 = true;
+         t = a2;
+         a2 = a1;
+         break;
+       }
+      if (TREE_CODE (a1) == MULT_EXPR && TREE_CODE (a2) == MULT_EXPR)
+       {
+         tree o1 = TREE_OPERAND (a1, 0);
+         tree o2 = TREE_OPERAND (a1, 1);
+         while (CONVERT_EXPR_P (o1))
+           o1 = TREE_OPERAND (o1, 0);
+         while (CONVERT_EXPR_P (o2))
+           o2 = TREE_OPERAND (o2, 0);
+         if ((DECL_P (o1) && c_omp_is_loop_iterator (o1, d) >= 0)
+             || (DECL_P (o2) && c_omp_is_loop_iterator (o2, d) >= 0))
+           {
+             a2 = TREE_OPERAND (t, 1);
+             if (TREE_CODE (t) == MINUS_EXPR)
+               neg_a2 = true;
+             t = a1;
+             break;
+           }
+       }
+      if (TREE_CODE (a2) == MULT_EXPR)
+       {
+         a1 = TREE_OPERAND (t, 0);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a1 = true;
+         t = a2;
+         a2 = a1;
+         break;
+       }
+      if (TREE_CODE (a1) == MULT_EXPR)
+       {
+         a2 = TREE_OPERAND (t, 1);
+         if (TREE_CODE (t) == MINUS_EXPR)
+           neg_a2 = true;
+         t = a1;
+         break;
+       }
+      a2 = integer_zero_node;
+      break;
+    default:
+      break;
+    }
+
+  a1 = integer_one_node;
+  if (TREE_CODE (t) == MULT_EXPR)
+    {
+      tree o1 = TREE_OPERAND (t, 0);
+      tree o2 = TREE_OPERAND (t, 1);
+      while (CONVERT_EXPR_P (o1))
+       o1 = TREE_OPERAND (o1, 0);
+      while (CONVERT_EXPR_P (o2))
+       o2 = TREE_OPERAND (o2, 0);
+      if (DECL_P (o1) && c_omp_is_loop_iterator (o1, d) >= 0)
+       {
+         a1 = TREE_OPERAND (t, 1);
+         t = o1;
+       }
+      else if (DECL_P (o2) && c_omp_is_loop_iterator (o2, d) >= 0)
+       {
+         a1 = TREE_OPERAND (t, 0);
+         t = o2;
+       }
+    }
+
+  d->kind &= 3;
+  tree ret = NULL_TREE;
+  if (DECL_P (t) && c_omp_is_loop_iterator (t, d) >= 0)
+    {
+      location_t loc = d->expr_loc;
+      if (loc == UNKNOWN_LOCATION)
+       loc = d->stmt_loc;
+      if (!lang_hooks.types_compatible_p (TREE_TYPE (*tp), TREE_TYPE (t)))
+       {
+         if (d->kind == 0)
+           error_at (loc, "outer iteration variable %qD used in initializer"
+                          " expression has type other than %qT",
+                     t, TREE_TYPE (*tp));
+         else
+           error_at (loc, "outer iteration variable %qD used in condition"
+                          " expression has type other than %qT",
+                     t, TREE_TYPE (*tp));
+         d->fail = true;
+       }
+      else if (!INTEGRAL_TYPE_P (TREE_TYPE (a1)))
+       {
+         error_at (loc, "outer iteration variable %qD multiplier expression"
+                        " %qE is not integral", t, a1);
+         d->fail = true;
+       }
+      else if (!INTEGRAL_TYPE_P (TREE_TYPE (a2)))
+       {
+         error_at (loc, "outer iteration variable %qD addend expression"
+                        " %qE is not integral", t, a2);
+         d->fail = true;
+       }
+      else
+       {
+         walk_tree_1 (&a1, c_omp_check_loop_iv_r, d, NULL, lh);
+         walk_tree_1 (&a2, c_omp_check_loop_iv_r, d, NULL, lh);
+        }
+      if (!d->fail)
+       {
+         a1 = fold_convert (TREE_TYPE (*tp), a1);
+         a2 = fold_convert (TREE_TYPE (*tp), a2);
+         if (neg_a1)
+           a1 = fold_build1 (NEGATE_EXPR, TREE_TYPE (a1), a1);
+         if (neg_a2)
+           a2 = fold_build1 (NEGATE_EXPR, TREE_TYPE (a2), a2);
+         ret = t;
+         *tp = make_tree_vec (3);
+         TREE_VEC_ELT (*tp, 0) = t;
+         TREE_VEC_ELT (*tp, 1) = a1;
+         TREE_VEC_ELT (*tp, 2) = a2;
+       }
+    }
+  else
+    walk_tree_1 (&t, c_omp_check_loop_iv_r, d, NULL, lh);
+
+  d->ppset = ppset;
+  return ret;
+}
+
 /* Diagnose invalid references to loop iterators in lb, b and incr
    expressions.  */
 
@@ -1116,6 +1324,7 @@ c_omp_check_loop_iv (tree stmt, tree dec
 
   data.declv = declv;
   data.fail = false;
+  data.maybe_nonrect = false;
   data.stmt_loc = EXPR_LOCATION (stmt);
   data.lh = lh;
   data.ppset = &pset;
@@ -1129,9 +1338,31 @@ c_omp_check_loop_iv (tree stmt, tree dec
       gcc_assert (TREE_OPERAND (cond, 0) == decl);
       tree incr = TREE_VEC_ELT (OMP_FOR_INCR (stmt), i);
       data.expr_loc = EXPR_LOCATION (TREE_OPERAND (init, 1));
-      data.kind = 0;
+      tree vec_outer1 = NULL_TREE, vec_outer2 = NULL_TREE;
+      int kind = 0;
+      if (i > 0
+         && (unsigned) c_omp_is_loop_iterator (decl, &data) < (unsigned) i)
+       {
+         location_t loc = data.expr_loc;
+         if (loc == UNKNOWN_LOCATION)
+           loc = data.stmt_loc;
+         error_at (loc, "the same loop iteration variables %qD used in "
+                        "multiple associated loops", decl);
+         data.fail = true;
+       }
+      /* Handle non-rectangular loop nests.  */
+      if (TREE_CODE (stmt) != OACC_LOOP
+         && (TREE_CODE (TREE_OPERAND (init, 1)) == TREE_VEC
+             || INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (init, 1))))
+         && i > 0)
+       kind = 4;
+      data.kind = kind;
+      data.idx = i;
       walk_tree_1 (&TREE_OPERAND (init, 1),
-                  c_omp_check_loop_iv_r, &data, &pset, lh);
+                  c_omp_check_loop_iv_r, &data, NULL, lh);
+      if (data.maybe_nonrect)
+       vec_outer1 = c_omp_check_nonrect_loop_iv (&TREE_OPERAND (init, 1),
+                                                 &data, lh);
       /* Don't warn for C++ random access iterators here, the
         expression then involves the subtraction and always refers
         to the original value.  The C++ FE needs to warn on those
@@ -1141,10 +1372,24 @@ c_omp_check_loop_iv (tree stmt, tree dec
              && decl == TREE_PURPOSE (TREE_VEC_ELT (declv, i))))
        {
          data.expr_loc = EXPR_LOCATION (cond);
-         data.kind = 1;
+         data.kind = kind | 1;
          walk_tree_1 (&TREE_OPERAND (cond, 1),
-                      c_omp_check_loop_iv_r, &data, &pset, lh);
+                      c_omp_check_loop_iv_r, &data, NULL, lh);
+         if (data.maybe_nonrect)
+           vec_outer2 = c_omp_check_nonrect_loop_iv (&TREE_OPERAND (cond, 1),
+                                                     &data, lh);
        }
+      if (vec_outer1 && vec_outer2 && vec_outer1 != vec_outer2)
+       {
+         location_t loc = data.expr_loc;
+         if (loc == UNKNOWN_LOCATION)
+           loc = data.stmt_loc;
+         error_at (loc, "two different outer iteration variables %qD and %qD"
+                        " used in a single loop", vec_outer1, vec_outer2);
+         data.fail = true;
+       }
+      if (vec_outer1 || vec_outer2)
+       OMP_FOR_NON_RECTANGULAR (stmt) = 1;
       if (TREE_CODE (incr) == MODIFY_EXPR)
        {
          gcc_assert (TREE_OPERAND (incr, 0) == decl);
@@ -1155,13 +1400,13 @@ c_omp_check_loop_iv (tree stmt, tree dec
            {
              data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 0));
              walk_tree_1 (&TREE_OPERAND (incr, 0),
-                          c_omp_check_loop_iv_r, &data, &pset, lh);
+                          c_omp_check_loop_iv_r, &data, NULL, lh);
            }
          else
            {
              data.expr_loc = EXPR_LOCATION (TREE_OPERAND (incr, 1));
              walk_tree_1 (&TREE_OPERAND (incr, 1),
-                          c_omp_check_loop_iv_r, &data, &pset, lh);
+                          c_omp_check_loop_iv_r, &data, NULL, lh);
            }
        }
     }
@@ -1171,7 +1416,7 @@ c_omp_check_loop_iv (tree stmt, tree dec
 /* Similar, but allows to check the init or cond expressions individually.  */
 
 bool
-c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, tree decl,
+c_omp_check_loop_iv_exprs (location_t stmt_loc, tree declv, int i, tree decl,
                           tree init, tree cond, walk_tree_lh lh)
 {
   hash_set<tree> pset;
@@ -1179,15 +1424,24 @@ c_omp_check_loop_iv_exprs (location_t st
 
   data.declv = declv;
   data.fail = false;
+  data.maybe_nonrect = false;
   data.stmt_loc = stmt_loc;
   data.lh = lh;
   data.ppset = &pset;
+  data.idx = i;
+  if (i > 0
+      && (unsigned) c_omp_is_loop_iterator (decl, &data) < (unsigned) i)
+    {
+      error_at (stmt_loc, "the same loop iteration variables %qD used in "
+                         "multiple associated loops", decl);
+      data.fail = true;
+    }
   if (init)
     {
       data.expr_loc = EXPR_LOCATION (init);
       data.kind = 0;
       walk_tree_1 (&init,
-                  c_omp_check_loop_iv_r, &data, &pset, lh);
+                  c_omp_check_loop_iv_r, &data, NULL, lh);
     }
   if (cond)
     {
@@ -1196,10 +1450,10 @@ c_omp_check_loop_iv_exprs (location_t st
       data.kind = 1;
       if (TREE_OPERAND (cond, 0) == decl)
        walk_tree_1 (&TREE_OPERAND (cond, 1),
-                    c_omp_check_loop_iv_r, &data, &pset, lh);
+                    c_omp_check_loop_iv_r, &data, NULL, lh);
       else
        walk_tree_1 (&TREE_OPERAND (cond, 0),
-                    c_omp_check_loop_iv_r, &data, &pset, lh);
+                    c_omp_check_loop_iv_r, &data, NULL, lh);
     }
   return !data.fail;
 }
--- gcc/c/c-parser.c.jj 2020-06-16 12:23:41.208216697 +0200
+++ gcc/c/c-parser.c    2020-06-16 12:35:02.442298081 +0200
@@ -7594,6 +7594,8 @@ c_parser_expr_no_commas (c_parser *parse
   struct c_expr lhs, rhs, ret;
   enum tree_code code;
   location_t op_location, exp_location;
+  bool save_in_omp_for = c_in_omp_for;
+  c_in_omp_for = false;
   gcc_assert (!after || c_dialect_objc ());
   lhs = c_parser_conditional_expression (parser, after, omp_atomic_lhs);
   op_location = c_parser_peek_token (parser)->location;
@@ -7633,6 +7635,7 @@ c_parser_expr_no_commas (c_parser *parse
       code = BIT_IOR_EXPR;
       break;
     default:
+      c_in_omp_for = save_in_omp_for;
       return lhs;
     }
   c_parser_consume_token (parser);
@@ -7652,6 +7655,7 @@ c_parser_expr_no_commas (c_parser *parse
       ret.original_code = ERROR_MARK;
     }
   ret.original_type = NULL;
+  c_in_omp_for = save_in_omp_for;
   return ret;
 }
 
@@ -18119,8 +18123,10 @@ c_parser_omp_for_loop (location_t loc, c
          if (i > 0)
            vec_safe_push (for_block, c_begin_compound_stmt (true));
          this_pre_body = push_stmt_list ();
+         c_in_omp_for = true;
          c_parser_declaration_or_fndef (parser, true, true, true, true, true,
                                         NULL, vNULL);
+         c_in_omp_for = false;
          if (this_pre_body)
            {
              this_pre_body = pop_stmt_list (this_pre_body);
@@ -18158,9 +18164,11 @@ c_parser_omp_for_loop (location_t loc, c
          init_exp = c_parser_expr_no_commas (parser, NULL);
          init_exp = default_function_array_read_conversion (init_loc,
                                                             init_exp);
+         c_in_omp_for = true;
          init = build_modify_expr (init_loc, decl, decl_exp.original_type,
                                    NOP_EXPR, init_loc, init_exp.value,
                                    init_exp.original_type);
+         c_in_omp_for = false;
          init = c_process_expr_stmt (init_loc, init);
 
          c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
@@ -18181,19 +18189,13 @@ c_parser_omp_for_loop (location_t loc, c
       if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
        {
          location_t cond_loc = c_parser_peek_token (parser)->location;
+         c_in_omp_for = true;
          struct c_expr cond_expr
            = c_parser_binary_expression (parser, NULL, NULL_TREE);
+          c_in_omp_for = false;
 
          cond = cond_expr.value;
          cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
-         if (COMPARISON_CLASS_P (cond))
-           {
-             tree op0 = TREE_OPERAND (cond, 0), op1 = TREE_OPERAND (cond, 1);
-             op0 = c_fully_fold (op0, false, NULL);
-             op1 = c_fully_fold (op1, false, NULL);
-             TREE_OPERAND (cond, 0) = op0;
-             TREE_OPERAND (cond, 1) = op1;
-           }
          switch (cond_expr.original_code)
            {
            case GT_EXPR:
@@ -18337,8 +18339,10 @@ c_parser_omp_for_loop (location_t loc, c
      an error from the initialization parsing.  */
   if (!fail)
     {
+      c_in_omp_for = true;
       stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv,
                               incrv, body, pre_body, true);
+      c_in_omp_for = false;
 
       /* Check for iterators appearing in lb, b or incr expressions.  */
       if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL))
@@ -18348,6 +18352,40 @@ c_parser_omp_for_loop (location_t loc, c
        {
          add_stmt (stmt);
 
+         for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INIT (stmt)); i++)
+           {
+             tree init = TREE_VEC_ELT (OMP_FOR_INIT (stmt), i);
+             gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+             tree decl = TREE_OPERAND (init, 0);
+             tree cond = TREE_VEC_ELT (OMP_FOR_COND (stmt), i);
+             gcc_assert (COMPARISON_CLASS_P (cond));
+             gcc_assert (TREE_OPERAND (cond, 0) == decl);
+
+             tree op0 = TREE_OPERAND (init, 1);
+             if (!OMP_FOR_NON_RECTANGULAR (stmt)
+                 || TREE_CODE (op0) != TREE_VEC)
+               TREE_OPERAND (init, 1) = c_fully_fold (op0, false, NULL);
+             else
+               {
+                 TREE_VEC_ELT (op0, 1)
+                   = c_fully_fold (TREE_VEC_ELT (op0, 1), false, NULL);
+                 TREE_VEC_ELT (op0, 2)
+                   = c_fully_fold (TREE_VEC_ELT (op0, 2), false, NULL);
+               }
+
+             tree op1 = TREE_OPERAND (cond, 1);
+             if (!OMP_FOR_NON_RECTANGULAR (stmt)
+                 || TREE_CODE (op1) != TREE_VEC)
+               TREE_OPERAND (cond, 1) = c_fully_fold (op1, false, NULL);
+             else
+               {
+                 TREE_VEC_ELT (op1, 1)
+                   = c_fully_fold (TREE_VEC_ELT (op1, 1), false, NULL);
+                 TREE_VEC_ELT (op1, 2)
+                   = c_fully_fold (TREE_VEC_ELT (op1, 2), false, NULL);
+               }
+           }
+
          if (cclauses != NULL
              && cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
            {
--- gcc/c/c-tree.h.jj   2020-06-16 12:10:03.613011138 +0200
+++ gcc/c/c-tree.h      2020-06-16 12:35:02.443298066 +0200
@@ -657,6 +657,7 @@ extern alias_set_type c_get_alias_set (t
 extern int in_alignof;
 extern int in_sizeof;
 extern int in_typeof;
+extern bool c_in_omp_for;
 
 extern tree c_last_sizeof_arg;
 extern location_t c_last_sizeof_loc;
--- gcc/c/c-typeck.c.jj 2020-06-16 12:10:03.615011109 +0200
+++ gcc/c/c-typeck.c    2020-06-16 12:35:02.443298066 +0200
@@ -71,6 +71,9 @@ int in_sizeof;
 /* The level of nesting inside "typeof".  */
 int in_typeof;
 
+/* True when parsing OpenMP loop expressions.  */
+bool c_in_omp_for;
+
 /* The argument of last parsed sizeof expression, only to be tested
    if expr.original_code == SIZEOF_EXPR.  */
 tree c_last_sizeof_arg;
@@ -6209,15 +6212,20 @@ build_modify_expr (location_t location,
   if (!(is_atomic_op && modifycode != NOP_EXPR))
     {
       tree rhs_semantic_type = NULL_TREE;
-      if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR)
+      if (!c_in_omp_for)
        {
-         rhs_semantic_type = TREE_TYPE (newrhs);
-         newrhs = TREE_OPERAND (newrhs, 0);
+         if (TREE_CODE (newrhs) == EXCESS_PRECISION_EXPR)
+           {
+             rhs_semantic_type = TREE_TYPE (newrhs);
+             newrhs = TREE_OPERAND (newrhs, 0);
+           }
+         npc = null_pointer_constant_p (newrhs);
+         newrhs = c_fully_fold (newrhs, false, NULL);
+         if (rhs_semantic_type)
+           newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
        }
-      npc = null_pointer_constant_p (newrhs);
-      newrhs = c_fully_fold (newrhs, false, NULL);
-      if (rhs_semantic_type)
-       newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
+      else
+       npc = null_pointer_constant_p (newrhs);
       newrhs = convert_for_assignment (location, rhs_loc, lhstype, newrhs,
                                       rhs_origtype, ic_assign, npc,
                                       NULL_TREE, NULL_TREE, 0);
@@ -7745,12 +7753,15 @@ digest_init (location_t init_loc, tree t
 
   STRIP_TYPE_NOPS (inside_init);
 
-  if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
+  if (!c_in_omp_for)
     {
-      semantic_type = TREE_TYPE (inside_init);
-      inside_init = TREE_OPERAND (inside_init, 0);
+      if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
+       {
+         semantic_type = TREE_TYPE (inside_init);
+         inside_init = TREE_OPERAND (inside_init, 0);
+       }
+      inside_init = c_fully_fold (inside_init, require_constant, &maybe_const);
     }
-  inside_init = c_fully_fold (inside_init, require_constant, &maybe_const);
 
   /* Initialization of an array of chars from a string constant
      optionally enclosed in braces.  */
@@ -12475,7 +12486,7 @@ build_binary_op (location_t location, en
          converted = 1;
          resultcode = xresultcode;
 
-         if (c_inhibit_evaluation_warnings == 0)
+         if (c_inhibit_evaluation_warnings == 0 && !c_in_omp_for)
            {
              bool op0_maybe_const = true;
              bool op1_maybe_const = true;
--- gcc/cp/semantics.c.jj       2020-06-16 12:10:03.620011036 +0200
+++ gcc/cp/semantics.c  2020-06-16 13:02:07.735849231 +0200
@@ -8566,7 +8566,7 @@ handle_omp_for_class_iterator (int i, lo
                TREE_OPERAND (cond, 1), iter);
       return true;
     }
-  if (!c_omp_check_loop_iv_exprs (locus, orig_declv,
+  if (!c_omp_check_loop_iv_exprs (locus, orig_declv, i,
                                  TREE_VEC_ELT (declv, i), NULL_TREE,
                                  cond, cp_walk_subtrees))
     return true;
@@ -8952,8 +8952,8 @@ finish_omp_for (location_t locus, enum t
       tree orig_init;
       FOR_EACH_VEC_ELT (*orig_inits, i, orig_init)
        if (orig_init
-           && !c_omp_check_loop_iv_exprs (locus, orig_declv
-                                                 ? orig_declv : declv,
+           && !c_omp_check_loop_iv_exprs (locus,
+                                          orig_declv ? orig_declv : declv, i,
                                           TREE_VEC_ELT (declv, i), orig_init,
                                           NULL_TREE, cp_walk_subtrees))
          fail = true;
@@ -9047,35 +9047,11 @@ finish_omp_for (location_t locus, enum t
          return NULL;
        }
 
-      if (!processing_template_decl)
-       {
-         init = fold_build_cleanup_point_expr (TREE_TYPE (init), init);
-         init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
-                                      tf_warning_or_error);
-       }
+      if (!processing_template_decl && TREE_CODE (init) != TREE_VEC)
+       init = cp_build_modify_expr (elocus, decl, NOP_EXPR, init,
+                                    tf_warning_or_error);
       else
        init = build2 (MODIFY_EXPR, void_type_node, decl, init);
-      if (cond
-         && TREE_SIDE_EFFECTS (cond)
-         && COMPARISON_CLASS_P (cond)
-         && !processing_template_decl)
-       {
-         tree t = TREE_OPERAND (cond, 0);
-         if (TREE_SIDE_EFFECTS (t)
-             && t != decl
-             && (TREE_CODE (t) != NOP_EXPR
-                 || TREE_OPERAND (t, 0) != decl))
-           TREE_OPERAND (cond, 0)
-             = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
-
-         t = TREE_OPERAND (cond, 1);
-         if (TREE_SIDE_EFFECTS (t)
-             && t != decl
-             && (TREE_CODE (t) != NOP_EXPR
-                 || TREE_OPERAND (t, 0) != decl))
-           TREE_OPERAND (cond, 1)
-             = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
-       }
       if (decl == error_mark_node || init == error_mark_node)
        return NULL;
 
@@ -9104,9 +9080,45 @@ finish_omp_for (location_t locus, enum t
 
   for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)); i++)
     {
-      decl = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (omp_for), i), 0);
+      init = TREE_VEC_ELT (OMP_FOR_INIT (omp_for), i);
+      decl = TREE_OPERAND (init, 0);
+      cond = TREE_VEC_ELT (OMP_FOR_COND (omp_for), i);
       incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i);
 
+      if (!processing_template_decl)
+       {
+         if (TREE_CODE (TREE_OPERAND (init, 1)) == TREE_VEC)
+           {
+             tree t = TREE_VEC_ELT (TREE_OPERAND (init, 1), 1);
+             TREE_VEC_ELT (TREE_OPERAND (init, 1), 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+             t = TREE_VEC_ELT (TREE_OPERAND (init, 1), 2);
+             TREE_VEC_ELT (TREE_OPERAND (init, 1), 2)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+         else
+           {
+             tree t = TREE_OPERAND (init, 1);
+             TREE_OPERAND (init, 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+         if (TREE_CODE (TREE_OPERAND (cond, 1)) == TREE_VEC)
+           {
+             tree t = TREE_VEC_ELT (TREE_OPERAND (cond, 1), 1);
+             TREE_VEC_ELT (TREE_OPERAND (cond, 1), 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+             t = TREE_VEC_ELT (TREE_OPERAND (cond, 1), 2);
+             TREE_VEC_ELT (TREE_OPERAND (cond, 1), 2)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+         else
+           {
+             tree t = TREE_OPERAND (cond, 1);
+             TREE_OPERAND (cond, 1)
+               = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+           }
+       }
+
       if (TREE_CODE (incr) != MODIFY_EXPR)
        continue;
 
--- gcc/cp/pt.c.jj      2020-06-16 12:10:03.619011051 +0200
+++ gcc/cp/pt.c 2020-06-16 13:51:59.210595705 +0200
@@ -17465,7 +17465,16 @@ tsubst_omp_for_iterator (tree t, int i,
       else
        decl = RECUR (decl);
     }
-  init = RECUR (init);
+  if (init && TREE_CODE (init) == TREE_VEC)
+    {
+      init = copy_node (init);
+      TREE_VEC_ELT (init, 0)
+       = tsubst_decl (TREE_VEC_ELT (init, 0), args, complain);
+      TREE_VEC_ELT (init, 1) = RECUR (TREE_VEC_ELT (init, 1));
+      TREE_VEC_ELT (init, 2) = RECUR (TREE_VEC_ELT (init, 2));
+    }
+  else
+    init = RECUR (init);
 
   if (orig_declv && OMP_FOR_ORIG_DECLS (t))
     {
@@ -17517,7 +17526,21 @@ tsubst_omp_for_iterator (tree t, int i,
 
       if (!range_for)
        {
-         cond = RECUR (TREE_VEC_ELT (OMP_FOR_COND (t), i));
+         cond = TREE_VEC_ELT (OMP_FOR_COND (t), i);
+         if (COMPARISON_CLASS_P (cond)
+             && TREE_CODE (TREE_OPERAND (cond, 1)) == TREE_VEC)
+           {
+             tree lhs = RECUR (TREE_OPERAND (cond, 0));
+             tree rhs = copy_node (TREE_OPERAND (cond, 1));
+             TREE_VEC_ELT (rhs, 0)
+               = tsubst_decl (TREE_VEC_ELT (rhs, 0), args, complain);
+             TREE_VEC_ELT (rhs, 1) = RECUR (TREE_VEC_ELT (rhs, 1));
+             TREE_VEC_ELT (rhs, 2) = RECUR (TREE_VEC_ELT (rhs, 2));
+             cond = build2 (TREE_CODE (cond), TREE_TYPE (cond),
+                            lhs, rhs);       
+           }
+         else
+           cond = RECUR (cond);
          incr = TREE_VEC_ELT (OMP_FOR_INCR (t), i);
          if (TREE_CODE (incr) == MODIFY_EXPR)
            {
--- gcc/testsuite/c-c++-common/gomp/loop-6.c.jj 2020-06-16 12:35:02.438298139 
+0200
+++ gcc/testsuite/c-c++-common/gomp/loop-6.c    2020-06-16 12:35:02.438298139 
+0200
@@ -0,0 +1,113 @@
+int bar (int);
+int baz (int *);
+
+void
+f1 (int x)
+{
+  int i = 0, j = 0, k = 0;
+  long long l = 0;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i * i; j < 16; j += 2)    /* { dg-error "initializer expression 
refers to iteration variable" } */
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i + 3; j < (i + 1) * 2; j += 2)   /* { dg-error "condition 
expression refers to iteration variable" } */
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = (i + 1) * 2; j < i * 8; j += 2)   /* { dg-error "initializer 
expression refers to iteration variable" } */
+      ;
+  #pragma omp for collapse(3)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = 0; j < 16; j++)
+      for (k = i + j; k < 32; k++)     /* { dg-error "initializer expression 
refers to iteration variable" } */
+       ;
+  #pragma omp for collapse(2)
+  for (l = 0; l < 16; l++)
+    for (j = 0; j < l; j++)            /* { dg-error "outer iteration variable 
'l' used in condition expression has type other than 'int'" } */
+      ;
+  #pragma omp for collapse(2)          /* { dg-error "outer iteration variable 
'l' used in initializer expression has type other than 'int'" "" { target c } } 
*/
+  for (l = 0; l < 16; l++)             /* { dg-error "outer iteration variable 
'l' used in initializer expression has type other than 'int'" "" { target c++ } 
} */
+    for (j = 7LL * l; j < 32; j++)
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i + 3; j < i * 2 + 2; j += 2)
+      ;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = i * 2 + 2; j < i * 6 + 2; j += 2)
+      ;
+  #pragma omp for collapse(3)
+  for (i = 0; i < 16; i = i + 2)
+    for (j = 0; j < 16; j++)
+      for (k = 14 + 7 * i; k < 32 * j; k++)    /* { dg-error "two different 
outer iteration variables 'i' and 'j' used in a single loop" } */
+       ;
+  #pragma omp for schedule(static, 2) collapse(2)      /* { dg-error 
"'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for schedule(static) collapse(2)         /* { dg-error 
"'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for schedule(dynamic, 5) collapse(2)     /* { dg-error 
"'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for ordered collapse(2)                  /* { dg-error 
"'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for ordered collapse(2)                  /* { dg-error 
"'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp for ordered (3) collapse (2)             /* { dg-error 
"'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 64; i++)
+    for (j = 0; j < i; j++)
+      for (k = 0; k < 64; k++)
+        {
+          #pragma omp ordered depend (sink: i - 1, j - 2, k - 3)
+          #pragma omp ordered depend (source)
+        }
+  #pragma omp for ordered (3) collapse (2)             /* { dg-error 
"'ordered' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 64; i++)
+    for (j = 0; j < 64; j++)
+      for (k = i; k < 64; k++)
+        {
+          #pragma omp ordered depend (sink: i - 1, j - 2, k - 3)
+          #pragma omp ordered depend (source)
+        }
+  #pragma omp for simd schedule(simd: static) collapse(2)      /* { dg-error 
"'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+}
+
+void
+f2 (void)
+{
+  int i = 0, j = 0;
+  #pragma omp distribute dist_schedule(static, 4) collapse(2)  /* { dg-error 
"'dist_schedule' clause may not appear on non-rectangular 'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+  #pragma omp distribute collapse(2) dist_schedule(static)     /* { dg-error 
"'dist_schedule' clause may not appear on non-rectangular 'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+  #pragma omp distribute parallel for simd schedule(simd: static) collapse(2)  
/* { dg-error "'schedule' clause may not appear on non-rectangular 'for'" } */
+  for (i = 0; i < 16; i++)
+    for (j = 1; j < i; j++)
+      ;
+  #pragma omp distribute parallel for simd collapse(2) dist_schedule(static)   
/* { dg-error "'dist_schedule' clause may not appear on non-rectangular 
'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+  #pragma omp distribute simd collapse(2) dist_schedule(static)        /* { 
dg-error "'dist_schedule' clause may not appear on non-rectangular 
'distribute'" } */
+  for (i = 0; i < 64; i++)
+    for (j = i; j < 64; j++)
+      ;
+}
--- gcc/testsuite/gcc.dg/gomp/loop-1.c.jj       2020-06-16 12:10:03.627010935 
+0200
+++ gcc/testsuite/gcc.dg/gomp/loop-1.c  2020-06-16 12:35:02.439298124 +0200
@@ -73,13 +73,13 @@ f1 (int x)
   for (i = j; i < 16; i = i + 2)
     for (j = 0; j < 16; j++)
       ;
-  #pragma omp for collapse(2) /* { dg-error "initializer expression refers to 
iteration variable" } */
+  #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
     for (j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
-    for (j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+    for (j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
@@ -91,11 +91,11 @@ f1 (int x)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to 
iteration variable" } */
@@ -206,13 +206,13 @@ f2 (int x)
   for (int i = 0; i < 16; i = i + 2)
     for (int j = 0; j < 16; j += 2)
       ;
-  #pragma omp for collapse(2) /* { dg-error "initializer expression refers to 
iteration variable" } */
+  #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
     for (int j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
-    for (int j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+    for (int j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
@@ -224,11 +224,11 @@ f2 (int x)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (int j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers 
to iteration variable" } */
+    for (int j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
--- gcc/testsuite/gcc.dg/gomp/loop-2.c.jj       2020-06-16 12:41:01.183073116 
+0200
+++ gcc/testsuite/gcc.dg/gomp/loop-2.c  2020-06-16 12:40:34.503461694 +0200
@@ -0,0 +1,13 @@
+void
+foo (void)
+{
+  int i = 0;
+  #pragma omp for collapse(2)  /* { dg-error "the same loop iteration 
variables 'i' used in multiple associated loops" } */
+  for (i = 0; i < 16; i++)
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)     /* { dg-error "the same loop iteration 
variables 'j' used in multiple associated loops" } */
+  for (int j = 0; j < 16; j++)
+    for (j = 0; j < 16; j++)
+      ;
+}
--- gcc/testsuite/g++.dg/gomp/loop-1.C.jj       2020-06-16 12:10:03.626010950 
+0200
+++ gcc/testsuite/g++.dg/gomp/loop-1.C  2020-06-16 12:35:02.438298139 +0200
@@ -74,12 +74,12 @@ f1 (int x)
     for (j = 0; j < 16; j++)
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression refers 
to iteration variable" } */
+  for (i = 0; i < 16; i = i + 2)
     for (j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
-    for (j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+    for (j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
@@ -91,11 +91,11 @@ f1 (int x)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to 
iteration variable" } */
@@ -207,12 +207,12 @@ f2 (int x)
     for (int j = 0; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+  for (int i = 0; i < 16; i = i + 2)
     for (int j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
-    for (int j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+    for (int j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
@@ -224,11 +224,11 @@ f2 (int x)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (int j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers 
to iteration variable" } */
+    for (int j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
--- gcc/testsuite/g++.dg/gomp/loop-2.C.jj       2020-06-16 12:10:03.627010935 
+0200
+++ gcc/testsuite/g++.dg/gomp/loop-2.C  2020-06-16 12:35:02.439298124 +0200
@@ -75,12 +75,12 @@ f1 (int x)
     for (j = 0; j < 16; j++)
       ;
   #pragma omp for collapse(2)
-  for (i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression refers 
to iteration variable" } */
+  for (i = 0; i < 16; i = i + 2)
     for (j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i = i + 2)
-    for (j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+    for (j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
@@ -92,11 +92,11 @@ f1 (int x)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < 16; i++)
-    for (j = 0; j < i + 4; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (i = 0; i < j + 4; i++) /* { dg-error "condition expression refers to 
iteration variable" } */
@@ -209,12 +209,12 @@ f2 (int x)
     for (int j = 0; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
-  for (int i = 0; i < 16; i = i + 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+  for (int i = 0; i < 16; i = i + 2)
     for (int j = i; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i = i + 2)
-    for (int j = i + 3; j < 16; j += 2) /* { dg-error "initializer expression 
refers to iteration variable" } */
+    for (int j = i + 3; j < 16; j += 2)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
@@ -226,11 +226,11 @@ f2 (int x)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i; j++) /* { dg-error "condition expression refers to 
iteration variable" } */
+    for (int j = 0; j < i; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
-    for (int j = 0; j < i + 4; j++) /* { dg-error "condition expression refers 
to iteration variable" } */
+    for (int j = 0; j < i + 4; j++)
       ;
   #pragma omp for collapse(2)
   for (int i = 0; i < 16; i++)
--- gcc/testsuite/g++.dg/gomp/loop-5.C.jj       2020-06-16 12:43:58.329527966 
+0200
+++ gcc/testsuite/g++.dg/gomp/loop-5.C  2020-06-16 13:14:42.273870347 +0200
@@ -0,0 +1,50 @@
+void
+foo ()
+{
+  int i = 0;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i++)     // { dg-error "the same loop iteration 
variables 'i' used in multiple associated loops" }
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)
+  for (int j = 0; j < 16; j++) // { dg-error "the same loop iteration 
variables 'j' used in multiple associated loops" }
+    for (j = 0; j < 16; j++)
+      ;
+}
+
+template <int N>
+void
+bar ()
+{
+  int i = 0;
+  #pragma omp for collapse(2)
+  for (i = 0; i < 16; i++)     // { dg-error "the same loop iteration 
variables 'i' used in multiple associated loops" }
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)
+  for (int j = 0; j < 16; j++) // { dg-error "the same loop iteration 
variables 'j' used in multiple associated loops" }
+    for (j = 0; j < 16; j++)
+      ;
+}
+
+template <typename T>
+void
+baz ()
+{
+  T i = 0;
+  #pragma omp for collapse(2)  // { dg-error "the same loop iteration 
variables 'i' used in multiple associated loops" }
+  for (i = 0; i < 16; i++)
+    for (i = 1; i < 32; i++)
+      ;
+  #pragma omp taskloop collapse(2)     // { dg-error "the same loop iteration 
variables 'j' used in multiple associated loops" }
+  for (T j = 0; j < 16; j++)
+    for (j = 0; j < 16; j++)
+      ;
+}
+
+void
+test ()
+{
+  bar <0> ();
+  baz <int> ();
+}
--- gcc/testsuite/g++.dg/gomp/loop-6.C.jj       2020-06-16 12:44:45.453851633 
+0200
+++ gcc/testsuite/g++.dg/gomp/loop-6.C  2020-06-16 13:12:27.458831975 +0200
@@ -0,0 +1,69 @@
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> 
&, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - 
(const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type 
, const I<S> &);
+private:
+  T *p;
+};
+
+template <typename T> bool operator == (I<T> &, I<T> &);
+template <typename T> bool operator == (const I<T> &, const I<T> &);
+template <typename T> bool operator != (I<T> &, I<T> &);
+template <typename T> bool operator != (const I<T> &, const I<T> &);
+template <typename T> bool operator < (I<T> &, I<T> &);
+template <typename T> bool operator < (const I<T> &, const I<T> &);
+template <typename T> bool operator <= (I<T> &, I<T> &);
+template <typename T> bool operator <= (const I<T> &, const I<T> &);
+template <typename T> bool operator > (I<T> &, I<T> &);
+template <typename T> bool operator > (const I<T> &, const I<T> &);
+template <typename T> bool operator >= (I<T> &, I<T> &);
+template <typename T> bool operator >= (const I<T> &, const I<T> &);
+template <typename T> typename I<T>::difference_type operator - (I<T> &, I<T> 
&);
+template <typename T> typename I<T>::difference_type operator - (const I<T> &, 
const I<T> &);
+template <typename T> I<T> operator + (typename I<T>::difference_type, const 
I<T> &);
+
+void
+f1 (I<int> &x, I<int> &y)
+{
+  I<int> i;
+  #pragma omp for collapse(2)
+  for (i = x; i < y; i++)      // { dg-error "the same loop iteration 
variables 'i' used in multiple associated loops" }
+    for (i = x; i < y; i++)
+      ;
+  #pragma omp for collapse(2)
+  for (I<int> j = x; j < y; j++)// { dg-error "the same loop iteration 
variables 'j' used in multiple associated loops" }
+    for (j = y; j > x; j--)
+      ;
+}

        Jakub

Reply via email to